#include "U8glib.h"
#include <SPI.h>
#include <RTClib.h>


U8GLIB_SSD1306_128X64 u8g; // create an instant of OLED display

RTC_DS1307 rtc;
//states for length of button presses
#define button 19
#define HALT while(true);
#define STATE_NORMAL 0
#define STATE_SHORT 1
#define STATE_LONG 2
#define STATE_ELONG 3

float pi = 3.14;

int Xmid = 31;
int Ymid = 31;

int sHour = 0;
int sMin = 0;
int sSec = 0;

int Minute = 0;


unsigned long button_time = 0;
unsigned long last_button_time = 0;

volatile int  resultButton = 0;

bool changeToSW = false;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200); //serial begin
  pinMode(button, INPUT_PULLUP);
  u8g.begin();
  if (!rtc.begin()) { //if rtc module is not found, display error msg
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }
  rtc.adjust(DateTime(2022, 8, 25, 11, 30, 0)); //set randon date/time
  u8g.setFont(u8g_font_7x13); // set the font for text
  attachInterrupt(digitalPinToInterrupt(button), clock_change, CHANGE);
  //attachInterrupt(digitalPinToInterrupt(19), clock_change2, FALLING);
  Serial.println("Enter time in format hhmm"); //prompt user

}

void clock_change () {
  //int state = digitalRead(19);
  //set to true, create function in which the stopwatch will run
  //if (changeToSW is true, call the stopwatch funtion in main so we can allow looping)
  //when in loop, if button pressed for less then 3 secs, start/ stop watch (check for high and low pin).

  //button_time = millis(); //start counting
  //mechanism to stop millis from accumulating
  //attachInterrupt(digitalPinToInterrupt(19), clock_change2, FALLING);
  const unsigned long LONG_DELTA = 2000ul;               // hold seconds for a long press
  const unsigned long ELONG_DELTA = 4000ul;
  const unsigned long DEBOUNCE_DELTA = 30ul;        // debounce time
  static int lastButtonStatus = HIGH;                                   // HIGH indicates the button is NOT pressed
  int buttonStatus;                                                                    // button atate Pressed/LOW; Open/HIGH
  static unsigned long longTime = 0ul, shortTime = 0ul, ElongTime = 0ul; // future times to determine is button has been poressed a short or long time
  boolean Released = true, Transition = false;                  // various button states
  boolean timeoutShort = false, timeoutLong = false, timeoutLongE = false;    // flags for the state of the presses

  buttonStatus = digitalRead(button);                // read the button state on the pin "BUTTON_PIN"
  timeoutShort = (millis() > shortTime);                          // calculate the current time states for the button presses
  timeoutLong = (millis() > longTime);
  timeoutLongE = (millis() > ElongTime);

  if (buttonStatus != lastButtonStatus) {                          // reset the timeouts if the button state changed
    shortTime = millis() + DEBOUNCE_DELTA;
    longTime = millis() + LONG_DELTA;
    ElongTime = millis() + ELONG_DELTA;
  }

  Transition = (buttonStatus != lastButtonStatus);        // has the button changed state
  Released = (Transition && (buttonStatus == HIGH));

  lastButtonStatus = buttonStatus;

  if ( ! Transition) {                                                                //without a transition, there's no change in input
    // if there has not been a transition, don't change the previous result
    resultButton =  STATE_NORMAL | resultButton;
    return;
  }

  if (timeoutLongE && Released) {
    resultButton = STATE_ELONG | resultButton;
  }
  else if (timeoutLong && Released) {                                      // long timeout has occurred and the button was just released
    resultButton = STATE_LONG | resultButton;       // ensure the button result reflects a long press
    //Serial.println("pressed for long!");
  }

  else if (timeoutShort && Released) {                          // short timeout has occurred (and not long timeout) and button was just released
    resultButton = STATE_SHORT | resultButton;     // ensure the button result reflects a short press
  }
  else {                                                                                  // else there is no change in status, return the normal state
    resultButton = STATE_NORMAL | resultButton; // with no change in status, ensure no change in button status
  }
}
/*
  void clock_change2 () {

  last_button_time = millis(); //time when button is released
  Serial.println(last_button_time - button_time);

  if ((last_button_time - button_time) >= 3000) { //check time
    changeToSW = true; //set flag to initiate stopwatch
    button_time = last_button_time;
    Serial.println("long press");
    Serial.println(button_time);

  }

  else {
    //changeToSW = false;
    Serial.println("Short Press");
    Serial.println(button_time);
  }
  //mechanism to stop millis from accumulating
  attachInterrupt(digitalPinToInterrupt(19), clock_change, RISING);

  }
*/

int pressed = 0;
int state = 0;
int startSW = 0;
unsigned long timer = 0;
int ms = 0;
int mint = 0;
int seconds = 0;
int sc = 0;
int miR = 0;

void playSW() {
  //u8g.drawStr(20, 60, "hello");
  u8g.setColorIndex(0);
  u8g.drawBox(1, 1, 64, 128);
  u8g.setColorIndex(1);
  if (digitalRead(button) == 0) { //if button is pressed
    if (pressed == 0) //button state control
    {
      state++;  //go the next stage
      pressed = 1;  //set pressed to 1
      if (state > 3) state = 0; //go to state 0 after last state
    }
  }
  else
  {
    pressed = 0;
  }

  if (state == 0) {
    u8g.drawStr(15, 35, "PRESS TO START!"); //prompt user in first state
    timer = 0; //need to set timer to 0 when start again

    sc = 0;
    mint = 0;
    timer = 0;
    miR = 0;
    ms = 0;
    startSW = 0;
  }

  if (state == 1) { //state to run stopwatch
    u8g.drawStr(30, 10, "STOPWATCH");
    if (startSW == 0) {
      startSW = 1;
      timer = millis();
    }
    ms = (millis() - timer); //millisecond time

    mint = ms / 60000; //convert to minutes
    seconds = ms / 1000; //convert to seconds

    if (seconds > 59) { //if one minute has passed
      sc = (seconds / 1000) - (mint * 60); //
    }
    else {
      sc = seconds;
    }
    miR = (ms % 1000) / 10;

    //convert to char array and display on oled
    String display = String(mint) + ":" + String(sc) + ":" + String(miR);
    int strLen = display.length() + 1;
    char disC[strLen];
    display.toCharArray(disC, strLen);
    u8g.drawStr(40, 45, disC);


  }

  if (state == 2) { //state to display global varibles (time stopwatch was stopped)
    //u8g.setCursorPos(52,0);
    u8g.setColorIndex(0);
    u8g.drawBox(1, 1, 64, 128);
    u8g.setColorIndex(1);
    u8g.drawStr(35, 10, "ELAPSED:");
    //u8g.setCursorPos(42,30);
    String display = String(mint) + ":" + String(sc) + ":" + String(miR);
    int strLen = display.length() + 1;
    char disC[strLen];
    display.toCharArray(disC, strLen);
    u8g.drawStr(40, 45, disC);


  }

  if (state == 3) { //show clock interface when button pressed 3 third time 

    showClock();
  }


}

void hourHand (int hour, int minute) {
  //trignometry to draw to hour hand
  //formula for y pos: y = (R*cos(pi-(2*pi)/12*hour-(2*PI)/720*minute))
  //formula for x pos: x = (R*sin(pi-(2*pi)/12*hour-(2*PI)/720*minute))
  float x, y;
  y = (20 * cos(pi - (2 * pi) / 12 * hour - (2 * PI) / 720 * minute)) + Ymid;
  x = (20 * sin(pi - (2 * pi) / 12 * hour - (2 * PI) / 720 * minute)) + Xmid;

  u8g.drawLine(Xmid, Ymid, x, y);


}

void minHand(int minute)
{
  //trignometry to draw to minute hand
  //formula for y pos: y = (R*cos(pi-(2*pi)/60*minute))
  //formula for x pos: x = (R*sin(pi-(2*pi)/60*minute))
  float x, y;
  y = (22 * cos(pi - (2 * pi) / 60 * minute)) + Ymid;
  x = (22 * sin(pi - (2 * pi) / 60 * minute)) + Xmid;
  u8g.drawLine(Xmid, Ymid, x, y);
}

void secHand(int second) {
  //trignometry to draw to second hand
  //formula for y pos: (R*cos(pi-(2*pi)/60*second))
  //formula for x pos: (R*sin(pi-(2*pi)/60*second))
  float x, y;
  y = (24 * cos(pi - (2 * pi) / 60 * second)) + Ymid;
  x = (24 * sin(pi - (2 * pi) / 60 * second)) + Xmid;
  u8g.drawLine(Xmid, Ymid, x, y);


}

int swap = 0;

void loop() {
  // put your main code here, to run repeatedly:
  // DateTime now = rtc.now(); //store date data into now variable

  //sHour = now.hour();//store hour data
  //sMin = now.minute();//store minute data

  switch (resultButton) { //swtich statement for varible

    case STATE_NORMAL: { //default state
        /*  Serial.print(".");
          count++;
          count = count % 10;
          if (count==0) Serial.println(""); */
        break;
      }

    case STATE_SHORT: { //short press state
        Serial.println("Short press has been detected");
        //digitalWrite(LED,HIGH);
        //delay(1000);
        //digitalWrite(LED, LOW);
        resultButton = STATE_NORMAL; //take no action, go to default state 
        break;
      }

    case STATE_LONG: { //long press state
        Serial.println("Button was pressed for long time");
        //digitalWrite(LED,HIGH);
        //delay(3000);
        //digitalWrite(LED, LOW);
        //longButton++;
        changeToSW = true;
        resultButton = STATE_NORMAL;
        break;
      }

    case STATE_ELONG: { //extra long state 
        Serial.println("Oops! See Distinction task for this functionality!");
        resultButton = STATE_NORMAL;
        break;
      }
  }

  if (changeToSW == true) {
    u8g.firstPage();
    do {
      playSW();
    } while ( u8g.nextPage() && rtc.isrunning());

  }

  else {
    u8g.firstPage(); //marks the beginning of the picture loop.
    do {

      showClock();

    } while ( u8g.nextPage() && rtc.isrunning()); //marks the end of the body of the picture loop

    u8g.setColorIndex(1);
    u8g.drawStr(0, 20, "outside");

  }

}

void showClock() {
  u8g.setColorIndex(1); // set the colour to white

  for (int i = 0; i < 3; i++) {
    u8g.drawCircle(Xmid, Ymid, 31 - i); //draw outer clock circle, three lines
  }

  for (int i = 0; i < 4; i++) {
    u8g.drawCircle(Xmid, Ymid, i); //draw middle circle
  }

  int a = 0;

  if (Serial.available() > 0 ) {

    Minute = Serial.parseInt(); //read time input from serial
    Serial.read(); //get rid of carriage value

    a = 1; //set to indicate serial has been used
  }

  int firstPart = Minute / 100; //get hour part of input
  int secPart = Minute - firstPart * 100; //get minute part of input
  if (a == 1) //if serial is used
  {
    rtc.adjust(DateTime(2022, 8, 25, firstPart, secPart, 0)); //adjust time to input
  }
  DateTime now = rtc.now(); //continue from time


  sHour = now.hour();//store hour data
  sMin = now.minute();//store minute data
  sSec = now.second(); //store second data



  //coverting data into string then char array
  String digitalC = String(sHour) + ":" + String(sMin);
  int strLen = digitalC.length() + 1;
  char digC[strLen];
  digitalC.toCharArray(digC, strLen);




  //pass data to hand functions
  minHand(sMin);
  hourHand(sHour, sMin);
  secHand(sSec);
  //draw digital clock
  u8g.drawStr(80, 35, digC);
}
GND5VSDASCLSQWRTCDS1307+