// global config

#include "config.h"

//################# LIBRARIES ##########################
#include <ESP8266WiFi.h>
#include <Timezone.h>        // https://github.com/JChristensen/Timezone
#include <ESP8266WebServer.h>
#include <WiFiManager.h>     // https://github.com/tzapu/WiFiManager
#include <DNSServer.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>  // https://github.com/markruys/arduino-Max72xxPanel
#include <time.h>

#include "OTAsetup.h"
#include "d_helper.h"


//################# DISPLAY CONNECTIONS ################
// LED Matrix Pin -> ESP8266 Pin
// Vcc            -> 3v  (3V on NodeMCU 3V3 on WEMOS)
// Gnd            -> Gnd (G on NodeMCU)
// DIN            -> D7  (Same Pin for WEMOS)
// CS             -> D4  (Same Pin for WEMOS)
// CLK            -> D5  (Same Pin for WEMOS)

//################ PROGRAM SETTINGS ####################
String version = "0.2b";
int PORT = 80;
int wait   = 50;
int spacer = 1;
int width  = 5 + spacer;
String SITE_WIDTH =  "1000";
int timezone = 0;
int dstOffset = 0;
const char* ntpServer = "fr.pool.ntp.org";
int brightness = 2;
int pinCS = D4;
int numberOfHorizontalDisplays = 4;
int numberOfVerticalDisplays   = 1;

//################## INITIALIZING ######################
char time_value[20];
String message, webpage;
ESP8266WebServer server(PORT);
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

//################## Time Zone & dst config #############
TimeChangeRule CET = {"CET", Last, Sun, Oct, 2, 60};  //UTC + 1 hour
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};  //UTC + 2 hours
Timezone CentralEuropean(CET, CEST);

void configModeCallback (WiFiManager *myWiFiManager) { // AP config mode
  display_static_message("Setup");
}

void setup() {
  Serial.begin(115200); // initialize serial communications
  DEBUG_PRINT(F("\r\n"));
  matrix.fillScreen(LOW);  //clr screen
  matrix.setIntensity(brightness);

  initOTA();

  for (int i=0; i<numberOfHorizontalDisplays; i++){
    DEBUG_PRINT(F("Changing orientation of display #"));
    DEBUG_PRINTLN(i);
    matrix.setRotation(i, 1); // chaque matrice
    matrix.setRotation(2);    // l'ensemble de l'afficheur
  }


  display_static_message("Wi-Fi");

  WiFiManager wifiManager;
  // reset saved settings
  // wifiManager.resetSettings();

#ifndef DEBUG_WifiM
  wifiManager.setDebugOutput(false); // no debug
#endif
  wifiManager.setTimeout(180);
  wifiManager.setAPCallback(configModeCallback);
  if(!wifiManager.autoConnect("LibreMetric")) {
    DEBUG_PRINTLN(F("failed to connect and timeout occurred"));
    display_message("Failed to connect");
    delay(6000);
    ESP.reset(); //reset and try again
    delay(180000);
  }
  matrix.fillScreen(LOW);
  // At this stage the WiFi manager will have successfully connected to a network, or if not will try again in 180-seconds
  DEBUG_PRINTLN(F("WiFi connected..."));
  display_static_message("OK");
  DEBUG_PRINTLN(WiFi.localIP());
  configTime(timezone * 3600, dstOffset * 3600, ntpServer); // First sync of time with (S)NTP UTC time

#ifdef DEBUG_TELNET
  // Start the Telnet server
  telnetServer.begin();
  telnetServer.setNoDelay(true);
#endif

//----------------------------------------------------------------------
  server.begin();
  DEBUG_PRINTLN(F("Webserver started..."));
  matrix.setIntensity(brightness);
  brightness=16;
  DEBUG_PRINT(numberOfHorizontalDisplays);
  DEBUG_PRINTLN(F(" displays configurated..."));

  server.on("/", GetMessage);
  message = "Bienvenue !";

}

void loop() {
#ifdef DEBUG_TELNET
  // Handle Telnet connection for debugging
  handleTelnet();
#endif
  server.handleClient();
  matrix.fillScreen(LOW);
  time_t now = time(nullptr);
  String time = String(ctime(&now));
  //Serial.println(time);
  time.trim();
  time.substring(11,19).toCharArray(time_value, 10);
  int seconds = time.substring(17,19).toInt();
  for (int i = 0; i <= 4; i++) {
    matrix.drawChar(i*6+2,0, (i==2 && seconds %2) ?  char(0x20): time_value[i], HIGH,LOW,1); // H
  }
  matrix.write(); // Send bitmap to display
  if (message != "") {
    DEBUG_PRINT(F("On envoi \""));
    DEBUG_PRINT(message);
    DEBUG_PRINTLN(F("\" à LibreMetric"));
    display_static_message(message); // Display the message
    DEBUG_PRINT(F("Message envoyé à LibreMetric : "));
    DEBUG_PRINTLN(message);
    message = "";
  }
  if (brightness <= 15) {
    DEBUG_PRINT(F("Nouvelle luminosité : "));
    DEBUG_PRINTLN(brightness);
    matrix.setIntensity(brightness);
    brightness = 16;
  }
  yield();
  ArduinoOTA.handle();
  yield();
}
void display_static_message(String message){
	matrix.fillScreen(LOW);
	if (width * message.length() - spacer > matrix.width()) {
	display_message(message);
	}
	else {
		int x = (matrix.width()-(width * message.length() - spacer))/2;
		int y = (matrix.height() - 8) / 2; // center the text vertically
		for ( int i =0; i < message.length(); i++ ){
			matrix.drawChar(x + (i * width), y, message[i], HIGH, LOW, 1);  // HIGH LOW means foreground ON, background OFF, reverse these to invert the display!
		}
		matrix.write(); // Send bitmap to display
		delay(15*wait);
	}
}
void display_message(String message){
   for ( int i = 0 ; i < width * message.length() + matrix.width() - spacer; i++ ) {
    matrix.fillScreen(LOW);
    int letter = i / width;
    int x = (matrix.width() - 1) - i % width;
    int y = (matrix.height() - 8) / 2; // center the text vertically
    while ( x + width - spacer >= 0 && letter >= 0 ) {
      if ( letter < message.length() ) {
        matrix.drawChar(x, y, message[letter], HIGH, LOW, 1); // HIGH LOW means foreground ON, background OFF, reverse these to invert the display!
      }
      letter--;
      x -= width;
    }
    matrix.write(); // Send bitmap to display
    delay(wait);
  }
}

void GetMessage() {
  webpage = "";
  append_page_header();
  String IPaddress = WiFi.localIP().toString();
  webpage += "<form action=\"http://"+IPaddress+"\" method='post'>";
  webpage += "<P>Message à envoyer : <INPUT type='text' size ='60' name='message' placeholder='Votre message'><input type='submit', value='Envoyer !'></form></P><br>";
    webpage += "<form action=\"http://"+IPaddress+"\" method='post'>";
  webpage += "<P>Luminosité : <INPUT type='text' size ='60' name='brightness' placeholder='Luminosité de 0 à 15'><input type='submit', value='Envoyer !'></form></P><br>";
  append_page_footer();
  if (server.args() > 0 ) { // Arguments were received
    for ( uint8_t i = 0; i  <= server.args(); i++ ) {
      String Argument_Name   = server.argName(i);
      String client_response = server.arg(i);
      if (Argument_Name == "message") message = client_response;
      if (Argument_Name == "brightness") brightness = client_response.toInt();
    }
  }
  server.send(200, "text/html", webpage); // Send a response to the client to enter their inputs, if needed, Enter=defaults
}

void append_page_header() {
  webpage  = F("<!DOCTYPE HTML><html lang='fr'><head>");
  webpage += "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=utf-8'>";
  webpage += F("<title>Envoi de messages - LibreMetric</title><style>");
  webpage += F("body {width:");
  webpage += SITE_WIDTH;
  webpage += F("px;margin:0 auto;font-family:arial;font-size:14px;text-align:center;color:#776688;background-color:#F7F2Fd;}");
  webpage += F("ul{list-style-type:circle; margin:0;padding:0;overflow:hidden;background-color:#d8d8d8;font-size:14px;}");
  webpage += F("li{float:left;border-right:1px solid #bbb;}last-child {border-right:none;}");
  webpage += F("li a{display: block;padding:2px 12px;text-decoration:none;}");
  webpage += F("li a:hover{background-color:#FFFFFF;}");
  webpage += F("section {font-size:16px;}");
  webpage += F("p {background-color:#D1DBE3;font-size:16px;}");
  webpage += F("div.header,div.footer{padding:0.5em;color:white;background-color:gray;clear:left;}");
  webpage += F("h1{background-color:#d8d8d8;font-size:26px;}");
  webpage += F("h2{color:#9370DB;font-size:22px;line-height:65%;}");
  webpage += F("h3{color:#9370DB;font-size:16px;line-height:55%;}");
  webpage += F("</style></head><body><h1>LibreMetric ");
  webpage += version+"</h1>";
}

void append_page_footer(){ // Saves repeating many lines of code for HTML page footers
  webpage += F("<ul><li><a href='/'>Recharger la page</a></li></ul>");
  webpage += F("</body></html>");
}
