//lolin wemos d1 mini pro
// com port
//avrisp mkii

#include "Arduino.h"
#include <ArduinoJson.h>
#include <Esp32WifiManager.h>
#include "math.h"

WiFiClient client;

int day, month, year, dayOfWeek;
int summerTime = 1;
String miesiac;
int dzien;
String date;
String linia;

#define NUM_MAX 4

// for NodeMCU 1.0
#define DIN_PIN 13  // D7
#define CS_PIN  15  // D8
#define CLK_PIN 14  // D5

#define ROTATE 270   // Orientacja użytych modułów max7219 hehe

#include "max7219.h"
#include "fonts.h"
#define HOSTNAME "ESP8266-OTA-"

// =======================================================================
// CHANGE YOUR CONFIG HERE:
// =======================================================================


const char* ssid     = "FRITZ!";
const char* password = "2316743813681670";



int L = 0;


void setup()
{
  Serial.begin(115200);
  initMAX7219();
  sendCmdAll(CMD_SHUTDOWN, 1);

  // JASNOŚĆ DIODEK BW
  sendCmdAll(CMD_INTENSITY, L);
  Serial.print("WiFi... ");

  WiFi.begin(ssid, password);

  printStringWithShift("Collegamento", 15);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("IP: "); Serial.println(WiFi.localIP());
  printStringWithShift((String("  IP: ") + WiFi.localIP().toString()).c_str(), 15);
  delay(1500);
}


// =============================DEFINE VARS==============================
#define MAX_DIGITS 20
byte dig[MAX_DIGITS] = {0};
byte digold[MAX_DIGITS] = {0};
byte digtrans[MAX_DIGITS] = {0};
int updCnt = 0;
int dots = 0;
long dotTime = 0;
long clkTime = 0;
int dx = 0;
int dy = 0;
byte del = 0;
int h, m, s;
//BW
float utcOffset = +1;
long localEpoc = 0;
long localMillisAtUpdate = 0;
int pauzakurwa = 40;
// =======================================================================
void loop()
{
  if (updCnt <= 0) { // every 10 scrolls, ~450s=7.5m
    updCnt = 60;
    Serial.println("Dane ...");
    printStringWithShift("   Czas...", 15);
    getTime();
    Serial.println("Dane zaladowane");
    clkTime = millis();
  }

  if (millis() - clkTime > 60000 && !del && dots) { // clock for 30s, then scrolls for about 30s
    //    printStringWithShift(date.c_str(),40);
    //    delay(2000);
    updCnt--;
    clkTime = millis();
  }
  if (millis() - dotTime > 500) {
    dotTime = millis();
    dots = !dots;
  }
  updateTime();
  showAnimClock();
}

// =======================================================================

void showSimpleClock()
{
  dx = dy = 0;
  clr();
  showDigit(h / 10,  0, dig6x8);
  showDigit(h % 10,  8, dig6x8);
  showDigit(m / 10, 17, dig6x8);
  showDigit(m % 10, 25, dig6x8);
  showDigit(s / 10, 34, dig6x8);
  showDigit(s % 10, 42, dig6x8);
  setCol(15, dots ? B00100100 : 0);
  setCol(32, dots ? B00100100 : 0);
  refreshAll();
}

// =======================================================================

void showAnimClock()
{
  byte digPos[6] = {0, 8, 17, 25, 34, 42};
  int digHt = 12;
  int num = 6;
  int i;
  if (del == 0) {
    del = digHt;
    for (i = 0; i < num; i++) digold[i] = dig[i];
    dig[0] = h / 10 ? h / 10 : 10;
    dig[1] = h % 10;
    dig[2] = m / 10;
    dig[3] = m % 10;
    dig[4] = s / 10;
    dig[5] = s % 10;
    for (i = 0; i < num; i++)  digtrans[i] = (dig[i] == digold[i]) ? 0 : digHt;
  } else
    del--;

  clr();
  for (i = 0; i < num; i++) {
    if (digtrans[i] == 0) {
      dy = 0;
      showDigit(dig[i], digPos[i], dig6x8);
    } else {
      dy = digHt - digtrans[i];
      showDigit(digold[i], digPos[i], dig6x8);
      dy = -digtrans[i];
      showDigit(dig[i], digPos[i], dig6x8);
      digtrans[i]--;
    }
  }
  dy = 0;
  setCol(15, dots ? B00100100 : 0);
  setCol(32, dots ? B00100100 : 0);
  refreshAll();
  delay(30);
  // TU GUMA wypiszemy zmienne na port szeregowy
  // Serial.print(linia);

  // Serial.print(" Month=");
  // Serial.print( month );
  // Serial.print(" Day=");
  // Serial.print(day);
  // Serial.print(" Dzien wydlubany=");
  // Serial.print(dzien);
  // Serial.print(" miesiac wydl=");
  // Serial.print(miesiac);
  // Serial.print("    ");
  // Serial.println( summerTime );


  // KONIEC pisania GUMY na port
}

// =======================================================================

void showDigit(char ch, int col, const uint8_t *data)
{
  if (dy < -8 | dy > 8) return;
  int len = pgm_read_byte(data);
  int w = pgm_read_byte(data + 1 + ch * len);
  col += dx;
  for (int i = 0; i < w; i++)
    if (col + i >= 0 && col + i < 8 * NUM_MAX) {
      byte v = pgm_read_byte(data + 1 + ch * len + 1 + i);
      if (!dy) scr[col + i] = v; else scr[col + i] |= dy > 0 ? v >> dy : v << -dy;
    }
}

// =======================================================================

void setCol(int col, byte v)
{
  if (dy < -8 | dy > 8) return;
  col += dx;
  if (col >= 0 && col < 8 * NUM_MAX)
      if (!dy) scr[col] = v; else scr[col] |= dy > 0 ? v >> dy : v << -dy;
}

// =======================================================================

int showChar(char ch, const uint8_t *data)
{
  int len = pgm_read_byte(data);
  int i, w = pgm_read_byte(data + 1 + ch * len);
  for (i = 0; i < w; i++)
    scr[NUM_MAX * 8 + i] = pgm_read_byte(data + 1 + ch * len + 1 + i);
  scr[NUM_MAX * 8 + i] = 0;
  return w;
}

// =======================================================================
int dualChar = 0;

unsigned char convertPolish(unsigned char _c)
{
  unsigned char c = _c;
  if (c == 196 || c == 197 || c == 195) {
    dualChar = c;
    return 0;
  }
  if (dualChar) {
    switch (_c) {
      case 133: c = 1 + '~'; break; // 'ą'
      case 135: c = 2 + '~'; break; // 'ć'
      case 153: c = 3 + '~'; break; // 'ę'
      case 130: c = 4 + '~'; break; // 'ł'
      case 132: c = dualChar == 197 ? 5 + '~' : 10 + '~'; break; // 'ń' and 'Ą'
      case 179: c = 6 + '~'; break; // 'ó'
      case 155: c = 7 + '~'; break; // 'ś'
      case 186: c = 8 + '~'; break; // 'ź'
      case 188: c = 9 + '~'; break; // 'ż'
      //case 132: c = 10+'~'; break; // 'Ą'
      case 134: c = 11 + '~'; break; // 'Ć'
      case 152: c = 12 + '~'; break; // 'Ę'
      case 129: c = 13 + '~'; break; // 'Ł'
      case 131: c = 14 + '~'; break; // 'Ń'
      case 147: c = 15 + '~'; break; // 'Ó'
      case 154: c = 16 + '~'; break; // 'Ś'
      case 185: c = 17 + '~'; break; // 'Ź'
      case 187: c = 18 + '~'; break; // 'Ż'
      default:  break;
    }
    dualChar = 0;
    return c;
  }
  switch (_c) {
    case 185: c = 1 + '~'; break;
    case 230: c = 2 + '~'; break;
    case 234: c = 3 + '~'; break;
    case 179: c = 4 + '~'; break;
    case 241: c = 5 + '~'; break;
    case 243: c = 6 + '~'; break;
    case 156: c = 7 + '~'; break;
    case 159: c = 8 + '~'; break;
    case 191: c = 9 + '~'; break;
    case 165: c = 10 + '~'; break;
    case 198: c = 11 + '~'; break;
    case 202: c = 12 + '~'; break;
    case 163: c = 13 + '~'; break;
    case 209: c = 14 + '~'; break;
    case 211: c = 15 + '~'; break;
    case 140: c = 16 + '~'; break;
    case 143: c = 17 + '~'; break;
    case 175: c = 18 + '~'; break;
    default:  break;
  }
  return c;
}

// =======================================================================

void printCharWithShift(unsigned char c, int shiftDelay) {
  c = convertPolish(c);
  if (c < ' ' || c > '~' + 25) return;
  c -= 32;
  int w = showChar(c, font);
  for (int i = 0; i < w + 1; i++) {
    delay(pauzakurwa);
    scrollLeft();
    refreshAll();
  }
}

// =======================================================================

void printStringWithShift(const char* s, int shiftDelay) {
  while (*s) {
    printCharWithShift(*s, shiftDelay);
    s++;
  }
}
// =======================================================================

void getTime()
{
  WiFiClient client;
  if (!client.connect("www.google.com", 80)) {
    Serial.println("connection to google failed");
    return;
  }

  client.print(String("GET / HTTP/1.1\r\n") +
               String("Host: www.google.com\r\n") +
               //String("Połączenie: close\r\n\r\n"));
               String("connection: close\r\n\r\n"));
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    //Serial.println(".");
    repeatCounter++;
  }

  String line;
  client.setNoDelay(false);
  while (client.connected() && client.available()) {
    line = client.readStringUntil('\n');

    line.toUpperCase();
           //line = "DATE: THU, 29 FEB 2022 13:00:13 GMT";  // TU w celach testowych czy działa zmiana czasu
    
    if (line.startsWith("DATE: ")) {
      date = "     " + line.substring(6, 22);
      date.toUpperCase();
      //      decodeDate(date);
      h = line.substring(23, 25).toInt();
      m = line.substring(26, 28).toInt();
      s = line.substring(29, 31).toInt();
      dzien = line.substring(11, 13).toInt();
      miesiac = line.substring(14, 17);

      if (miesiac == "JAN") {
        month = 1;
      }
      if (miesiac == "FEB") {
        month = 2;
      }
      if (miesiac == "MAR") {
        month = 3;
      }
      if (miesiac == "APR") {
        month = 4;
      }
      if (miesiac == "MAY") {
        month = 5;
      }
      if (miesiac == "JUN") {
        month = 6;
      }
      if (miesiac == "JUL") {
        month = 7;
      }
      if (miesiac == "AUG") {
        month = 8;
      }
      if (miesiac == "SEP") {
        month = 9;
      }
      if (miesiac == "OCT") {
        month = 10;
      }
      if (miesiac == "NOV") {
        month = 11;
      }
      if (miesiac == "DEC") {
        month = 12;
      }
      
      day = dzien;

      linia = line;
      summerTime = checkSummerTime();
      if (h + utcOffset + summerTime > 23) {
        if (++day > 31) {
          day = 1;
          month++;
        };  // needs better patch
        if (++dayOfWeek > 7) dayOfWeek = 1;
      }
      localMillisAtUpdate = millis();
      localEpoc = (h * 60 * 60 + m * 60 + s);
    }
  }
  client.stop();
}

// =======================================================================

int checkSummerTime()   //BW
{
  //month = 10;
  // day = 29;
  //return 1;
  if (month > 3 && month < 10) return 1;
  if (month == 3 && day >= 31 - (((5 * year / 4) + 4) % 7) ) return 1;
  if (month == 10 && day < 31 - (((5 * year / 4) + 1) % 7) ) return 1;
  //GUMA
  //  miesiac = month;
  //  dzien = day;
  // END GUMA
  //LATO
  //return 1;

  //ZIMA
  return 0;

}

// =======================================================================

// =======================================================================

void updateTime()
{
  //long curEpoch = localEpoc + ((millis() - localMillisAtUpdate) / 1000);
 // long epoch = round(curEpoch + 3600 * (utcOffset + summerTime) + 86400L) % 86400L;
  //h = ((epoch  % 86400L) / 3600) % 24;
 // m = (epoch % 3600) / 60;
 // s = epoch % 60;
}

// =======================================================================