#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
RTC_DS1307 RTC;

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

//Indlæs soltider i programhukommelse
const unsigned int soltid[366][2] PROGMEM = {
  {1600, 849}, //1, 01-01-2017
  {1602, 849},
  {1603, 848},
  {1604, 848},
  {1606, 848},
  {1607, 847},
  {1608, 847},
  {1610, 846},
  {1612, 845},
  {1613, 844},
  {1615, 844},
  {1617, 843},
  {1618, 842},
  {1620, 841},
  {1622, 840},
  {1624, 838},
  {1626, 837},
  {1627, 836},
  {1629, 835},
  {1631, 833},
  {1633, 832},
  {1635, 831},
  {1637, 829},
  {1639, 828},
  {1641, 826},
  {1643, 824},
  {1645, 823},
  {1648, 821},
  {1650, 819},
  {1652, 818},
  {1654, 816},
  {1656, 814}, //32, 01-02-2017
  {1658, 812},
  {1700, 810},
  {1702, 808},
  {1704, 806},
  {1707, 804},
  {1709, 802},
  {1711, 800},
  {1713, 758},
  {1715, 756},
  {1717, 754},
  {1720, 752},
  {1722, 750},
  {1724, 747},
  {1726, 745},
  {1728, 743},
  {1730, 741},
  {1732, 738},
  {1735, 736},
  {1737, 734},
  {1739, 731},
  {1741, 729},
  {1743, 727},
  {1745, 724},
  {1747, 722},
  {1749, 719},
  {1752, 717},
  {1754, 715},
  {1756, 712}, //60, 01-03-2017
  {1758, 710},
  {1800, 707},
  {1802, 705},
  {1804, 702},
  {1806, 700},
  {1808, 657},
  {1810, 655},
  {1812, 652},
  {1814, 650},
  {1816, 647},
  {1818, 644},
  {1820, 642},
  {1822, 639},
  {1824, 637},
  {1826, 634},
  {1828, 632},
  {1831, 629},
  {1833, 626},
  {1835, 624},
  {1837, 621},
  {1839, 619},
  {1841, 616},
  {1843, 613},
  {1945, 711},
  {1947, 708},
  {1949, 706},
  {1951, 703},
  {1953, 700},
  {1955, 658},
  {1957, 655},
  {1959, 653}, //91, 01-04-2017
  {2001, 650},
  {2002, 648},
  {2004, 645},
  {2006, 642},
  {2008, 640},
  {2010, 637},
  {2012, 635},
  {2014, 632},
  {2016, 630},
  {2018, 627},
  {2020, 625},
  {2022, 622},
  {2024, 620},
  {2026, 617},
  {2028, 615},
  {2030, 612},
  {2032, 610},
  {2034, 607},
  {2036, 605},
  {2038, 602},
  {2040, 600},
  {2042, 558},
  {2044, 555},
  {2046, 553},
  {2048, 551},
  {2050, 548},
  {2052, 546},
  {2054, 544},
  {2056, 542},
  {2058, 539}, //121, 01-05-2017
  {2100, 537},
  {2102, 535},
  {2104, 533},
  {2106, 531},
  {2108, 529},
  {2110, 527},
  {2112, 525},
  {2114, 523},
  {2116, 521},
  {2118, 519},
  {2119, 517},
  {2121, 515},
  {2123, 513},
  {2125, 511},
  {2127, 509},
  {2129, 508},
  {2130, 506},
  {2132, 504},
  {2134, 503},
  {2136, 501},
  {2137, 459},
  {2139, 458},
  {2140, 456},
  {2142, 455},
  {2144, 454},
  {2145, 452},
  {2147, 451},
  {2148, 450},
  {2149, 449},
  {2151, 448},
  {2152, 447}, //152, 01-06-2017
  {2153, 446},
  {2155, 445},
  {2156, 444},
  {2157, 443},
  {2158, 442},
  {2159, 441},
  {2200, 441},
  {2201, 440},
  {2202, 440},
  {2203, 439},
  {2204, 439},
  {2204, 438},
  {2205, 438},
  {2206, 438},
  {2206, 438},
  {2207, 438},
  {2207, 438},
  {2207, 438},
  {2208, 438},
  {2208, 438},
  {2208, 438},
  {2208, 439},
  {2208, 439},
  {2208, 439},
  {2208, 440},
  {2208, 440},
  {2207, 441},
  {2207, 442},
  {2207, 442},
  {2206, 443}, //182, 01-07-2017
  {2206, 444},
  {2205, 445},
  {2205, 446},
  {2204, 447},
  {2203, 448},
  {2202, 449},
  {2202, 450},
  {2201, 451},
  {2200, 453}, //191
  {2159, 454},
  {2158, 455},
  {2156, 457},
  {2155, 458},
  {2154, 459},
  {2153, 501},
  {2151, 502},
  {2150, 504},
  {2148, 505},
  {2147, 507},
  {2145, 509},
  {2144, 510},
  {2142, 512},
  {2141, 513},
  {2139, 515},
  {2137, 517},
  {2135, 519},
  {2134, 520},
  {2132, 522},
  {2130, 524},
  {2128, 526},
  {2126, 528}, //213, 01-08-2017
  {2124, 529},
  {2122, 531},
  {2120, 533},
  {2118, 535},
  {2116, 537},
  {2114, 539},
  {2111, 541},
  {2109, 543},
  {2107, 544},
  {2105, 546},
  {2103, 548},
  {2100, 550},
  {2058, 552},
  {2056, 554},
  {2054, 556},
  {2051, 558},
  {2049, 600},
  {2046, 602},
  {2044, 603},
  {2042, 605},
  {2039, 607},
  {2037, 609},
  {2034, 611},
  {2032, 613},
  {2029, 615},
  {2027, 617},
  {2024, 619},
  {2022, 621},
  {2019, 623},
  {2017, 625},
  {2014, 626}, //244, 01-09-2017
  {2012, 628},
  {2009, 630},
  {2007, 632},
  {2004, 634},
  {2001, 636},
  {1959, 638},
  {1956, 640},
  {1954, 642},
  {1951, 644},
  {1949, 646},
  {1946, 647},
  {1943, 649},
  {1941, 651},
  {1938, 653},
  {1935, 655},
  {1933, 657},
  {1930, 659},
  {1928, 701},
  {1925, 703},
  {1922, 705},
  {1920, 707},
  {1917, 708},
  {1915, 710},
  {1912, 712},
  {1909, 714},
  {1907, 716},
  {1904, 718},
  {1902, 720},
  {1859, 722},
  {1856, 724}, //273, 01-10-2017
  {1854, 726},
  {1851, 728},
  {1849, 730},
  {1846, 732},
  {1844, 734},
  {1841, 736},
  {1838, 738},
  {1836, 740},
  {1833, 742},
  {1831, 744},
  {1828, 746},
  {1826, 748},
  {1823, 750},
  {1821, 752},
  {1819, 754},
  {1816, 756},
  {1814, 758},
  {1811, 800},
  {1809, 802},
  {1807, 804},
  {1804, 806},
  {1802, 808},
  {1800, 810},
  {1757, 812},
  {1755, 814},
  {1753, 816},
  {1751, 818},
  {1648, 720},
  {1646, 722},
  {1644, 725},
  {1642, 727}, //305, 01-11-2017
  {1640, 729},
  {1638, 731},
  {1636, 733},
  {1634, 735},
  {1632, 737},
  {1630, 739},
  {1628, 741},
  {1626, 743},
  {1624, 745},
  {1622, 747},
  {1620, 749},
  {1619, 752},
  {1617, 754},
  {1615, 756},
  {1614, 758},
  {1612, 800},
  {1610, 802},
  {1609, 803},
  {1607, 805},
  {1606, 807},
  {1605, 809},
  {1603, 811},
  {1602, 813},
  {1601, 815},
  {1600, 817},
  {1559, 818},
  {1558, 820},
  {1557, 822},
  {1556, 823},
  {1555, 825}, //335, 01-12-2017
  {1554, 827},
  {1553, 828},
  {1553, 830},
  {1552, 831},
  {1551, 833},
  {1551, 834},
  {1550, 835},
  {1550, 837},
  {1550, 838},
  {1550, 839},
  {1549, 840},
  {1549, 841},
  {1549, 842},
  {1549, 843},
  {1549, 844},
  {1550, 845},
  {1550, 846},
  {1550, 846},
  {1551, 847},
  {1551, 847},
  {1552, 848},
  {1552, 848},
  {1553, 849},
  {1554, 849},
  {1554, 849},
  {1555, 849},
  {1556, 849},
  {1557, 849},
  {1558, 849},
  {1559, 849}, //365, 31-12-2017
  {1559, 849}  //366 i tilfælde af skudår
};

/* PORTOVERSIGT
    A4 -> display SDA + rtc SDA
    A5 -> display SCK + rtc SCL
    D4 -> relay IN1 (foran hus)
    D5 -> relay IN2 (bag hus)
    D6 -> knap 1 (stil 1 time tilbage)
    D7 -> knap 2 (stil 1 time frem)
    D8 -> knap 3 (tænd lys manuelt)
    D13 -> intern LED
*/

const int Relay1 = 4; //Sæt til port D4
const int Relay2 = 5; //Sæt til port D5
const int button1 = 6; //Sæt til port D6
const int button2 = 7; //Sæt til port D7
const int button3 = 8; //Sæt til port D8
const int statusBlinkPin = 13; //Sæt til port D13, intern LED
const unsigned long interval = 1000; // the time we need to wait
const unsigned long intervalTimer = 900000; //Tid lys skal være tændt ved tryk på knap 3. 900000 msek = 15 min, 15000 msek = 15 sek.
unsigned long currentMillis;
unsigned long previousMillis = 0; // millis() returns an unsigned long
unsigned long previousTimerMillis = 0; // millis() returns an unsigned long
//bool setBackTime = false;
bool manualOn = false; //Er lys tændt manuelt
bool button3State = false;
bool statusBlinkState = false; //For toggle blink on/off
bool statusRelay1 = false; //false = slukket, true = tændt
bool statusRelay2 = false; //false = slukket, true = tændt
DateTime now;

//Vi kan spare 36 bytes SRAM ved at bruge PROGMEM
const char charOn[] PROGMEM = {"ON"};
const char charOff[] PROGMEM = {"OFF"};
const char charForan[] PROGMEM = {"      <Foran"};
const char charBag[] PROGMEM = {"           Bag>"};
const char charGemTid[] PROGMEM = {" Gem tid? "};
const char charJa[] PROGMEM = {"    JA: Tryk igen    "};
const char charNej[] PROGMEM = {"      NEJ: Vent      "};
const char charTidNul[] PROGMEM = {":00:00"};

void setup()   {
  //Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  //RTC.adjust(DateTime(__DATE__, __TIME__));
  //Sæt tid: DateTime(year,month,day,hour,min,sec)

  pinMode(Relay1, OUTPUT);
  pinMode(Relay2, OUTPUT);
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(button3, INPUT);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C
  display.ssd1306_command(SSD1306_SETCONTRAST); //Vælg lysstyrkeregister
  display.ssd1306_command(0); //Sæt lysstyrkeregister til det lavest mulige
  display.display(); //Skriv skærmbuffer (logo) til skærm
  delay(5000);

  //Clear the buffer/screen
  display.clearDisplay();
  display.display();
  delay(500);
  pinMode(statusBlinkPin, OUTPUT);
}

void loop() {
  currentMillis = millis(); //grab current time
  if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    if (((unsigned long)(currentMillis - previousTimerMillis) >= intervalTimer) && (manualOn == true)) {
      previousTimerMillis = millis(); //save the "current" time
      manualOn = false;
    }
    now = RTC.now(); //Hent tid fra RTC
    setRelays((now.hour() * 100) + now.minute(), calculateDayOfYear(now.day(), now.month(), now.year()) - 1); //styr relæerne med: (tid som int, day of year)
    display.clearDisplay(); //Clear display
    printRelayStatus();
    printStaticText();
    printTimeDate();
    printSunUpDown();
    statusBlink();
    display.display(); //Print to screen
    previousMillis = millis(); //save the "current" time
  }

  if (digitalRead(button1) == HIGH) {
    delay(20); //Debounce
    if (digitalRead(button1) == HIGH) {
      while (digitalRead(button1) == HIGH) delay(10); //Debounce, wait for no button press
      knap1();
    }
  }

  if (digitalRead(button2) == HIGH) {
    delay(20); //Debounce
    if (digitalRead(button2) == HIGH) {
      while (digitalRead(button2) == HIGH) delay(10); //Debounce, wait for no button press
      knap2();
    }
  }

  if (digitalRead(button3) == HIGH) {
    delay(20);
    if (button3State == false) {
      if (digitalRead(button3) == HIGH) {
        if (manualOn == true) {
          manualOn = false;
        } else {
          manualOn = true;
        }
        button3State = true;
      }
    }
    previousTimerMillis = millis();
  } else button3State = false;
}

void knap1() {
  char printChar;
  //int k;
  int len;
  display.clearDisplay();
  display.setCursor(6, 0);
  display.setTextSize(2);
  display.setTextColor(BLACK, WHITE);
  //display.println(" Gem tid? ");
  len = strlen_P(charGemTid);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charGemTid + k);
    display.print(printChar);
  }
  display.println();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.println();
  display.print(" ");
  display.setTextSize(2);
  display.print(" ");
  if (now.hour() < 10) display.print("0");
  display.print(now.hour(), DEC);
  //display.println(":00:00");
  len = strlen_P(charTidNul);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charTidNul + k);
    display.print(printChar);
  }
  display.println();
  display.setTextSize(1);
  display.println();
  //display.println("    JA: Tryk igen    ");
  len = strlen_P(charJa);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charJa + k);
    display.print(printChar);
  }
  display.println();
  //display.println("      NEJ: Vent      ");
  len = strlen_P(charNej);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charNej + k);
    display.print(printChar);
  }
  display.println();
  display.display(); //Print to screen
  for (int i = 0; i < 5000; i++) {
    if (digitalRead(button1) == HIGH) {
      RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), 0, 0));
      display.clearDisplay();
      display.setCursor(6, 0);
      display.setTextSize(2);
      display.setTextColor(BLACK, WHITE);
      //display.println(" Gem tid? ");
      len = strlen_P(charGemTid);
      for (int k = 0; k < len; k++) {
        printChar = pgm_read_byte_near(charGemTid + k);
        display.print(printChar);
      }
      display.println();
      display.setTextColor(WHITE);
      display.setTextSize(2);
      display.println();

      display.setTextSize(4);
      display.setCursor(36, 24);
      display.print("OK!");
      display.display(); //Print to screen
      
      delay(2500);
      //setBackTime = false;
      break;
    }
    delay(1);
  }
}

void knap2() {
  char printChar;
  //int k;
  int len;
  display.clearDisplay();
  display.setCursor(6, 0);
  display.setTextSize(2);
  display.setTextColor(BLACK, WHITE);
  //display.println(" Gem tid? ");
  len = strlen_P(charGemTid);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charGemTid + k);
    display.print(printChar);
  }
  display.println();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.println();
  display.print(" ");
  display.setTextSize(2);
  display.print(" ");
  if (now.hour() < 10) display.print("0");
  display.print(now.hour()+1, DEC);
  //display.println(":00:00");
  len = strlen_P(charTidNul);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charTidNul + k);
    display.print(printChar);
  }
  display.println();
  display.setTextSize(1);
  display.println();
  //display.println("    JA: Tryk igen    ");
  len = strlen_P(charJa);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charJa + k);
    display.print(printChar);
  }
  display.println();
  //display.println("      NEJ: Vent      ");
  len = strlen_P(charNej);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charNej + k);
    display.print(printChar);
  }
  display.println();
  display.display(); //Print to screen
  for (int i = 0; i < 5000; i++) {
    if (digitalRead(button2) == HIGH) {
      RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour()+1, 0, 0));
      display.clearDisplay();
      display.setCursor(6, 0);
      display.setTextSize(2);
      display.setTextColor(BLACK, WHITE);
      //display.println(" Gem tid? ");
      len = strlen_P(charGemTid);
      for (int k = 0; k < len; k++) {
        printChar = pgm_read_byte_near(charGemTid + k);
        display.print(printChar);
      }
      display.println();
      display.setTextColor(WHITE);
      display.setTextSize(2);
      display.println();

      display.setTextSize(4);
      display.setCursor(36, 24);
      display.print("OK!");
      display.display(); //Print to screen
      delay(2500);
      //setBackTime = false;
      break;
    }
    delay(1);
  }
}

void statusBlink() {
  if (statusBlinkState == true) {
    digitalWrite(statusBlinkPin, LOW);
    statusBlinkState = false;
    display.fillRect(60, 24, 4, 12, BLACK); //Fjern kolon i tid hvert interval
  } else {
    digitalWrite(statusBlinkPin, HIGH);
    statusBlinkState = true;
  }
}

void setRelays(int timeNow, int dayOfYear) {
  if (manualOn == true) {
    taendRelay(Relay1);
    taendRelay(Relay2);
    statusRelay1 = true;
    statusRelay2 = true;
  } else {
    int solOp = pgm_read_word(&(soltid[dayOfYear][1]));
    int solNed = pgm_read_word(&(soltid[dayOfYear][0]));
    //Tjek om vi er ((over/lig solopgang) OG (under solnedgang)) ELLER ((over 00:15) OG (under 05:15))
    if (((timeNow >= solOp) && (timeNow < solNed)) || ((timeNow >= 15) && (timeNow < 515))) {
      //Sluk lys
      slukRelay(Relay1);
      slukRelay(Relay2);
      statusRelay1 = false;
      statusRelay2 = false;
    } else {
      //Tænd lys
      taendRelay(Relay1);
      slukRelay(Relay2);
      statusRelay1 = true;
      statusRelay2 = false;
    }
  }
}

void taendRelay(int R) {
  digitalWrite(R, LOW);
}

void slukRelay(int R) {
  digitalWrite(R, HIGH);
}

void printRelayStatus() {
  display.setCursor(0, 0);
  display.setTextSize(2);
  if (manualOn == true) {
    const long divider = 60000; //60000 ved 15 min, sæt til 1000 hvis 15 sek.
    int timerLeft = ((intervalTimer - (currentMillis - previousTimerMillis)) / divider) + 1;

    if (timerLeft > (intervalTimer / divider)) {
      timerLeft = intervalTimer / divider;

    }

    display.setTextColor(BLACK, WHITE);
    display.print(timerLeft);
    //display.setTextColor(WHITE);
    if (timerLeft > 9) {
      //display.print("      ");
      display.setCursor(100, 0);
    } else display.setCursor(112, 0); //display.print("        ");
    //display.setTextColor(BLACK, WHITE);

    display.print(timerLeft);
    //display.print((int)((intervalTimer - (currentMillis - previousTimerMillis)) / divider));
  } else {
    char printChar;
    //int k;
    int len;
    //display.clearDisplay();
    if (statusRelay1 == true) {
      display.setTextColor(BLACK, WHITE);
      len = strlen_P(charOn);
      for (int k = 0; k < len; k++) {
        printChar = pgm_read_byte_near(charOn + k);
        display.print(printChar);
      }
      //display.print("ON");
      display.setTextColor(WHITE);
      display.print(" "); //Kan ikke spare noget ved PROGMEM
    }
    else {
      display.setTextColor(WHITE);
      len = strlen_P(charOff);
      for (int k = 0; k < len; k++) {
        printChar = pgm_read_byte_near(charOff + k);
        display.print(printChar);
      }
      //display.print("OFF");
    }
    display.setCursor(92, 0);
    display.setTextColor(WHITE);
    if (statusRelay2 == true) {
      display.setTextColor(WHITE);
      display.print(" "); //Kan ikke spare noget ved PROGMEM
      display.setTextColor(BLACK, WHITE);
      //display.print("ON");
      len = strlen_P(charOn);
      for (int k = 0; k < len; k++) {
        printChar = pgm_read_byte_near(charOn + k);
        display.print(printChar);
      }
    }
    else {
      len = strlen_P(charOff);
      for (int k = 0; k < len; k++) {
        printChar = pgm_read_byte_near(charOff + k);
        display.print(printChar);
      }
      //display.print("OFF");
    }
  }
}

void printStaticText() {
  char printChar;
  //int k;
  int len;
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  len = strlen_P(charForan);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charForan + k);
    display.print(printChar);
  }
  display.println();
  //display.println("      <Foran");
  len = strlen_P(charBag);
  for (int k = 0; k < len; k++) {
    printChar = pgm_read_byte_near(charBag + k);
    display.print(printChar);
  }
  display.println();
  //display.println("           Bag>");
}

void printTimeDate() {
  display.setCursor(4, 16);
  display.setTextSize(4);
  display.setTextColor(WHITE);
  if (now.hour() < 10) display.print(0, DEC);
  display.print(now.hour(), DEC);
  display.print(":");
  if (now.minute() < 10) display.print(0, DEC);
  display.println(now.minute(), DEC);
  //display.setTextColor(WHITE);
  display.setCursor(36, 48);
  display.setTextSize(1);
  if (now.day() < 10) display.print(0, DEC);
  display.print(now.day(), DEC);
  display.print("/");
  if (now.month() < 10) display.print(0, DEC);
  display.print(now.month(), DEC);
  display.print("/");
  display.println(now.year(), DEC);
}

void printSunUpDown() {
  //Deklarer og sæt day of year til 0
  int dagnr = 0;

  //Udregn day of year og træk 1 fra, da array index starter på 0
  dagnr = calculateDayOfYear(now.day(), now.month(), now.year()) - 1;

  //Hent solop og -ned fra array
  int sunUp = pgm_read_word(&(soltid[dagnr][1]));
  int sunDown = pgm_read_word(&(soltid[dagnr][0]));

  //display.setCursor(0, 64);
  display.setTextSize(1);
  display.print(" Op: ");
  display.print(convertIntToTime(sunUp));
  display.print(" Ned: ");
  display.print(convertIntToTime(sunDown));
  //if (digitalRead(button3) == HIGH) display.print("!");
}

String convertIntToTime(int intTime) {
  String tempStreng = String(intTime).substring(0, String(intTime).length() - 2) + ":";
  return tempStreng + String(intTime).substring(String(intTime).length() - 2);
}

int calculateDayOfYear(int day, int month, int year) {

  // Given a day, month, and year (4 digit), returns
  // the day of year. Errors return 999.

  int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

  // Verify we got a 4-digit year
  if (year < 1000) {
    return 999;
  }

  // Check if it is a leap year, this is confusing business
  if (year % 4  == 0) {
    if (year % 100 != 0) {
      daysInMonth[1] = 29;
    }
    else {
      if (year % 400 == 0) {
        daysInMonth[1] = 29;
      }
    }
  }

  // Make sure we are on a valid day of the month
  if (day < 1) {
    return 999;
  } else if (day > daysInMonth[month - 1]) {
    return 999;
  }

  int doy = 0;
  for (int i = 0; i < month - 1; i++) {
    doy += daysInMonth[i];
  }

  doy += day;
  return doy;
}