#include <Wire.h>
#include <RTClib.h>
#include <SoftwareSerial.h>

#define RX_PIN 10     // RS232 RX pin
#define TX_PIN 11     // RS232 TX pin
#define BUTTON_PIN 2  // Button pin
#define LED_PIN 3     // Button pin
#define PC_PIN 4      // Button pin

// Creating a structure for weekdays, on time, off time and a check if user wants to turn on or off the projector for that specific day
struct Schedule {
  int weekday;           // 1 = Monday, 2 = Tuesday, ..., 7 = Sunday
  bool needsToSchedule;  // Flag to check if projector needs to be scheduled for this day
  int onHour;            // 24-hour format
  int onMinute;          // 24-hour format
  int offHour;           // 24-hour format
  int offMinute;         // 24-hour format
  bool turnOn;           // Flag to check if projector is already ON
};

// Here's how the schedule structure works:
// { weekday, needsToSchedule, onHour, onMinute, offHour, offMinute, turnOn, turnOff }
// For example, the following schedule will turn on the projector at 8:00 and turn it off at 20:00 on Monday
// { 1, true, 8, 0, 20, 0, false, false }
// For example, the following schedule will turn on the projector at 8:00 and turn it off at 20:00 on Tuesday
// { 2, true, 8, 0, 20, 0, false, false }

// Creating an array of schedules for each day of the week
Schedule schedules[] = {
  { 0, false, 8, 0, 20, 0, false},  // Sunday
  { 1, true, 8, 0, 20, 0, false},   // Monday
  { 2, false, 8, 0, 20, 0, false},  // Tuesday
  { 3, false, 8, 0, 20, 0, false},  // Wednesday
  { 4, true, 8, 0, 20, 0, false},   // Thursday
  { 5, true, 0, 34, 0, 35, false},   // Friday
  { 6, false, 8, 0, 20, 0, false},  // Saturday
};


// Creating an object of the RTC_DS3231 class
RTC_DS3231 rtc;
SoftwareSerial rs232Serial(RX_PIN, TX_PIN);

bool projectorOn = false;

int previousSecondCheck = 0;  // Variable to store the previous second check

void setup() {
  Serial.begin(115200);
  rs232Serial.begin(115200);
  pinMode(BUTTON_PIN, INPUT_PULLUP);                                         // Configure button pin with internal pull-up
  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), checkButton, FALLING);  // Trigger on falling edge (button press)

  pinMode(LED_PIN, OUTPUT);  // Configure button pin with internal pull-up
  pinMode(PC_PIN, OUTPUT);   // Configure button pin with internal pull-up

  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1)
      ;
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, setting the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));  // Set RTC to current compile time
  }

  Serial.println("System initialized.");
}

void loop() {
  checkSerialCommands();
  printCurrentTime();  // Print current time and also check for RTC schedule
  checkButton();
  delay(50);  // Small delay to prevent high CPU usage
}

// Simplified button state check
void checkButton() {
  if (digitalRead(BUTTON_PIN) == LOW) {    // Check if button is pressed
    delay(200);                            // Short debounce delay
    if (digitalRead(BUTTON_PIN) == LOW) {  // Check if still pressed
      toggleProjector();                   // Toggle projector state
      Serial.println("Button pressed - toggling projector");
    }
  }
}

// Function to toggle projector ON/OFF state
void toggleProjector() {
  if (projectorOn) {
    sendRS232Command("OFF");
    digitalWrite(LED_PIN, LOW);
    projectorOn = false;
    delay(10000);  // Shutdown delay
    activatePCRelay();
    Serial.println("Projector turned OFF");
  } else {
    sendRS232Command("ON");
    digitalWrite(LED_PIN, HIGH);
    projectorOn = true;
    delay(10000);  // Shutdown delay
    activatePCRelay();
    Serial.println("Projector turned ON");
  }
}

void activatePCRelay() {
  digitalWrite(PC_PIN, HIGH);
  delay(15000);
  digitalWrite(PC_PIN, LOW);
}

// Function to send RS232 ON/OFF commands
void sendRS232Command(String command) {
  if (command == "ON") {
    byte onCommand[] = { 0x06, 0x14, 0x00, 0x04, 0x00, 0x34, 0x11, 0x00, 0x00, 0x5D };
    rs232Serial.write(onCommand, sizeof(onCommand));
  } else if (command == "OFF") {
    byte offCommand[] = { 0x06, 0x14, 0x00, 0x04, 0x00, 0x34, 0x11, 0x01, 0x00, 0x5E };
    rs232Serial.write(offCommand, sizeof(offCommand));
  }
  delay(1000);  // Delay to ensure command is processed
}
void turnOnPcProjector() {
  projectorOn = true;      // Set projector on flag true
  sendRS232Command("ON");  // Send ON command
  digitalWrite(LED_PIN, HIGH);
  digitalWrite(PC_PIN, HIGH);  // Start with PC relay on
  delay(1000);
  digitalWrite(PC_PIN, LOW);  // Turn PC relay off
}
void turnOffPcProjector() {
  projectorOn = false;      // Reset projector on flag
  sendRS232Command("OFF");  // Send OFF command
  digitalWrite(LED_PIN, LOW);
  digitalWrite(PC_PIN, HIGH);  // Start with PC relay on
  delay(1000);
  digitalWrite(PC_PIN, LOW);  // Turn PC relay off
}
// Function to check for RTC schedule
void checkRTCSchedule() {
  DateTime now = rtc.now();

  // Check for schedule for current day
  for (int i = 0; i < 7; i++) {                                                                                  // Loop through all schedules
    if (now.dayOfTheWeek() == schedules[i].weekday && schedules[i].needsToSchedule == true) {                    // Check if current day matches schedule and schedule is enabled
      if (now.hour() == schedules[i].onHour && now.minute() == schedules[i].onMinute && !schedules[i].turnOn) {  // Check if ON time matches and projector is not already ON
        if (projectorOn == false)                                                                                // Check  if previously projector is off then turn it on
          turnOnPcProjector();
        schedules[i].turnOn = true;  // Set turn ON flag to true
        Serial.println("Projector turned ON by schedule");
      } else if (now.hour() == schedules[i].offHour && now.minute() == schedules[i].offMinute && schedules[i].turnOn) {  // Check if OFF time matches and projector is not already OFF
        if (projectorOn == true)                                                                                         // Check if previously projector is on only then call turn off fucntion
          turnOffPcProjector();
        schedules[i].turnOn = false;
        Serial.println("Projector turned OFF by schedule");

        schedules[i].turnOn = false;
      }
    }
  }
}
// Function to check for serial commands (manual ON/OFF)
void checkSerialCommands() {
  if (Serial.available() > 0) {
    String controlCommand = Serial.readString();
    controlCommand.trim();

    if (controlCommand.equalsIgnoreCase("ON") && !projectorOn) {
      turnOnPcProjector();  // Send ON command
      Serial.println("Projector turned ON by serial command");
    } else if (controlCommand.equalsIgnoreCase("OFF") && projectorOn) {
      turnOffPcProjector();  // Send OFF command
      Serial.println("Projector turned OFF by serial command");
    }
  }
}

// Function to print the current time from the RTC
void printCurrentTime() {
  DateTime now = rtc.now();
  if (now.second() != previousSecondCheck) {  // Print time only once per minute
    Serial.print("Current Date and Time: ");
    char buf[] = "YY/MM/DD hh:mm:ss";    // Create a buffer for the date and time structure that needs to be printed
    Serial.print(now.toString(buf));   // Print current date and time
    Serial.print(", Day of week:");
    Serial.println(now.dayOfTheWeek());
    previousSecondCheck = now.second();  // Update the previous second check
    checkRTCSchedule();                  // Check for RTC schedule
  }
}
GND5VSDASCLSQWRTCDS1307+