#include <Wire.h>
#include <EEPROM.h>
#include <TimerOne.h>
#include<Adafruit_GFX.h>
#include<Adafruit_SSD1306.h>
#define OLED_RESET -1

Adafruit_SSD1306 OLED(OLED_RESET);

//Other
int rot;
int temphr;
int SetTime_st = 0;
char city[3] = "UTC";

char ar[65];
char ch_input;
int zone_input = 0;

#define xInput A0
#define yInput A1
#define zInput A2

//Debouncing
unsigned long debounceTime, debounceDelay = 250;
unsigned long Timee, Delayy = 250; int ch=0;

//button
#define red_button 4
#define blue_button 5
#define green_button 6
bool input_red, input_blue, input_green;

// initialize minimum and maximum Raw Ranges for each axis
int RawMin = 0;
int RawMax = 1023;

//Time
unsigned long sec = 0;
unsigned long mnt = EEPROM.read(4);
unsigned long hr = EEPROM.read(0);

// Take multiple samples to reduce noise
const int sampleSize = 10;

//TimeZone
int zone = 15;
struct TimeZone {
  int timeDiffer;
  char cityName[4];
};

TimeZone World[42] = {
  {-11,"PPG"},{-10,"HNL"},{-9,"ANC"},{-8,"YVR"},{-8,"LAX"},{-7,"YEA"},{-7,"DEN"},
  {-6,"MEX"},{-6,"CHI"},{-5,"NYC"},{-4,"SCL"},{-4,"YHZ"},{-3,"RIO"},{-2,"FEN"},
  {-1,"RAI"},{0,"UTC"},{0,"LIS"},{0,"LON"},{1,"MAD"},{1,"PAR"},{1,"ROM"},
  {1,"BER"},{1,"STO"},{2,"ATH"},{2,"CAI"},{2,"JRS"},{3,"MOW"},{3,"JED"},
  {4,"DXB"},{5,"KHI"},{6,"DEL"},{6,"DAC"},{7,"BKK"},{8,"SIN"},{8,"HKG"},
  {8,"TPE"},{9,"SEL"},{9,"TYO"},{10,"GUM"},{10,"SYD"},{11,"NOU"},{12,"WLG"}
};

void SetTimeZone(int endd){
  temphr = World[endd % 42].timeDiffer - World[zone].timeDiffer;
  if(temphr<0) hr += 24 + temphr;
  else hr += temphr;

  hr%=24;

  EEPROM.update(0,hr);
  for(int i=0;i<3;i++) city[i] = World[zone].cityName[i];
  zone = endd;
  EEPROM.update(8,zone);
}

void zone_input_check(){
  while(Serial.available() > 0){

    ch_input = Serial.read();
    if(ch_input !='\n' && zone_input < 3){
      ar[zone_input] = ch_input;
      zone_input++;
    }
    
  }

  if(zone_input > 0 && zone_input < 3 )){
    Serial.println("City Not Found");
    zone_input = 0;
  }

  if(zone_input == 3){
    for(int i=0;i<42;i++){
      if(!strcmp(ar,World[i].cityName))
      {
        Serial.print("Go to ");
        Serial.println(ar);
        zone_input = 0;
        SetTimeZone(i);
        return ;
      }
    }
    Serial.println("City Not Found");
    zone_input = 0;
  }
}

void countTime(){
  sec++;
  if(sec>=60) sec=0, mnt++,EEPROM.update(4,mnt);
  if(mnt>=60) mnt=0, hr++,EEPROM.update(0,hr);
  if(hr>23) hr=0;
}

void setup() 
{
  Serial.begin(9600);
  //Serial.println("Serial_Start");
  OLED.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  int a = 12;
  int b = 4;

  Timer1.initialize(1000000);
  Timer1.attachInterrupt(countTime);

  pinMode(red_button,INPUT_PULLUP);
  pinMode(blue_button,INPUT_PULLUP);
  pinMode(green_button,INPUT_PULLUP);

  debounceTime = millis();
}

void loop() 
{
  zone_input_check();

  input_red = digitalRead(red_button);
  input_blue = digitalRead(blue_button);
  input_green = digitalRead(green_button);

  if(millis()-debounceTime >= debounceDelay){
    
    if(!input_red){
      SetTimeZone(zone+1);
      debounceTime = millis();
    }

    if(!input_blue){
      SetTime_st++;
      if(SetTime_st > 2){ 
        SetTime_st = 0;
        EEPROM.update(4,mnt);
        EEPROM.update(0,hr);
      }
      Timee = millis();
      debounceTime = millis();
    }

    if(!input_green){
      if(SetTime_st==1) hr++;
      if(SetTime_st==2) mnt++;
      debounceTime = millis();
    }
  }
  rot = readRotation();
  OLED.clearDisplay();
  OLEDPrintTime(rot);
  OLED.display();
}

int ReadAxis(int axisPin)
{
  long reading = 0;
  //analogRead(axisPin);
  delay(1);
  for (int i = 0; i < sampleSize; i++)
  {
  reading += analogRead(axisPin);
  }
  return reading/sampleSize;
}

int readRotation()
{
  int rot;
  //Read raw values
  int xRaw = ReadAxis(xInput);
  int yRaw = ReadAxis(yInput);

  // Convert raw values to 'milli-Gs"
  long xScaled = map(xRaw, RawMin, RawMax, -3000, 3000);
  long yScaled = map(yRaw, RawMin, RawMax, -3000, 3000);


  // re-scale to fractional Gs
  float xAccel = xScaled / 1000.0;
  float yAccel = yScaled / 1000.0;
  
  if(xAccel > 0.5) rot = 0;
  if(xAccel < -0.5) rot = 2;
  if(yAccel > 0.5) rot = 3;
  if(yAccel < -0.5) rot = 1;

  return rot;
}

void OLEDPrintTime(int rot)
{
  OLED.setTextColor(WHITE); 
  OLED.setRotation(0);
  
  OLED.setTextSize(1); 
  if(rot == 0 || rot == 2){
    OLED.drawRect(25,5,78,22,WHITE);
    int set_x = 12;
      
    OLED.setCursor(17 + set_x,12);

    if(SetTime_st == 1){
      if(millis()-Timee >= Delayy && ch == 0){
        Timee = millis(); ch++;
      }
      if(millis()-Timee >= Delayy && ch==1){
        if(hr < 10) OLED.print("0"); OLED.print(hr);
        Timee = millis(); ch=0;
      }
    }
    else{
      if(hr < 10) OLED.print("0");
      OLED.print(hr);
    }

    OLED.setCursor(28 + set_x,12);
    OLED.print(":");

    OLED.setCursor(34 + set_x,12);

    if(SetTime_st == 2){
      if(millis()-Timee >= Delayy && ch == 0){
        Timee = millis(); ch++;
      }
      if(millis()-Timee >= Delayy && ch==1){
        if(mnt < 10) OLED.print("0"); OLED.print(mnt);
        Timee = millis(); ch=0;
      }
    }
    else{
      if(mnt < 10) OLED.print("0");
      OLED.print(mnt);
    }

    OLED.setCursor(45 + set_x,12);
    OLED.print(":");

    OLED.setCursor(51 + set_x,12);
    if(sec<10) OLED.print("0"); OLED.println(sec);

    OLED.setCursor(70 + set_x,12);
    OLED.println(World[zone].cityName);

  }
  
  else{
    OLED.drawRect(2,20,23,88,WHITE);
    int set_y = 28;
    OLED.setCursor(5,0 + set_y);
    OLED.println(World[zone].cityName);

    OLED.setCursor(8,16 + set_y);
    if(SetTime_st == 1){
      if(millis()-Timee >= Delayy && ch == 0){
        Timee = millis(); ch++;
      }
      if(millis()-Timee >= Delayy && ch==1){
        if(hr < 10) OLED.print("0"); OLED.print(hr);
        Timee = millis(); ch=0;
      }
    }
    else{
      if(hr < 10) OLED.print("0");
      OLED.print(hr);
    }

    OLED.setCursor(8,24 + set_y);
    OLED.print("..");

    OLED.setCursor(8,40 + set_y);
    if(SetTime_st == 2){
      if(millis()-Timee >= Delayy && ch == 0){
        Timee = millis(); ch++;
      }
      if(millis()-Timee >= Delayy && ch==1){
        if(mnt < 10) OLED.print("0"); OLED.print(mnt);
        Timee = millis(); ch=0;
      }
    }
    else{
      if(mnt < 10) OLED.print("0");
      OLED.print(mnt);
    }

    OLED.setCursor(8,48 + set_y);
    OLED.print("..");

    OLED.setCursor(8,64 + set_y);
    if(sec<10) OLED.print("0"); OLED.println(sec);
  } 
}