#include <BMP085.h>
#include <EEPROM.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <DS1302.h>
#include <TimeLord.h>
#include <Wire.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 6, 7);
DS1302 rtc(12, 11, 10);
Time t = rtc.time();
String dayAsString(const Time::Day day) {
  switch (day) {
    case Time::kSunday: return "Sunday";
    case Time::kMonday: return "Monday";
    case Time::kTuesday: return "Tuesday";
    case Time::kWednesday: return "Wednesday";
    case Time::kThursday: return "Thursday";
    case Time::kFriday: return "Friday";
    case Time::kSaturday: return "Saturday";
  }
  return "(unknown day)";
}
TimeLord tardis;
float const LATITUDE = 52.70;
float const LONGITUDE = 25.40;
byte today[6];
byte prevSecond = 99, prevHour = 99;
BMP085 dps = BMP085();
long Temperature = 0, Pressure = 0;
float t_f = 0;
int buttonPushCounter = 0;
int buttonState = 0;
int lastButtonState = 0;
const unsigned char PROGMEM moon0[] =
{ B00000111, B11100000,
  B00001000, B00010000,
  B00010000, B00001000,
  B00100000, B00000100,
  B01000000, B00000010,
  B10000000, B00000001,
  B10000000, B00000001,
  B10000000, B00000001,
  B10000000, B00000001,
  B10000000, B00000001,
  B01000000, B00000010,
  B00100000, B00000100,
  B00010000, B00001000,
  B00001000, B00010000,
  B00000111, B11100000
};
const unsigned char PROGMEM moon1[] =
{ B00000111, B11100000,
  B00001000, B01110000,
  B00010000, B00111000,
  B00100000, B00011100,
  B01000000, B00001110,
  B10000000, B00001111,
  B10000000, B00001111,
  B10000000, B00001111,
  B10000000, B00001111,
  B10000000, B00001111,
  B01000000, B00001110,
  B00100000, B00011100,
  B00010000, B00111000,
  B00001000, B01110000,
  B00000111, B11100000
};
const unsigned char PROGMEM moon2[] =
{ B00000111, B11100000,
  B00001000, B11110000,
  B00010000, B11111000,
  B00100000, B11111100,
  B01000000, B11111110,
  B10000000, B11111111,
  B10000000, B11111111,
  B10000000, B11111111,
  B10000000, B11111111,
  B10000000, B11111111,
  B01000000, B11111110,
  B00100000, B11111100,
  B00010000, B11111000,
  B00001000, B11110000,
  B00000111, B11100000
};
const unsigned char PROGMEM moon3[] =
{ B00000111, B11100000,
  B00001011, B11110000,
  B00010111, B11111000,
  B00101111, B11111100,
  B01001111, B11111110,
  B10001111, B11111111,
  B10001111, B11111111,
  B10001111, B11111111,
  B10001111, B11111111,
  B10001111, B11111111,
  B01001111, B11111110,
  B00101111, B11111100,
  B00010111, B11111000,
  B00001011, B11110000,
  B00000111, B11100000
};
const unsigned char PROGMEM moon4[] =
{ B00000111, B11100000,
  B00001111, B11110000,
  B00011111, B11111000,
  B00111111, B11111100,
  B01111111, B11111110,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B01111111, B11111110,
  B00111111, B11111100,
  B00011111, B11111000,
  B00001111, B11110000,
  B00000111, B11100000
};
const unsigned char PROGMEM moon5[] =
{ B00000111, B11100000,
  B00001111, B11010000,
  B00011111, B11101000,
  B00111111, B11110100,
  B01111111, B11110010,
  B11111111, B11110001,
  B11111111, B11110001,
  B11111111, B11110001,
  B11111111, B11110001,
  B11111111, B11110001,
  B01111111, B11110010,
  B00111111, B11110100,
  B00011111, B11101000,
  B00001111, B11010000,
  B00000111, B11100000
};
const unsigned char PROGMEM moon6[] =
{ B00000111, B11100000,
  B00001111, B00010000,
  B00011111, B00001000,
  B00111111, B00000100,
  B01111111, B00000010,
  B11111111, B00000001,
  B11111111, B00000001,
  B11111111, B00000001,
  B11111111, B00000001,
  B11111111, B00000001,
  B01111111, B00000010,
  B00111111, B00000100,
  B00011111, B00001000,
  B00001111, B00010000,
  B00000111, B11100000
};
const unsigned char PROGMEM moon7[] =
{ B00000111, B11100000,
  B00001110, B00010000,
  B00011100, B00001000,
  B00111000, B00000100,
  B01110000, B00000010,
  B11110000, B00000001,
  B11110000, B00000001,
  B11110000, B00000001,
  B11110000, B00000001,
  B11110000, B00000001,
  B01110000, B00000010,
  B00111000, B00000100,
  B00011100, B00001000,
  B00001110, B00010000,
  B00000111, B11100000
};
void drawMoon(int moon_x, int moon_y, int phase) {
  display.fillRect(moon_x, moon_y, 16, 15, WHITE);
  display.drawBitmap(moon_x, moon_y, moon4,  16, 15, WHITE);
  switch (phase) {
    case 0:
      display.drawBitmap(moon_x, moon_y, moon0,  16, 15, BLACK);
      break;
    case 1:
      display.drawBitmap(moon_x, moon_y, moon1,  16, 15, BLACK);
      break;
    case 2:
      display.drawBitmap(moon_x, moon_y, moon2,  16, 15, BLACK);
      break;
    case 3:
      display.drawBitmap(moon_x, moon_y, moon3,  16, 15, BLACK);
      break;
    case 4:
      display.drawBitmap(moon_x, moon_y, moon4,  16, 15, BLACK);
      break;
    case 5:
      display.drawBitmap(moon_x, moon_y, moon5,  16, 15, BLACK);
      break;
    case 6:
      display.drawBitmap(moon_x, moon_y, moon6,  16, 15, BLACK);
      break;
    case 7:
      display.drawBitmap(moon_x, moon_y, moon7,  16, 15, BLACK);
      break;
    default:
      display.drawBitmap(moon_x, moon_y, moon4,  16, 15, WHITE);
  }
}
void drawMoonDate(int moon_x, int moon_y, uint8_t * datetoday) {
  float phase;
  phase = tardis.MoonPhase(datetoday);
  if (phase >= 0.0   && phase <= 0.0625)  {
    drawMoon(moon_x, moon_y, 0);
  }; 
  if (phase > 0.0625 && phase <= 0.1875)  {
    drawMoon(moon_x, moon_y, 1);
  }; 
  if (phase > 0.1875 && phase <= 0.3125 ) {
    drawMoon(moon_x, moon_y, 2);
  }; 
  if (phase > 0.3125 && phase <= 0.4375)  {
    drawMoon(moon_x, moon_y, 3);
  }; 
  if (phase > 0.4375 && phase <= 0.5625)  {
    drawMoon(moon_x, moon_y, 4);
  }; 
  if (phase > 0.5625 && phase <= 0.6875)  {
    drawMoon(moon_x, moon_y, 5);
  }; 
  if (phase > 0.6875 && phase <= 0.8125)  {
    drawMoon(moon_x, moon_y, 6);
  }; 
  if (phase > 0.8125 && phase <= 0.9375)  {
    drawMoon(moon_x, moon_y, 7);
  }; 
  if (phase > 0.9375 && phase <= 1)       {
    drawMoon(moon_x, moon_y, 0);
  }; 
}
void drawSignal(float streng) {
  display.fillRect(0, 0, 12, 6, WHITE);
  display.drawTriangle(0, 0, 8, 0, 4, 4, BLACK);
  display.drawLine(4, 0, 4, 6, BLACK);
  display.drawLine(6, 5, 6, 6, BLACK);
  display.drawLine(8, 4, 8, 6, BLACK);
  display.drawLine(10, 2, 10, 6, BLACK);
  display.drawLine(12, 0, 12, 6, BLACK);
}
void drawBatteryState(float v_bat) {
  display.fillRect(68, 0, 16, 7, WHITE);
  display.drawRect(83, 2, 1, 3, BLACK);
  display.drawRoundRect(68, 0, 15, 7, 2, BLACK);
  
  
  
  
  
  
  
  if (v_bat > 4500)   {
    display.fillRect(70, 2, 10, 3, BLACK);
  }
  if (v_bat > 4048)   {
    display.drawRect(79, 2, 2, 3, BLACK);
  }
  if (v_bat > 3896)   {
    display.drawRect(76, 2, 2, 3, BLACK);
  }
  if (v_bat > 3744)    {
    display.drawRect(73, 2, 2, 3, BLACK);
  }
  if (v_bat > 3592)    {
    display.drawRect(70, 2, 2, 3, BLACK);
  }
}
void drawTime(byte x, byte y) {
  display.fillRect(0 + x, 0 + y, 48, 7, WHITE);
  
  Time t = rtc.time();
  display.setTextColor(BLACK);
  display.setTextSize(1);
  display.setCursor(x, y);
  display.print(t.hr);
  display.print(":");
  display.print(t.min);
  display.print(":");
  display.print(t.sec);
}
void updateMoonSunDate()
{
  Time t = rtc.time();
  today[0] = 0;
  today[1] = 0;
  today[2] = 12;
  today[3] = t.date;
  today[4] = t.mon;
  today[5] = t.yr - 2000;
}
void drawSunRiseSet(byte x, byte y) {
  updateMoonSunDate();
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.fillRect(x, y, 33, y + 8, WHITE);
  if (tardis.SunRise(today)) 
  {
    display.setCursor(x, y);
    display.print((int) today[tl_hour]);
    display.print(":");
    display.println((int) today[tl_minute]);
  }
  if (tardis.SunSet(today)) 
  {
    display.setCursor(x, y + 8);
    display.print((int) today[tl_hour]);
    display.print(":");
    display.println((int) today[tl_minute]);
  }
}
void drawPressure(byte x, byte y) {
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.fillRect(x, y, 33, y + 8, WHITE);
  display.setCursor(x, y);
  t_f = Temperature;
  display.println( t_f / 10, 1);
  display.setCursor(x, y + 8);
  
  display.println(Pressure / 133.3, 1);
}
long readVcc() {
  
  
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
#else
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
  delay(75); 
  ADCSRA |= _BV(ADSC); 
  while (bit_is_set(ADCSRA, ADSC)); 
  uint8_t low  = ADCL; 
  uint8_t high = ADCH; 
  long result = (high << 8) | low;
  
  
  
  
  
  result = 1132060 / result;
  return result; 
  
}
void drawVcc(byte x, byte y, word vcc) {
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.fillRect(x, y, 33, y + 8, WHITE);
  display.setCursor(x, y);
  display.println(vcc);
}
void pressure_drawLine(byte x, byte h)
{
  display.drawLine(x, 47 - h, x, 47, BLACK);
}
void pressure_drawGraph()
{
  display.fillRect(0, 25, 83, 47, WHITE);
  for (int i = 0; i <= 83; i++) {
    pressure_drawLine(i, EEPROM.read(i));
  }
}
void setup()
{
  Serial.begin(9600);
 
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(2, OUTPUT);
  
  
  
  String day = dayAsString(t.day);
  
  tardis.TimeZone(3 * 55);
  tardis.Position(LATITUDE, LONGITUDE);
  
  Wire.begin();
  display.begin();
  display.setContrast(55);
  display.clearDisplay();
  display.drawLine(0, display.height() / 2, display.width(), display.height() / 2, BLACK);
  dps.init();
  updateMoonSunDate();
  drawMoonDate(34, 8, today);
  pressure_drawGraph();
  display.display();
  prevHour = rtc.time().hr;
  
  
  
  
  
  
}
void loop()
{
  unsigned long currentMillis = millis();
  unsigned long currentMillis2 = millis();
  byte temp;
  
  
  
  if (rtc.time().hr != prevHour) {
    prevHour = rtc.time().hr;
    dps.getPressure(&Pressure);
    dps.getTemperature(&Temperature);
    for (int i = 0; i <= 82; i++) {
      temp = EEPROM.read(i + 1);
      EEPROM.write(i, temp);
    }
    EEPROM.write(83, ceil(Pressure / 133.3) - 740);
    pressure_drawGraph();
    display.display();
  }
  
  
  
  if (rtc.time().sec != prevSecond) {
    prevSecond = rtc.time().sec;
    dps.getPressure(&Pressure);
    dps.getTemperature(&Temperature);
    updateMoonSunDate();
    drawPressure(0, 8);
    drawTime(17, 0);
    drawSunRiseSet(53, 8);
    drawMoonDate(34, 8, today);
    drawBatteryState(readVcc());
    drawSignal(5);
    
    display.display();
  }
  
  buttonState = digitalRead(8);
  
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPushCounter++;
    }
  }
  lastButtonState = buttonState;
  if (buttonPushCounter % 2 == 0) {
    digitalWrite(2, HIGH);
  } else {
    digitalWrite(2, LOW);
  }
}