#include <SmingCore.h>

///////////////////////////////////////////////////////////////////
// Set your SSID & Pass for initial configuration
#include "configuration.h" // application configuration
///////////////////////////////////////////////////////////////////

#include "webserver.h"
#include "tm1650.h"
#include "AHTxx.h"

Timer procTimer, procRTimer;
Timer displayTimer, tmpTimer;
Timer showHighTimer, showLowTimer;
Timer brightTimer;
// Sensors values
float SensorT, SensorH, SensorHI, SensorCR;
String StrCF;
// Time values
time_t Time, NTPLastUpdate;
DateTime dt;

void RequestData(void);
void GetData(void);
void connectOk(const String& SSID, MacAddress bssid, uint8_t channel);
void connectFail(const String& ssid, MacAddress bssid, WifiDisconnectReason reason);
void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway);

void showWatch(void);
void showTime(void);
void showTemperature(void);
void showHumidity(void);
void setBright(void);

// NTP Client
void onNtpReceive(NtpClient& client, time_t timestamp);
NtpClient ntpClient("ntp.time.in.ua", 1500, onNtpReceive); // every 15 min

AHTxx sensor;

void init(void) {
	spiffs_mount(); // Mount file system, in order to work with files

	Serial.begin(SERIAL_BAUD_RATE);  // 115200 by default
	Serial.systemDebugOutput(false); // Debug output to serial
	Serial.println("Wall Segment Clock");

	ActiveConfig = loadConfig();

	// set timezone hourly difference to UTC
	SystemClock.setTimeZone(ActiveConfig.AddTZ);

	WifiStation.config(ActiveConfig.NetworkSSID, ActiveConfig.NetworkPassword);
	WifiStation.enable(true);
	WifiAccessPoint.enable(false);

	WifiEvents.onStationConnect(connectOk);
	WifiEvents.onStationDisconnect(connectFail);
	WifiEvents.onStationGotIP(gotIP);

	// initialize I2C
	Wire.pins(4, 5);
	Wire.begin();

	// Sensors start. Possible infinity loop...
//	Serial.println("Wait for Sensor...");
//	while (sensor.IsReadyToRequest() == false);
	// polling sensors - once per two seconds
	procTimer.initializeMs(2000, RequestData).start();

	// Low LED output
	TM1650_Init();
	brightTimer.initializeMs(1000, setBright).start();

	// обновление экрана два раза в секунду
	displayTimer.initializeMs(500, showWatch).start();
}

void showWatch(void) {
	static time_t oldTime;

	Time = SystemClock.now();

	dt.setTime(Time);

	/*
	 * теперь в dt у нас следующее:
	 * 	int8_t Hour;
	 * 	int8_t Minute;
	 * 	int8_t Second;
	 * 	int16_t Milliseconds;
	 * 	int8_t Day;
	 * 	int8_t DayofWeek; -- Sunday is day 0
	 * 	int8_t Month; // Jan is month 0
	 * 	int16_t Year;  // Full Year numer
	 */

	if (oldTime == Time) {
		// Старая секунда - нужно гасить точки
		TM1650_DotRes(Dig_2);
	}	else {
		// Новая секунда
		oldTime = Time;
		TM1650_Out(dt.Hour >> 4, dt.Hour & 0xf, dt.Minute >>4, dt.Minute & 0xf);
		TM1650_DotSet(Dig_2);
	}
}

/*
 * Выводим текущее время [HH MM] на верхние индикаторы
 */
void showTime(void) {
	static uint8_t oldHour = 0xFF, oldMinute = 0xFF;

	if (oldMinute != dt.Minute) {
		oldMinute = dt.Minute;

		// ...
		
		if (oldHour != dt.Hour) {
			oldHour = dt.Hour;

			// ...
		} // new hour
	} // new minute
}

/*
 * Выводим температуру на нижние индикаторы
 */
void showTemperature(void) {
		// ...
}

/*
 * Выводим влажность на нижние индикаторы
 */
void showHumidity(void) {
		// ...
}

/*
 * Выводим дату на верхние индикаторы [DD MM]
 */
 void showDate(void) {
 		// ...
}

/*
 * Автоматическая регулировка яркости индикаторов
 * GY-49 (MAX44009)
 */
void setBright(void) {
		// ...
}

/**
 * @brief Start Sensor measure.
 */
void RequestData(void) {
	if (sensor.IsReadyToRequest()) {
		sensor.StartMeasure();
		tmpTimer.initializeMs(600, GetData).startOnce();
	} else {
		Serial.println("Sensor: not ready to request.");
	}
}

/**
 * @brief Get data from Temperature/Humidity Sensor.
 */
void GetData(void) {
	ahtxx_t data;

	sensor.GetData(&data);
	if (data.Error != St_OK) {
		Serial.println("Sensor: Data error!");
		return;
	}

	SensorH = data.Humidity / 10;
	SensorT = data.Temperature / 10;

	Serial.print("Humidity: ");
	Serial.print(SensorH);
	Serial.print("%. Temperature: ");
	Serial.print(SensorT);
	Serial.println("*C");
}

void connectOk(const String& SSID, MacAddress bssid, uint8_t channel)
{
	debugf("connected");
	WifiAccessPoint.enable(false);
}

void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway)
{
	Serial.print("Got IP address: ");
	Serial.println(ip);
	// Restart main screen output
	procTimer.restart();
	displayTimer.restart();

	// start NTP Client there?

	startWebServer();
}

void connectFail(const String& ssid, MacAddress bssid, WifiDisconnectReason reason)
{
	debugf("connection FAILED: %s", WifiEvents.getDisconnectReasonDesc(reason).c_str());
	WifiAccessPoint.config("ClockConfig", "", AUTH_OPEN);
	WifiAccessPoint.enable(true);
	// Stop main screen output
	procTimer.stop();
	displayTimer.stop();

	Serial.println("WiFi ClockConfig");
	Serial.println(WifiAccessPoint.getIP());

	startWebServer();
	WifiStation.disconnect();
	WifiStation.connect();
}

/**
 * @brief NTP Client
 */
void onNtpReceive(NtpClient& client, time_t timestamp)
{
	SystemClock.setTime(timestamp, eTZ_UTC);
	NTPLastUpdate = SystemClock.now();
	Serial.println("*** Time synchronized OK! ***"); // DEBUG
}
