
#include "MqttDesencadenadorManager.h"


MqttDesencadenador::MqttDesencadenador()
{
	activo = true;
}
MQTTvalor MqttDesencadenador::GetVarValue(char* ivar, MqttVarManager* vars)
{
	MqttVar* v = GetVar(ivar, vars);
	return v->val;
}
float MqttDesencadenador::GetValue(char* ivar, MqttVarManager* vars)
{
	MqttVar* v = GetVar(ivar, vars);
	if (v->flags & MqttVar::FLOAT_VAR)
		return v->val.f;
	return (float)v->val.i;
}

int MqttDesencadenador::GetIvar(char* ivar)
{
	char buf[16];
	int n = strlen(ivar);
	strcpy(buf, ivar);
	buf[n - 1] = 0;
	return atoi(buf);
}
MqttVar* MqttDesencadenador::GetVar(char* ivar, MqttVarManager* vars)
{
	return vars->Get(GetIvar(ivar));
}
void MqttDesencadenador::ExeEfecto(MqttVarManager* vars, char* oper, char* x, char* y)
{
#ifdef DEBUG_PS

	Serial.print("MqttDesencadenador::ExeEfecto: ");
	Serial.print(oper);
	Serial.print(" x: ");
	Serial.print(x);
	Serial.print(" y: ");
	Serial.println(y);
#endif

	switch (oper[0])
	{
	case('!'):
	{
		vars->InvierteVar(GetIvar(x));
		return;
	}
	case('='):
	{
		MqttVar* v = GetVar(x, vars);
		MQTTvalor val = GetVarValue(x, vars);
		if (v->flags & MqttVar::FLOAT_VAR)
			val.f = atof(y);
		else
			val.i = atoi(y);
		vars->SetVal(GetIvar(x), val);
		return;
	}
	}
}
bool MqttDesencadenador::Eval(MqttVarManager* vars, char* oper, char* x, char* y)
{
#ifdef DEBUG_PS

	Serial.print("MqttDesencadenador::eval: ");
	Serial.print(oper);
	Serial.print(" x: ");
	Serial.print(x);
	Serial.print(" y: ");
	Serial.println(y);
#endif
	//las variables estaran terminadas en } 
	float vx, vy;
	//pilla valores
	int nx = strlen(x);
	int ny = strlen(y);
	if (x[nx - 1] == '}')
		vx = GetValue(x, vars);
	else
		vx = atof(x);
	if (ny <= 0)
		vy = 0;
	else if (y[ny - 1] == '}')
		vy = GetValue(y, vars);
	else
		vy = atof(y);
	switch (oper[0])
	{
	case('!'):
		return vx != 1;
	case('='):
		return vx == vy;
	case('<'):
	{
		if (oper[1] == '=')
			return vx <= vy;
		return vx < vy;
	}

	case('>'):
		if (oper[1] == '=')
			return vx >= vy;
		return vx > vy;
	}
	return false;

}
int MqttDesencadenador::GetElementosOper(char* oper)
{
	if (oper[0] == '!')
		return 1;
	else
		return 2;
}
void MqttDesencadenador::procesaOper(MqttExeParam* p)
{
	if (expresion[p->i] <= '9' && expresion[p->i] >= '0' || expresion[p->i] == '.' || expresion[p->i] == '{' || expresion[p->i] == ' ')
	{
		p->estado = 0;
		p->toper = true;
		p->oper[p->noper] = 0;
		#ifdef DEBUG_PS
		  Serial.print("encontrado oper: ");
		  Serial.println( p->oper);
	    #endif
	}
	else
	{
		p->oper[p->noper++] = expresion[p->i];
		p->i++;
	}
}

void MqttDesencadenador::procesaVar(MqttExeParam* p)
{
	if ((expresion[p->i] <= '9' && expresion[p->i] >= '0') || expresion[p->i] == '.')
	{
		if (p->tvar1)
			p->var2[p->nvar2++] = expresion[p->i];
		else
			p->var1[p->nvar1++] = expresion[p->i];
		p->i++;


	}
	else
	{
		p->estado = 0;
		if (expresion[p->i] == '}')
		{
			if (p->tvar1)
				p->var2[p->nvar2++] = expresion[p->i];
			else
				p->var1[p->nvar1++] = expresion[p->i];
			p->i++;
		}
		if (p->tvar1)
		{
			p->var2[p->nvar2] = 0;
			p->tvar2 = true;
			#ifdef DEBUG_PS
			Serial.print("encontrado var2: ");
			Serial.println( p->var2);
			  #endif
		}
		else
		{
			p->var1[p->nvar1] = 0;
			p->tvar1 = true;
			#ifdef DEBUG_PS
			Serial.print("encontrado var1: ");
			Serial.println( p->var1);
			  #endif
		}
	}
}
bool MqttDesencadenador::Exe(MqttVarManager* vars)
{
#ifdef DEBUG_PS

	Serial.print("MqttDesencadenador::Exe: ");
	Serial.print(expresion);
	Serial.print(" activo: ");
	Serial.println(activo);
#endif
	//por ahora limite de 2 var
	MqttExeParam p;
	bool res = false;
	while (expresion[p.i] != 0 && p.sigue)
	{
		/*
		  #ifdef DEBUG_PS
		Serial.print("MqttDesencadenador::Exe: ");
		Serial.print(expresion[i]);
		Serial.print(" estado ");
		Serial.println(estado);
		#endif
		*/

		switch (p.estado)
		{

		case(0)://estado selector
		{
			//distincion de operar
			if (p.toper)
			{
				if (p.oper[0] == '-' && p.oper[1] == '>')
				{

					p.tcausa = true;
					p.toper = false;
					p.noper = 0;
					p.oper[0] = 0;
					if (!p.res || !activo)
					{
						activo = !p.res;
						/*  #ifdef DEBUG_PS

					   Serial.println("Fin causa sale ");
						#endif*/
						p.sigue = false;
						break;
					}
					else
					{
						activo = false;
						res = true;
						/*#ifdef DEBUG_PS
						activo=false;
					  Serial.println("Fin causa sigue ");
					   #endif*/
					}
				}
				else if (p.oper[0] == '&')
				{
					/* #ifdef DEBUG_PS

					Serial.println("operador and ");
					 #endif*/
					 //p.tcausa=true;
					p.toper = false;
					p.noper = 0;
					p.esAnd = true;
					p.oper[0] = 0;

				}
				else if (p.oper[0] == '|')
				{
					/*#ifdef DEBUG_PS

					Serial.println("operador or ");
					 #endif*/
					 //p.tcausa=true;
					p.toper = false;
					p.noper = 0;
					p.esAnd = false;
				}
			}
			if (p.toper && p.tvar1 && (GetElementosOper(p.oper) == 1 || p.tvar2))
			{

				//valida causa
				if (!p.tcausa)
				{
					//valida causa
					if (p.esAnd)
						p.res = p.res && Eval(vars, p.oper, p.var1, p.var2);
					else
						p.res = p.res || Eval(vars, p.oper, p.var1, p.var2);

					/* #ifdef DEBUG_PS
				   Serial.print("validaCausa res: ");
				   Serial.print(p.res);
					Serial.print(" esAnd:  ");
				   Serial.println(p.esAnd);
			   #endif*/

				}
				else
				{
					//ejecuta efecto
					ExeEfecto(vars, p.oper, p.var1, p.var2);
				}
				/*#ifdef DEBUG_PS

				 Serial.println("Fin oper ");
			   #endif*/
				p.tvar1 = p.tvar2 = p.toper = false;
				p.nvar1 = p.nvar2 = p.noper = 0;
				p.var1[0] = 0;
				p.var2[0] = 0;
				p.oper[0] = 0;
			}
			if (expresion[p.i] == ' ')//pasa de los espacios
			{
				p.i++;
				break;
			}

			//distincion de escalares
			if ((expresion[p.i] <= '9' && expresion[p.i] >= '0') || expresion[p.i] == '.')
			{
				p.estado = 1;
				if (p.tvar1)
					p.nvar2 = 0;
				else
					p.nvar1 = 0;
			}
			else
			{
				//distincion de variables
				if (expresion[p.i] == '{')
				{
					p.estado = 1;
					p.i++;
				}
				else//distincion de operadores
				{
					p.estado = 2;
				}
			}
		}
		break;
		case(1)://pillando var o escalar   
			procesaVar(&p);
			break;
		case(2)://pilla oper
			procesaOper(&p);
			break;
		}
	}
#ifdef DEBUG_PS

	Serial.println("MqttDesencadenador::Exe fin");
#endif
	return  res;
}
//*******************************************************************
MqttDesencadenadorArray::MqttDesencadenadorArray()
{
	n = 0;
}

MqttDesencadenador* MqttDesencadenadorArray::Get(int i)
{
	return &(data[i]);
}

int MqttDesencadenadorArray::Add(MqttDesencadenador* var)
{
	data[n] = *var;
	strcpy(data[n].expresion, var->expresion);
	n++;
	return n - 1;
}
//*******************************************************************
MqttDesencadenadorManager::MqttDesencadenadorManager()
{
	revisa = true;
}

void MqttDesencadenadorManager::OnVarChange(int ivar)
{
	revisa = true;
	//marca Accion--
}

void MqttDesencadenadorManager::inicia(MqttVarManager* v)
{
	vars = v;
	if (des.n > 0)
	{
#ifdef DEBUG_PS
		Serial.println("MqttDesencadenador::inicia como listenner");
#endif
		vars->AddListenner(this);
	}
}

void MqttDesencadenadorManager::Suscribe()
{

}
int MqttDesencadenadorManager::OnMqtt(char* topic, char* payload)
{
	return -1;
}

void MqttDesencadenadorManager::loop()
{
	if (revisa)
	{
		revisa = false;
		RevisaDesencadenadores();
	}
}

void MqttDesencadenadorManager::RevisaDesencadenadores()
{
#ifdef DEBUG_PS
	Serial.println("MqttDesencadenadorManager::RevisaDesencadenadores");
#endif
	bool revisa = true;
	while (revisa)
	{
		revisa = false;
		for (int i = 0; i < des.n; i++)
		{
			if (des.Get(i)->Exe(vars))
				revisa = true;
		}
		//desmarca Var de volatiles
		vars->ResetVolatileVar();
	}

#ifdef DEBUG_PS
	Serial.println("RevisaDesencadenadores fin");
#endif
}
void MqttDesencadenadorManager::AddDes(char* expresion)
{
	MqttDesencadenador d;
	strcpy(d.expresion, expresion);
	des.Add(&d);
}
