/* 
RUNNING TEXT TRANSJAKARTA RUTE 1 -> `Blok M - Kota`

ARSITEKTUR & ORGANISASI KOMPUTER - KELOMPOK 6 - KELAS B
1. Dinda Cantika Putri - 2210511054
2. Nisaul Husna - 2210511055
3. Adinda Rizki Sya'bana Diva - 2210511056
4. Choirunnisa Zalfaa Nabilah - 2210511070
*/

#include <MD_Parola.h> // pustaka untuk mengoperasikan modul LED
#include <MD_MAX72xx.h> // pustaka untuk mengoperasikan modul MAX7219
#include <SPI.h> // pustaka SPI (Serial Peripheral Interface) untuk komunikasi dengan MAX7219

#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW // mendefinisikan tipe hardware untuk modul LED
#define MAX_DEVICES 5 // mendefinisikan jumlah modul LED yang digunakan (5 modul)
#define MAX_ZONES 2 // mendefinisikan jumlah zona untuk penampilan teks

#define CLK_PIN 13 // menetapkan pin nomor 13 sebagai pin CLOCK (mengatur kecepatan transfer data antar perangkat)
#define DATA_PIN 11 // menetapkan pin nomor 11 sebagai pin DATA (informasi dikirim/diterima antar perangkat)
#define CS_PIN 10 // menetapkan pin nomor 10 sebagai pin CHIP SELECT (berkomunikasi dengan mikrokontroler)

// Inisialisasi objek `P` dari kelas MD_PAROLA untuk kendali modul LED
MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

// Array untuk nama-nama halte transjakarta rute 1: Blok M - Kota
const char* halte[] = {
  "Blok M", "ASEAN", "Kejaksaan Agung", "Masjid Agung", 
  "Bundaran Senayan", "Gelora Bung Karno", "Polda Metro Jaya", 
  "Bendungan Hilir", "Karet", "Dukuh Atas", "Tosari", 
  "Bundaran HI Astra", "M.H Thamrin", "Kebon Sirih", "Monumen Nasional", 
  "Harmoni", "Sawah Besar", "Mangga Besar", "Taman Sari", "Glodok", 
  "Kota", "Museum Sejarah Jakarta", "Kali Besar"
};

// menghitung jumlah elemen dalam array `halte`
const int halteCount = sizeof(halte) / sizeof(halte[0]);

// Inisialisasi variabel untuk pesan/teks pada kedua zona
String rute1 = "1 |"; // nama rute
String halteRute = "Blok M - Kota"; // rute awal - akhir

String pesan_sampai; // inisialisasi variabel pesan yang dicetak pada terminal

unsigned long lastUpdate = 0; // variabel untuk menyimpan waktu terakhir update
const int updateInterval = 20000; // Interval waktu display `Blok M - Kota`
const int displayInterval = 15000; // Interval waktu display halte

int currentHalteIndex = 0; // Variabel untuk menyimpan indeks saat ini dari array halte yang sedang ditampilkan
bool showingDefaultMessage = true; // Variabel boolean untuk menentukan apakah pesan default sedang ditampilkan atau tidak

void setup() {
  Serial.begin(115200); // Inisialisasi komunikasi serial dengan kecepatan 115200 bits per detik
  P.begin(2); // Mengspesifikasikan dua zona yang akan dipakai
  P.displayClear(); // Menghapus konten yang sedang ditampilkan di modul LED

  // Membagi display menjadi dua zona
  P.setZone(1, 4, 4); // Zone 1: Modul LED 4 (paling kiri)
  P.setZone(0, 0, 3); // Zone 0: Modul LED range 3 - 0

  // Menampilkan pesan/teks dengan text effect tertentu
  P.displayZoneText(1, rute1.c_str(), PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
  P.displayZoneText(0, halteRute.c_str(), PA_RIGHT, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}

void loop() {
  // Menerapkan animasi pada teks
  if (P.displayAnimate()) { // jika ada animasi yang berjalan
    // Memeriksa apakah kedua zona telah menyelesaikan animasi masing-masings
    bool bAllDone = true; // Variabel boolean untuk mengecek apakah semua zona telah menyelesaikan animasinya
    for (uint8_t i = 0; i < MAX_ZONES; i++) { // Iterasi sebanyak `MAX_ZONES` untuk memeriksa status zona
      bAllDone = bAllDone && P.getZoneStatus(i); // Memeriksa status zona ke-i dan menggabungkan hasilnya dengan nilai bAllDone
    }

    // Jika animasi kedua zona sudah selesai ditampilkan, reset display
    if (bAllDone) {
      P.displayReset(); // reset display
      delay(750); // delay sebanyak 750 milidetik sebelum memulai animasi lagi
    }
  }

  // Mendapatkan nilai waktu saat ini dalam milidetik sejak program dimulai
  unsigned long currentMillis = millis();

  // Memeriksa apakah sudah waktunya untuk memperbarui pesan `Blok M - Kota` berdasarkan updateInterval dan TRUE
  if (showingDefaultMessage && (currentMillis - lastUpdate >= updateInterval)) {
    // Menampilkan halte berikutnya
    currentHalteIndex = (currentHalteIndex + 1) % halteCount; // Menentukan halte indeks berikutnya
    halteRute = halte[currentHalteIndex]; // Meng-update nilai `halteRute` dengan nama halte berikutnya dari array `halte`
    pesan_sampai = String("Sampai di halte ") + halte[currentHalteIndex]; // menggabungkan string untuk menampilkan sudah sampai halte mana
    Serial.println(pesan_sampai); // mencetak pesan
    P.displayClear(0); // Menghapus pesan pada zona 0 LED
    P.displayZoneText(0, halteRute.c_str(), PA_RIGHT, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT); // menampilkan halte yang sudah dituju
    lastUpdate = currentMillis; // Meng-update nilai waktu saat ini
    showingDefaultMessage = false; // Mengubah nilai menjadi false karena yang ditampilkan bukan `Blok M - Kota`
  }

  // Memeriksa apakah sudah waktunya untuk memperbarui pesan `Blok M - Kota` berdasarkan updateInterval dan FALSE
  if (!showingDefaultMessage && (currentMillis - lastUpdate >= displayInterval)) {
    halteRute = "Blok M - Kota"; // Menampilkan rute 1 atau pesan default
    P.displayClear(0); // Menghapus pesan pada zona 0 LED
    P.displayZoneText(0, halteRute.c_str(), PA_RIGHT, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT); // menampilkan pesan default
    lastUpdate = currentMillis; // Memperbarui waktu terakhir pesan ditampilkan.
    showingDefaultMessage = true; // Menandai bahwa pesan default sedang ditampilkan.
  }
}