/*
 * Firmware for SweProj Gotek
 *
 * 2023 - Per Mårtensson (pm@sweproj.com)
 *
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <Arduino.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "config.h"
#include <WiFi.h>
#include <WiFiManager.h>
#include "Version.h"
#include "ESPWebDAV.h"
//#include "ESPFtpServer.h"
#include "WebOTA.h"
#include <SPI.h>
#include <NTPClient.h>
#include <ESP32Time.h>
#include <Wire.h>
#include <WireSlave.h>
#include <osd.h>
#include <ntp.h>
#include <task.h>
#include <timers.h>
#include <ESPFtpServer.h>

#define HOSTNAME "SweFlops"

static const char TAG[] = __FILE__;

// WebDAV server
#define IDLE_TASK_SIZE 1000
ESPWebDAV dav;
String statusMessage;
bool initFailed = false;
bool nrst_state=false;
WiFiUDP ntpUDP;
bool masterboot=true;
NTPClient timeClient(ntpUDP,"pool.ntp.org", 60, 60000);
// FTP server
FtpServer ftpSrv;
ESP32Time rtc(0);
// BOOT button
void handleBootButton(void);
SPISettings spiSettings;
// Wifi
WiFiManager wifiManager;
t_osd_info  osd_info;
//Timer
TimerHandle_t xNTPTimer = NULL;
BaseType_t xNTPTimerStarted;
#ifdef GOTEK_SDFAT2
SdCardFactory cardFactory;
#endif
const char fw_ver[] = FW_VER;
TaskHandle_t OSD_Task = NULL;
gotek::osd gotek_osd;
bool isSDInit = false;
struct osd_display_t osd_display;
struct Button {
    const uint8_t PIN;
    bool pressed;
	unsigned long button_time;
	unsigned long last_button_time;
};
Button button1 = {GOTEK_BUTTON_RIGHT, false,NULL,NULL};
Button button2 = {GOTEK_BUTTON_LEFT,  false,NULL,NULL};
void IRAM_ATTR button1_isr() {
    button1.button_time = millis();
	if (button1.button_time - button1.last_button_time > 250)
	{
		button1.pressed = true;
		button1.last_button_time = button1.button_time;
	}
}
void IRAM_ATTR button2_isr() {
    button2.button_time = millis();
	if (button2.button_time - button2.last_button_time > 250)
	{
		button2.pressed = true;
		button2.last_button_time = button2.button_time;
	}
}
void handleLED(void);
void IRAM_ATTR NTP_Timer_Handler(TimerHandle_t pxTimer){
	if (timeClient.update()){
		rtc.setTime(timeClient.getEpochTime());
		ESP_LOGI(TAG, "");
		ESP_LOGI(TAG, "--------------------------------");
		ESP_LOGI(TAG, "NTP update %s",rtc.getDateTime().c_str());
		ESP_LOGI(TAG, "--------------------------------");

	}

	
}

void setup()
{
	char *p;

	osd_info.protocol_ver = 0;
	osd_info.fw_major = 0;//strtol(fw_ver, &p, 10);
	osd_info.fw_minor = 0;//strtol(p + 1, NULL, 10);
	osd_info.buttons = 0;
	osd_info.buttons2 = 0;
	esp_log_level_set("*", ESP_LOG_INFO);

	pinMode(GOTEK_LED_GREEN, OUTPUT);
	pinMode(GOTEK_LED_BLUE, OUTPUT);
	pinMode(GOTEK_LED_ORANGE, OUTPUT);
	digitalWrite(GOTEK_LED_GREEN, LOW);
	digitalWrite(GOTEK_LED_BLUE, LOW);
	digitalWrite(GOTEK_LED_ORANGE, LOW);

	pinMode(GOTEK_STM_POWER,OUTPUT);
	pinMode(GOTEK_SD_SEL,OUTPUT);
	pinMode(GOTEK_STM_RST,OUTPUT_OPEN_DRAIN);
	digitalWrite(GOTEK_SD_SEL    ,LOW);	
	digitalWrite(GOTEK_STM_POWER  ,HIGH);
	digitalWrite(GOTEK_STM_RST    ,HIGH);

	
	GOTEK_LOGGING_SERIAL_PORT.begin(GOTEK_SERIAL_BAUD_RATE);
	GOTEK_LOGGING_SERIAL_PORT.setDebugOutput(GOTEK_DEBUG);


	ESP_LOGI(TAG, "");
	ESP_LOGI(TAG, "");
	ESP_LOGI(TAG, "**********************************************");
	ESP_LOGI(TAG, GOTEK_FULL_NAME);
	ESP_LOGI(TAG, "Version %s", GOTEK_VERSION);
	ESP_LOGI(TAG, "**********************************************");

	// Start WiFi
	ESP_LOGI(TAG, "");
	ESP_LOGI(TAG, "--------------------------------");
	ESP_LOGI(TAG, "Connect to WiFi");
	ESP_LOGI(TAG, "--------------------------------");

	WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP

	bool res = wifiManager.autoConnect(HOSTNAME);

	if (!res)
	{
		ESP_LOGI(TAG, "Running config portal");
		// ESP.restart();
	}
	else
	{
		// if you get here you have connected to the WiFi
		ESP_LOGI(TAG, "Connected");
	}

	// Init OTA firmware updater
	ESP_LOGI(TAG, "");
	ESP_LOGI(TAG, "--------------------------------");
	ESP_LOGI(TAG, "Start firmware update server");
	ESP_LOGI(TAG, "--------------------------------");
	webota.init_wifi(HOSTNAME);
	webota.init(WEB_SERVER_PORT, "/webota");
	
	// Start the WebDAV server
	ESP_LOGI(TAG, "");
	ESP_LOGI(TAG, "--------------------------------");
	ESP_LOGI(TAG, "Start WebDAV server");
	ESP_LOGI(TAG, "--------------------------------");
	if (!dav.init(WEBDAV_SERVER_PORT))
	{
		statusMessage = "An error occured while initialization of WebDAV server";
		ESP_LOGE(TAG, "ERROR: %s", statusMessage);
		initFailed = true;
	}
	ESP_LOGI(TAG, "WebDAV server started");

	// Start FTP server
	ESP_LOGI(TAG, "");
	ESP_LOGI(TAG, "--------------------------------");
	ESP_LOGI(TAG, "Start FTP server");
	ESP_LOGI(TAG, "--------------------------------");
	ftpSrv.begin("gotek", "gotek", GOTEK_SD_CS, spiSettings); 
	ESP_LOGI(TAG, "FTP server started");

	timeClient.setUpdateInterval(NTP_Update_Interval);

	xNTPTimer = xTimerCreate(
		"NtpTimer",
		pdMS_TO_TICKS(60 * 1000),
		pdTRUE,
		(void *)0,
		&NTP_Timer_Handler );

	if (xNTPTimer!= NULL){	
		xNTPTimerStarted = xTimerStart( xNTPTimer , portMAX_DELAY );
		if (xNTPTimerStarted==pdPASS){
			//vTaskStartScheduler();	
		}
	}
	
	// Setup FLASH button and LED
	pinMode(GOTEK_BUTTON_IO_0, INPUT_PULLUP);
	pinMode(GOTEK_BUTTON_RIGHT, INPUT);
	pinMode(GOTEK_BUTTON_LEFT, INPUT);
	attachInterrupt(button1.PIN, button1_isr, FALLING);
	attachInterrupt(button2.PIN, button2_isr, FALLING);

	digitalWrite(GOTEK_LED_GREEN, HIGH);

}

void loop()
{

	if (dav.isClientWaiting())
	{
		ESP_LOGI(TAG, "Client connected");
		if (initFailed)
			return dav.rejectClient(statusMessage);

		// call handle if server was initialized properly

		dav.initSD(GOTEK_SD_CS, spiSettings);
		dav.handleClient();
	}
	
	// FTP
	ftpSrv.handleFTP(); // make sure in loop you call handleFTP()!!

	// Web OTA update
	webota.handle();

	// Handle WiFi Manager
	wifiManager.process();
	//handleLED();
	handleBootButton();
	
	if (button1.pressed) {
        ESP_LOGD(TAG,"%s","Button1 has been pressed times\n");
		//osd_info.buttons |= K_RIGHT; 
        button1.pressed = false;
    }
	if (button2.pressed) {
        ESP_LOGD(TAG,"%s","Button2 has been pressed times\n");
		//osd_info.buttons |= K_LEFT; 
        button2.pressed = false;
    }

}

// The flash button is used to reset the WiFi settings
void handleBootButton(void)
{
	if (digitalRead(GOTEK_BUTTON_IO_0) == 0)
	{
		delay(50); // Debounce

		if (digitalRead(GOTEK_BUTTON_IO_0) == 0)
		{
			ESP_LOGI(TAG, "BOOT button pressed");

			delay(5000); // Wait 5 seconds

			if (digitalRead(GOTEK_BUTTON_IO_0) == 0)
			{
				ESP_LOGI(TAG, "BOOT button pressed for 5 seconds ");

				// Let the LED 5 seconds blinking
				for (int i = 0; i < 25; i++)
				{
					digitalWrite(GOTEK_LED_GREEN, LOW);
					delay(200);
					digitalWrite(GOTEK_LED_GREEN, HIGH);
					delay(200);
				}

				ESP_LOGI(TAG, "Reset WiFi settings");
				wifiManager.resetSettings();

				ESP_LOGI(TAG, "Restarting ...");
				ESP.restart();
			}
		}
	}
}


