/*                                          Basic Receiving
Name: Joshua Adams
Date: 4/22/24
Purpose of program:  To control whether certain functions run or not.

Requirements 
 - Global integers with the value of one 
 - Conditional if statements in he loop that 
 - Conditional statements allow the function to run if the value is 1

*/

//********libraries********
//****LEDS****
#include <Arduino.h>
#include "FastLED.h"
#include <WiFi.h>
//#include "AsyncTCP.h"
#include "time.hpp"
#include "parser.hpp"
//#include <FS.h>
//#include <LittleFS.h>
//#include <SPIFFS.h>
//#include <ESPAsyncWebServer.h>
//#include <ESPmDNS.h>
#include <WiFiAP.h>
#include <WiFiClient.h>
//#include <WebSerial.h>

//AsyncWebServer server(80);
//AsyncWebSocket ws("/ws"); // access at ws://[esp ip]/ws 
//AsyncEventSource events("/events"); // event source (Server-Sent events)   

unsigned long myTime[3];
struct
{
  long hours;
  long minutes;
  float seconds;
} currentTime;
//****LED Definitions****
  #define numleds 50
  #define ledpin 33

//****LEDS****
  CRGB leds[numleds] = {0};
  int brightness = 15;
  //int maxbrightness = 40;
  uint8_t fadeBy;
  byte red = 10;
  byte green = 10;
  byte blue = 10;



//delays
  float fadeInDelay = 3;
  float fadeOutDelay = 3;

  uint32_t f1Delay1 = 10;
  uint32_t f1Delay2 = 10;
  uint32_t f1Delay3 = 5;

//Time
  unsigned long serialReadStart;
  double timeAtLast;
  double timeSinceLast;
  double hour;
 
//HTTP Variables
  const char* http_username = "jcadams5";
  const char* http_password = ">R0$N@t3<";
  bool shouldReboot = false;  // Flag to use afer web update update that tells the program to reboot

//WiFi Station Variables
  const char* sta_ssid = "Wokwi-GUEST";
  const char* sta_password = "";

  IPAddress sta_local_ip(192,168,50,226);
  IPAddress sta_gateway(192,168,50,1);
  IPAddress sta_subnet(255,255,255,0);
  IPAddress sta_dns1(192,168,50,1);
  IPAddress sta_dns2(208,67,222,222);

//WiFi AP Variables
  const char *ap_ssid = "AP Tester";
  const char *ap_pass = "N@thaniel10!";
  IPAddress ap_local_ip(10,1,1,10);
  IPAddress ap_gateway(10,1,1,10);
  IPAddress ap_subnet(255,255,255,0);
  IPAddress ap_dhcp_lease_start(10,1,1,15); 

//DNS Variables
  const char* hostName = "LEDTester";


void initAP() {
    WiFi.enableAP(true);
    Serial.println("Initializing AP");
    WiFi.softAPConfig(ap_local_ip, ap_gateway, ap_subnet, ap_dhcp_lease_start);
  if (!WiFi.softAP(ap_ssid, ap_pass)) {
    Serial.println("Soft AP creation failed.");
    while(1);
  }
  Serial.print("AP IP address: ");
    Serial.println(ap_local_ip);
  }
void initWiFi() {
  int wifiTimeout = millis();
  WiFi.disconnect(false, true);
  WiFi.persistent(false);
  WiFi.setAutoReconnect(true);
  WiFi.setSleep(false);
  WiFi.config(sta_local_ip, sta_gateway, sta_subnet, sta_dns1, sta_dns2);
  WiFi.begin(sta_ssid, sta_password);
  delay(500);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("Connecting to WiFi");
    Serial.println("Please Wait.....");
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("WiFi IP: "+String(WiFi.localIP()));
      break;      
    }
    else if(wifiTimeout - millis() > 15000) {
      Serial.println("Unable to connect to WiFi");
      break;
      }
    }
  }

/*
void initDNS() {
   //use mdns for host name resolution
     if (!MDNS.begin(hostName)) { //http://esp32.local
       Serial.println("Error setting up MDNS responder!");
     }
     Serial.println(WiFi.localIP());
     Serial.println("URL: "+String(hostName)+".local");
      delay(2000);
     }
*/
void SetHue(int hue) {
  for(int i = 0; i < numleds; i++) { leds[i].setHue(hue);}
  FastLED.show();
 }

void SetAll(int function, byte red, byte green, byte blue) {
    for(int i = 0; i < numleds; i++) {
      leds[i].r = red;
      leds[i].g = green;
      leds[i].b = blue;
    }
    FastLED.show();
  }

void SetAll(byte red, byte green, byte blue) {
    for(int i = 0; i < numleds; i++) {
      leds[i].r = red;
      leds[i].g = green;
      leds[i].b = blue;
    }
    FastLED.show(); 
   } 

void WhiteFlameBackup(byte red, byte green, byte blue)  { 
  for(int i = 0; i < numleds; i++) {  //loop #1 Drawing one led and moving to the nexr loop
    leds[i].r = 1;
    leds[i].g = 1;
    leds[i].b = 1;
  for(int j = 0; j <= i; j++)  //Loop through only what the main loop has drawn so not to draw past the fade. Adds one pixel per cycle
    leds[j].CRGB::addToRGB(2);  //Adding one per cycle along with additional brightness to each pixel previously drawn appears to fade in
    FastLED.show();
    delay(f1Delay1);
  }
  while(leds->getLuma() > 0) {  //  loop #3
    for(int k = 0; k <= numleds - 1; k++) 
        leds[k].CRGB::subtractFromRGB(2); // loop #4 Causes the fade out due to he 3 getting higher on each iteration, for at he end it's almost faded all ou5
        FastLED.show();
        delay(f1Delay2);      
    }  
  }

void WhiteFlame(byte red, byte green, byte blue)  { 
  for(int i = 0; i < numleds; i++) {  //loop #1 Drawing one led and moving to the nexr loop
      leds[i].r = leds[i].r;
      leds[i].g = leds[i].g;
      leds[i].b = leds[i].b;
    for(int j = 0; j < numleds; j++)  //loop #2 assigning brightness 0 to j and iterating to 50
      leds[j].CRGB::addToRGB(2)+leds[j+1].CRGB::addToRGB(1);  // Due to drawing one led and raising the brightness by 3 each step it appears to fade in
      FastLED.show();
      delay(f1Delay1);
    }
    //Serial.println("Light: "+String(leds->getLuma()));
    //while(leds->getLuma() > 0) {  //  loop #3
    //  for(int k = 0; k <= numleds - 1; k++) 
    //      leds[k].CRGB::subtractFromRGB(2); // loop #4 Causes the fade out due to he 3 getting higher on each iteration, for at he end it's almost faded all ou5
    //      FastLED.show();
    //      delay(f1Delay2);      
    //}
      for(int k = 0; k <= numleds; k++) {
        leds[k].r = leds[k].r;
        leds[k].g = leds[k].g;
        leds[k].b = leds[k].b;
        for(int l = 0; l <= numleds; l++) {
          leds[l].CRGB::subtractFromRGB(3)+leds[l+1].CRGB::subtractFromRGB(1);
        }
        FastLED.show();
        delay(f1Delay2);
      }
    }

void setup() {
  //Serial.setTimeout(3000);
    Serial.begin(115200);
    delay(500);
    Serial.println("Starting Serial Communications");
    ulong quitter = Serial.getTimeout();
    Serial.println("Serial Timeout is: "+String(quitter));
    Serial.println("Setting up defined pins");
  //****LEDS****
    pinMode(ledpin, OUTPUT);
   // pinMode(LED_BUILTIN, OUTPUT);
    delay(100);
    Serial.println("Setting up LED Constructor");
    //****LED_CONSTRUCTOR****
    FastLED.addLeds<WS2812B, ledpin, GRB>(leds, numleds);
    FastLED.setBrightness(brightness);
    Serial.println("Setting up Power Limits");
    //****LED_POWERLIMITER**** 
    //set_max_power_indicator_LED(LED_BUILTIN);
    FastLED.setMaxPowerInMilliWatts(900);
    Serial.println("Clearing LED's.");
    FastLED.clear();
    FastLED.show();
    //WiFi STA/SP, DNS, SPIFFS, WebSerial
    WiFi.mode(WIFI_MODE_APSTA);
    initWiFi();
    initAP();
    //initDNS();
    //InitSPIFFS();
    //WebSerial.begin(&server);
    //WebSerial.msgCallback(recvMsg);
    //WebSocket, WebServer
    //ws.onEvent(onEvent);
    //server.addHandler(&ws);
    //server.addHandler(&events);
    //server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    //  request->send(SPIFFS, "/index.html", "text/html");
    //  });
    // send a file when /index is requested
    //server.on("/index", HTTP_ANY, [](AsyncWebServerRequest* request) {
	  //request->send(SPIFFS, "/index.htmL");
	  //});
    // HTTP basic authentication
    //server.on("/login", HTTP_GET, [](AsyncWebServerRequest* request) {
	  //if (!request->authenticate(http_username, http_password))
		//return request->requestAuthentication();
	  //request->send(200, "text/plain", "Login Success!");
	  //});
    // Simple Firmware Update Form
    //server.on("/update", HTTP_GET, [](AsyncWebServerRequest* request) {
	  //request->send(200, "text/html", "");
	  //});
    //    
    //server.onNotFound(onRequest);
    //server.onFileUpload(onUpload);
    //server.onRequestBody(onBody);
    //server.begin();

    timeAtLast = 0;
    currentTime.seconds;
    currentTime.minutes;
    currentTime.hours;
  }
  

void loop() { 
  int rightNow;

   GetTime(currentTime.hours, currentTime.minutes, currentTime.seconds);

    //  Take currentTime.hours, currentTime.minutes, currentTime.seconds
    //  cast them to chars. append them all to rightNow in the correct order

  //if(int(rightNow) - int(5) >= timeAtLast) { 
  //  
  //  //ShowTime(seconds,minutes,hours);
  //  timeAtLast = rightNow;
  //}
 

  if(Serial.available() > 0) {
    primaryFunction == 0;
    Serial.println("Strip1 off, parsing incoming serial communication!");
    //timeAtLast = rightNow;
    readingSerial = true;
    ReadSerial();
  }
  
  if(primaryFunction == 0) {
    //TimeSince(hours,minutes,seconds);
      if(rightNow - timeAtLast >= int(5) && readingSerial == false) {
        primaryFunction == 1;
      }
  }
  else if(primaryFunction == 1) {
    //WhiteFlame(red, green, blue);
    WhiteFlameBackup(red, green, blue);

  }

  if(secondaryFunction == 1) {
  }

  if(tertiaryFunction == 1) {
      
    }
    delay(10);
  }