#include <Wire.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include "ESPAsyncWebServer.h"
#include <iostream>     // std::cout
#include <sstream>      // std::istringstream
#include <string>       // std::string
#include <DS3231.h>
#include <Stepper.h>
#include <string>
#include <iostream>



#define motorA1 14
#define motorA2 12
#define motorA3 13
#define motorA4 15
#define buttonPin 18
#define clockT 4
#define clockD 23
#define svetlo 27
#define voda 1
#define cerpadlo 2

RTClib datumCas;
//AccelStepper stepper1(AccelStepper::DRIVER, motorA1, motorA2);
Stepper stepper1(200, motorA1, motorA2);
Stepper stepper2(200, motorA3, motorA4)
//WiFiServer server(80);
AsyncWebServer server(80);
//WiFiServer server(80);
//int cas[];
int otevritV[3];
int zavritV[3];
int tlacitkoVratek = LOW;
int zarovkaONOFF = LOW;
bool poziceVratek = false;
bool svetloNaWeb = false;
bool vodniSenzor = false;

std::string name;

String pole[5] = {};

String my;

//0-nic;1-otevrit;2-zavrit
int vratka = 0;
int zarovka = 0;
const char * html = "<p>vratka</p>"
"<div id=poziceVratekID>\n"
"\t<p>%pozicevratekNaWeb%</p>\n"
"</div>"
"<p>svetlo</p>"
"<div id = svetloNaWebID>\n"
"\t<p>%SvetloNaWeb%</p>\n"
"</div>"

"<div id = datumAkce>\n"
"\t<p>%Listdatumu%</p>\n"
"\t<p>%Listdatumuvyp%</p>\n"
"</div>"

;

//int datumlistu[3];
int otevritVdat[4];
//int zavritVdat[4];

class Zwebu
{
public:
	String datumspusteni;
	String hodinaspusteni;
	String minutaspusteni;
	String davkazrni;
	String voda;

public:
	String toString() const
	{
		return this->datumspusteni + this->hodinaspusteni + this->minutaspusteni + this->davkazrni + this->voda;
	}
};
const int pom = 10;
Zwebu zwebudata[pom];

class Zwebuvyp
{
public:
	String datumvypnuti;
	String hodinavypnuti;
	String minutavypnuti;

public:
	String toString() const
	{
		return this->datumvypnuti + this->hodinavypnuti + this->minutavypnuti;
	}
};

Zwebuvyp zwebudatavyp[pom];

String processor(const String& var)
{
	Serial.println(var);

	if (var == "pozicevratekNaWeb") {
		return String(poziceVratek);
	}
	if (var == "Listdatumu")
	{
		/*for (int i = 0; i < 4; i++)
		{*/
		String sloucenepolezap;
		for (int i = 0; i < 5; i++)
		{
			sloucenepolezap += String("<p class=\"datumsp\">" + zwebudata[i].datumspusteni + "</p>" + "<p class=\"hodinasp\">" + zwebudata[i].hodinaspusteni + "</p>" + "<p class=\"minutasp\">" + zwebudata[i].minutaspusteni + "</p>" + "<p>davka zrni</p>" + "<p class=\"zrnisp\">" + zwebudata[i].davkazrni + "</p>" + "<p>spusteni vody(ano/ne)</p>" + "<p class=\"vodasp\">" + zwebudata[i].voda + "</p>");

		}
		return sloucenepolezap;

		/*}*/
	}

	if (var == "Listdatumuvyp")
	{
		/*for (int i = 0; i < 4; i++)
		{*/

		String sloucenepolevyp;
		for (int i = 0; i < 5; i++)
		{
			sloucenepolevyp += String("<p class=\"datumvyp\">" + zwebudatavyp[i].datumvypnuti + "</p>" + "<p class=\"hodinavyp\">" + zwebudatavyp[i].hodinavypnuti + "</p>" + "<p class=\"minutavyp\">" + zwebudatavyp[i].minutavypnuti + "</p>");

		}
		return sloucenepolevyp;

		/*}*/
	}
	if (var == "SvetloNaWeb")
	{
		return String(svetloNaWeb);
	}
	else if (var == "PLACEHOLDER_HUMIDITY") {
		return String(vratka);
	}
	return String();
}

void setup()
{
	//WiFiMulti WiFiMulti;
	Serial.begin(115200);
	delay(10);
	WiFi.mode(WIFI_STA);
	WiFi.disconnect();
	delay(500);

	// We start by connecting to a WiFi network
	WiFi.begin("minitp", "kyberna2016");

	Wire.begin(clockD, clockT);
	stepper1.setSpeed(2000);

	Serial.println();
	Serial.println();
	Serial.print("Waiting for WiFi... ");

	while (WiFi.status() != WL_CONNECTED) {
		Serial.print(".");
		delay(500);
	}

	Serial.println("");
	Serial.println("WiFi connected");
	Serial.println("IP address: ");
	Serial.println(WiFi.localIP());

	delay(500);

	//stepper1.setMaxSpeed(2000);

	pinMode(buttonPin, INPUT);
	pinMode(svetlo, OUTPUT);
	pinMode(voda, INPUT);
	pinMode(cerpadlo, OUTPUT);

	//PinModeZarovka(svetlo, INPUT);
	//Serial.begin(9600);
	delay(10);

	server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {

		int paramsNr = request->params();
		Serial.println(paramsNr);

		for (int i = 0; i < paramsNr; i++) {

			AsyncWebParameter* p = request->getParam(i);
			Serial.print("Param name: ");
			Serial.println(p->name());
			Serial.print("Param value: ");
			Serial.println(p->value());
			Serial.println("------");

			if (p->name() == "vratkaONOFF")
			{
				//Serial.print("jetotady");
				Serial.print(p->value().toInt());
				switch (p->value().toInt())
				{
				case 1:
					vratka = 1;
					//Serial.print("jedeto");
					poziceVratek = false;
					break;
				case 2:
					vratka = 2;
					//Serial.print("nejede to");
					poziceVratek = true;
					break;
				default:
					break;
				}
			}Serial.print(vratka);

			if (p->name() == "svetloONOFF")
			{
				//Serial.print("jetotady");
				Serial.print(p->value().toInt());
				switch (p->value().toInt())
				{
				case 1:
					zarovka = 1;
					Serial.print("jedeto");
					svetloNaWeb = true;
					break;
				case 2:
					zarovka = 2;
					Serial.print("nejede to");
					svetloNaWeb = false;
					break;
				default:
					break;
				}
			}Serial.print(zarovka);
			if (p->name() == "DatumSpusteni")
			{
				for (int i = 0; i < paramsNr; i++) {
					AsyncWebParameter* p = request->getParam(i);
					if (p->name() == "DatumSpusteni")
					{
						while (!zwebudata[i].datumspusteni.isEmpty()) {
							i++;
						}
						zwebudata[i].datumspusteni = p->value();
						Serial.println("pomocnahodinavelsu");
						Serial.println(i);
					}
				}
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);
					if (p->name() == "hodina")
					{
						while (!zwebudata[i - 2].hodinaspusteni.isEmpty()) {
							i++;
						}
						zwebudata[i - 2].hodinaspusteni = p->value();
						Serial.println("pomocnahodinhodiny");
						Serial.println(i - 2);
					}
				}
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);
					if (p->name() == "minuta")
					{
						while (!zwebudata[i - 3].minutaspusteni.isEmpty()) {
							i++;
						}
						zwebudata[i - 3].minutaspusteni = p->value();
						Serial.println("pomocnahodinavminuty");
						Serial.println(i - 3);
					}
				}
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);
					if (p->name() == "zrni")
					{
						while (!zwebudata[i - 4].davkazrni.isEmpty()) {
							i++;
						}
						zwebudata[i - 4].davkazrni = p->value();
						Serial.println("pomocnahodinavminuty");
						Serial.println(i - 4);
					}
				}
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);
					if (p->name() == "voda")
					{
						while (!zwebudata[i - 5].voda.isEmpty()) {
							i++;
						}
						zwebudata[i - 5].voda = p->value();
						Serial.println("pomocnahodinavminuty");
						Serial.println(i - 5);
					}
				}
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);
					if (p->name() == "zrni")
					{
						while (!zwebudata[i - 6].zrni.isEmpty()) {
							i++;
						}
						zwebudata[i - 6].zrni = p->value();
						Serial.println("pomocnahodinavminuty");
						Serial.println(i - 6);
					}
				}
				otevritV[3] = 00;
			}

			if (p->name() == "DatumVypnuti")
			{
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);

					if (p->name() == "DatumVypnuti")
					{
						while (!zwebudatavyp[i].datumvypnuti.isEmpty()) {
							i++;
						}
						zwebudatavyp[i].datumvypnuti = p->value();
						Serial.println("pomocnahodinavelsu");
						Serial.println(i);
					}
				}
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);
					if (p->name() == "hodina")
					{
						while (!zwebudatavyp[i - 2].hodinavypnuti.isEmpty()) {
							i++;
						}
						zwebudatavyp[i - 2].hodinavypnuti = p->value();
						Serial.println("pomocnahodinhodiny");
						Serial.println(i - 2);
					}
				}
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);
					if (p->name() == "minuta")
					{
						while (!zwebudatavyp[i - 3].minutavypnuti.isEmpty()) {
							i++;
						}
						zwebudatavyp[i - 3].minutavypnuti = p->value();
						Serial.println("pomocnahodinavminuty");
						Serial.println(i - 3);
					}
				}
				otevritV[3] = 00;
			}

			if (p->name() == "voda" && p->value() == "zapnout")
				vodniSenzor = true;

			if (p->name() == "voda" && p->value() == "vypnout")
				vodniSenzor = false;

			if (p->name() == "zrni" && p->value() == "vypnout")
				vodniSenzor = false;

			if (p->name() == "vratka"&& p->value() == "otevrit")
			{
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);

					if (p->name() == "hodina")
					{
						//Serial.println(paramsNr);

						//const char* text = p->value();
						otevritV[0] = p->value().toInt();
						//cas[0] = atoi(p->value());
						Serial.println(otevritV[0]);
					}
					if (p->name() == "minuta")
					{
						//Serial.println(paramsNr);

						//const char* text = p->value();
						otevritV[1] = p->value().toInt();
						//cas[0] = atoi(p->value());
						Serial.println(otevritV[1]);
					}
				}
				otevritV[2] = 00;
			}

			if (p->name() == "vratka"&& p->value() == "zavrit")
			{
				for (int i = 0; i < paramsNr; i++) {

					AsyncWebParameter* p = request->getParam(i);


					if (p->name() == "hodina")
					{
						//Serial.println(paramsNr);

						//const char* text = p->value();
						zavritV[0] = p->value().toInt();
						//cas[0] = atoi(p->value());
						Serial.println(zavritV[0]);
					}
					if (p->name() == "minuta")
					{
						//Serial.println(paramsNr);

						//const char* text = p->value();
						zavritV[1] = p->value().toInt();
						//cas[0] = atoi(p->value());
						Serial.println(zavritV[1]);
					}
				}
				zavritV[2] = 00;
			}
		}
		request->send_P(200, "text/html", html, processor);
		//request->send(200, "text/plain", "message received", String(random(1000)));
	});
	DateTime now = datumCas.now();
	int timer[3] = { now.hour(),now.minute(),now.second() };
	Serial.println(now.hour());
	Serial.println(now.minute());
	Serial.println(now.second());
	server.begin();
	digitalWrite(svetlo, HIGH);
}
void loop() {

	tlacitkoVratek = digitalRead(buttonPin);
	//zarovkaONOFF = digitalRead(svetlo);

	DateTime now = datumCas.now();
	int timer[3] = { now.hour(),now.minute(),now.second() };
	String datumek = now.day() + "." + now.month() + '.' + now.year();

	// vodni senzor
	digitalWrite(cerpadlo, vodniSenzor && digitalRead(vodniSenzor) == HIGH ? HIGH : LOW);

	//hodiny, minuty, sekundy
	//otevreni pomoci nastaveneho casu
	if (timer[0] == otevritV[0] && timer[1] == otevritV[1] && timer[2] == otevritV[2] && poziceVratek == false)
	{
		for (int i = 0; i < 5; i++)
		{
			stepper1.step(6600);
		}
		for (int i = 0; i < otevritVdat[4]; i++)
		{
			stepper2.step(6600);
		}
		poziceVratek = true;
	}
	//pomoci data
	if (datumek == my && timer[0] == otevritVdat[0] && timer[1] == otevritVdat[1] && timer[2] == otevritVdat[2] && poziceVratek == false)
	{
		for (int i = 0; i < 5; i++)
		{
			stepper1.step(6600);
		}
		poziceVratek = true;
	}
	//zavreni pomoci nastaveneho casu
	if (timer[0] == zavritV[0] && timer[1] == zavritV[1] && timer[2] == zavritV[2] && poziceVratek == true)
	{
		for (int i = 0; i < 5; i++)
		{
			stepper1.step(-6600);
		}
		poziceVratek = false;
	}
	//zavreni vratek
	if (tlacitkoVratek == HIGH && poziceVratek == true || vratka == 2 && poziceVratek == true)
	{

		for (int i = 0; i < 5; i++)
		{
			stepper1.step(-6600);
		}
		tlacitkoVratek = LOW;
		poziceVratek = false;
		vratka = 0;
	}
	//otevreni vratek
	if (tlacitkoVratek == HIGH && poziceVratek == false || vratka == 1 && poziceVratek == false)
	{

		for (int i = 0; i < 5; i++)
		{
			stepper1.step(6600);
		}
		for (int i = 0; i < otevritVdat[4]; i++)
		{
			stepper1.step(6600);
		}
		tlacitkoVratek = LOW;
		poziceVratek = true;
		vratka = 0;
	}
	if (zarovka == 1)
	{
		//zarovkaONOFF = HIGH;
		digitalWrite(svetlo, LOW);
		svetloNaWeb = true;
		zarovka = 0;
	}
	if (zarovka == 2)
	{
		digitalWrite(svetlo, HIGH);
		//zarovkaONOFF = LOW;
		svetloNaWeb = false;
		zarovka = 0;
		for (int i = 0; i < 5; i++)
		{
			Serial.println(zwebudata[i].datumspusteni);
			Serial.println(zwebudata[i].hodinaspusteni);
			Serial.println(zwebudata[i].minutaspusteni);
			Serial.println("po{0}");
		}
	}
}