const char* otaServerIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
String printDigits(int digits)
{
  String f=String(digits);
  if (digits < 10) return ("0"+f); else return f;
}
  
 String genPlot(int *plot_input){
  int max_value = -32000;
  int min_value = 32000;
  String data;
  String circleData;
//   int point;
  
  for (byte i = 0; i < 15; i++) {
    max_value = max(plot_input , max_value);
    min_value = min(plot_input , min_value);
  }
  if (min_value >= max_value) max_value = min_value + 1;
    
  circleData = " ";
  data += R"rawliteral( 
  <div class="float">
  <svg viewBox="0 0 460 140" class="chart">
  <line x1="1" x2="500" y1="125" y2="125"  style="stroke:#ccc;stroke-width:1"></line>
  <line x1="35" x2="35" y1="1" y2="140" style="stroke:#ccc;stroke-width:1" ></line>
  )rawliteral";
  data += "<g class=\"labels x-labels\"><text x=\"1\" y=\"10\">" + String(max_value) + "</text>\n<text x=\"1\" y=\"123\">" + String(min_value) + "</text></g>\n";
  
  data += "<polyline fill=\"none\" stroke=\"#0074d9\" stroke-width=\"3\" points=\"";
  
  for (byte i = 0; i < 15; i++) {
    data += " " + String(i*31+35) + "," + String(125-map(plot_input, min_value, max_value, 0, 120)) + " ";
    circleData += "<circle cx=\"" + String(i*31+35) + "\" cy=\"" + String(125-map(plot_input, min_value, max_value, 0, 120)) + "\" data-value=\"" + String(plot_input) + "\" r=\"4\"><title>" + String(plot_input) + "</title></circle>\n";
  }
  data += "\"/>\n<g class=\"plotData\"> \n" + circleData + " </g>\n</svg></div>\n";
  return data;
}
// function to calculete Humidex
float calculate_humidex(float temperature, float humidity) {
  float e;
  e = (6.112 * pow(10, (7.5 * temperature / (237.7 + temperature))) * humidity / 100); //vapor pressure
  float humidex = temperature + 0.55555555 * (e - 10.0); //humidex
  return humidex;
}
void HandleClient() {
  unsigned long webpageLoad = millis();
  char daysOfTheWeek[9][12] = {"   Sunday", "   Monday", "  Tuesday", "Wednesday", " Thursday", "   Friday", " Saturday"};
  DateTime now = rtc.now();
  String webpage;
  webpage =  "<html>\n<head><title>"+hostName+"</title><meta charset='UTF-8' http-equiv='refresh' content='60' >\n";
  webpage += R"rawliteral(   <style>
        body {font-family: Sans; Color: #00979d;}
        h2 {line-height: 10%;}
        p {line-height: 20%;}
        .chart { height: 140px; width: 500; }
        .chart .grid { stroke: #ccc; stroke-dasharray: 0; stroke-width: 2;}
        .labels { font-size: 13px;}
        .chart .plotData { fill: red; stroke-width: 1;}
        .float { float: left;}
        .floatclear { clear: both;}
    </style>
    </head>
    <body>)rawliteral";
  webpage += "<p><br><b>   " + hostName + " </b></p><br>\n";
  
  webpage += "<div class=\"floatclear\"></div><br><p>  температура </p>\n";
  webpage += "<h2><br>    " + String(dispTemp) + " °C</h2>\n";
  webpage += "<p>   чувствуется как:</p>\n";
  webpage += "<h2><br>    " + String(calculate_humidex(dispTemp,dispHum)) + " °C</h2>\n"; 
  webpage += genPlot((int*)tempHour);
  webpage += genPlot((int*)tempDay);  
  
#if (EXT_SENS == 1)
  webpage += "<div class=\"floatclear\"></div><br><p>  внешняя температура </p>\n";
  webpage += "<h2><br>    ";
  
  if(extSensorStatus == 200) webpage += String(dispExtTemp) + " °C</h2>\n";
  else  webpage += "-Sensor Error-</h2>\n";
  webpage += "<p>   чувствуется как:</p>\n";
  webpage += "<h2><br>    " + String(calculate_humidex(dispExtTemp,dispExtHum)) + " °C</h2>\n"; 
  webpage += genPlot((int*)tempExtHour);
  webpage += genPlot((int*)tempExtDay);  
#endif
  webpage += "<div class=\"floatclear\"></div><br><p>  влажность </p>\n";
  webpage += "<h2><br>    " + String(dispHum) + " %  </h2>\n";
      
  webpage += genPlot((int*)humHour);
  webpage += genPlot((int*)humDay);  
  
#if (EXT_SENS == 1)
  webpage += "<div class=\"floatclear\"></div><br><p> внешняя влажность </p>\n";
  webpage += "<h2><br>    " + String(dispExtHum) + " %  </h2>\n";
#endif
  
  webpage += "<div class=\"floatclear\"></div><br><p>  атмосферное давление </p>\n";
  webpage += "<h2><br>    " + String(dispPres) + " hPa</h2>\n";
      
  webpage += genPlot((int*)pressHour);
  webpage += genPlot((int*)pressDay); 
  
  webpage += "<div class=\"floatclear\"></div><br><p>  вероятность осадков </p>\n";
  webpage += "<h2><br>    " + String(dispRain) + " %</h2><br>\n";
  webpage += "<p>  содержание CO2 </p>\n";
  webpage += "<h2><br>    " + String(dispCO2) + " ppm</h2>\n";
  
  for (byte i = 0; i < 15; i++) {                                          //cleaning zero values from empty cells and
    if((co2Hour<CO2_MIN) && (dispCO2>=CO2_MIN)) co2Hour = dispCO2;   //filter out cold sensor readings
    if((co2Day<CO2_MIN) && (dispCO2>=CO2_MIN)) co2Day = dispCO2;
  }
  webpage += genPlot((int*)co2Hour);
  webpage += genPlot((int*)co2Day); 
  
  webpage += "<div class=\"floatclear\"></div>\n<p><br>     RTC:" + printDigits(now.hour()) + ":" + printDigits(now.minute()) + ":"  + printDigits(now.second()) + "   " + daysOfTheWeek[now.dayOfTheWeek()];
  webpage += "  " + printDigits(now.day()) + "/" + printDigits(now.month()) + "/"  + String(now.year()) + "</p>  \n";
  webpage += "<p>     NTP:" + printDigits(hour()) + ":" + printDigits(minute()) + ":"  + printDigits(second()) + "                \n";
  webpage += "  " + printDigits(day()) + "/" + printDigits(month()) + "/"  + String(year()) + "</p>  \n";
  webpage += "<p>    Uptime: "+Uptime()+", WiFi signal: "+ String( WiFi.RSSI()) + "dBm, </p><p>    Battery: "+String(batteryVoltCalc()/100)+"V ("+analogRead(BATTERY)+"), Page generation: "+String(millis()-webpageLoad)+"msec</p><br><br>\n";
  webpage += "<p>   \n<a href='http://"+String(myIP)+"/set_WI_FI'>НАСТРОЙКИ</a></p>  <p>\n";
  webpage += "</body>\n";
  webpage += "</html>\n";
  server.send(200, "text/html", webpage);
}
void handleRoot() {
  String webpage;
  webpage =  "<html>"; 
  webpage += "<head><title> Setup </title><meta charset='UTF-8'>";
  webpage += "<style>";
  webpage += "body { font-family: Verdana; Color: #00979d;}";
  webpage += "</style>";
  webpage += "</head>";
  webpage += "<body>";
  String str = "";
  str += webpage;
  str += "<boy>\
   <form method=\"POST\" action=\"ok\">\
     <input type=\"radio\" value=\"1\" name=\"otaflag\"> Загрузить новую прошивку (после перезагрузки зайдите на страницу устройства и запустите процедуру)</br></br>\
     <input type=\"text\" value=\"" + ssid + "\" name=\"ssid\" maxlength=32> WiFi SSID</br></br>\  
     <input type=\"password\" value=\"" + pass + "\" name=\"pswd\" maxlength=64> PASSWORD</br></br>\
     <input type=\"text\" value=\"" + TIMEZONE + "\" name=\"tzn\" maxlength=3> TIMEZONE</br></br>\
     <input type=\"text\" value=\"" + mqtt_ip + "\" name=\"mqtt_ip\" maxlength=15> MQTT IP</br></br>\
     <input type=\"text\" value=\"" + mqtt_port + "\" name=\"mqtt_port\" maxlength=5> MQTT PORT</br></br>\
     <input type=\"text\" value=\"" + mqtt_auth + "\" name=\"mqtt_auth\" maxlength=32> MQTT USER</br></br>\
     <input type=\"password\" value=\"" + mqtt_pass + "\" name=\"mqtt_pass\" maxlength=32> MQTT PWD</br></br>\
     <input type=\"text\" value=\"" + mqtt_Temp + "\" name=\"mqtt_temp\" maxlength=64> MQTT Topic (temperature)</br></br>\
     <input type=\"text\" value=\"" + mqtt_Hum + "\" name=\"mqtt_hum\" maxlength=64> MQTT Topic (humidity)</br></br>\
     <input type=\"text\" value=\"" + mqtt_Press + "\" name=\"mqtt_press\" maxlength=64> MQTT Topic (pressure)</br></br>\
     <input type=\"text\" value=\"" + mqtt_CO2 + "\" name=\"mqtt_co2\" maxlength=64> MQTT Topic (CO2)</br></br>\
     <input type=SUBMIT value=\"Save\">\
   </form>\
 </body>\
</html>";
  server.send ( 200, "text/html", str );
} 
void handleOk(){
  String webpage;
  webpage =  "<html>";
  webpage += "<head><title>settings save </title><meta charset='UTF-8'>";
  webpage += "<style>";
  webpage += "body { font-family: Verdana; Color: #00979d;}";
  webpage += "</style>";
  webpage += "</head>"; 
  webpage += "<body>";
  String ssid_ap       = server.arg("ssid");
  String pass_ap       = server.arg("pswd");
  String TZN_ap        = server.arg("tzn");
  String mqtt_ip_ap    = server.arg("mqtt_ip");
  String mqtt_port_ap  = server.arg("mqtt_port");
  String mqtt_auth_ap  = server.arg("mqtt_auth");
  String mqtt_pass_ap  = server.arg("mqtt_pass");
  String mqtt_temp_ap  = server.arg("mqtt_temp");
  String mqtt_hum_ap   = server.arg("mqtt_hum");
  String mqtt_press_ap = server.arg("mqtt_press");
  String mqtt_CO2_ap   = server.arg("mqtt_co2");
  String otaFlag_ap    = server.arg("otaflag");
  int tz;
  String str = "";
 
  str += webpage;
  str += "<body>";
  tz = TZN_ap.toInt();
  (otaFlag_ap == "0") ? otaFlag = 0 : otaFlag = 1;
  
  if( (tz > -12) && (tz < 12) ) TIMEZONE = tz;
  mqtt_ip    = mqtt_ip_ap;
  mqtt_port  = mqtt_port_ap;
  
  mqtt_auth_ap.replace("%2F","/");
  mqtt_auth  = mqtt_auth_ap;
  
  mqtt_pass_ap.replace("%2F","/");
  mqtt_pass  = mqtt_pass_ap;
  
  mqtt_temp_ap.replace("%2F","/");
  mqtt_Temp  = mqtt_temp_ap;
  
  mqtt_hum_ap.replace("%2F","/");
  mqtt_Hum   = mqtt_hum_ap;
  
  mqtt_press_ap.replace("%2F","/");
  mqtt_Press = mqtt_press_ap;
  
  mqtt_CO2_ap.replace("%2F","/");
  mqtt_CO2   = mqtt_CO2_ap;
  ssid_ap.replace("%2F","/");
  pass_ap.replace("%2F","/");
  str +="Configuration saved in FS</br>\   
  <a href=\"/\">Return</a> to settings page</br>";
  str += "</body></html>";
  server.send ( 200, "text/html", str );
  
  saveConfig();
  if( (ssid_ap != String(ssid)) || (pass_ap != String(pass)) ){
      ssid = ssid_ap;
      pass = pass_ap;
      saveConfig();
      delay(1000);
      ESP.restart();
      delay(100);
  }
  if( otaFlag ) {
    lcd.clear();
    lcd.print("Rebooting...");
    delay(1000);
    ESP.restart();
    delay(100);
  }
}
void handleOTA() {
  Serial.println("Starting OTA mode.");    
  Serial.printf("Sketch size: %u\n", ESP.getSketchSize());
  Serial.printf("Free size: %u\n", ESP.getFreeSketchSpace());
  MDNS.begin(host);
  server.on("/", HTTP_GET, [](){
    server.sendHeader("Connection", "close");
    server.sendHeader("Access-Control-Allow-Origin", "*");
    server.send(200, "text/html", otaServerIndex);
  });
  server.on("/update", HTTP_POST, [](){
    server.sendHeader("Connection", "close");
    server.sendHeader("Access-Control-Allow-Origin", "*");
    server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK");
    setOtaFlag(0); 
    lcd.clear();
    delay(100);
    ESP.restart();
  },[](){
    HTTPUpload& upload = server.upload();
    if(upload.status == UPLOAD_FILE_START){
      //Serial.setDebugOutput(true);
      WiFiUDP::stopAll();
      Serial.printf("Update: %s\n", upload.filename.c_str());
      otaCount=300;
      uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
      if(!Update.begin(maxSketchSpace)){//start with max available size
        Update.printError(Serial);
      }
    } else if(upload.status == UPLOAD_FILE_WRITE){
      if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
        Update.printError(Serial);
      }
    } else if(upload.status == UPLOAD_FILE_END){
      if(Update.end(true)){ //true to set the size to the current progress
        Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
      } else {
        Update.printError(Serial);
      }
      Serial.setDebugOutput(false);
    }
    yield();
  });
  server.begin();
  Serial.printf("Ready! Open http://%s.local in your browser\n", host);
  MDNS.addService("http", "tcp", 80);
  otaTickLoop.attach(1, otaCountown);
}