//#include <ESP8266WiFi.h>//este para esp8266
#include <SPI.h>
#include "MqttDefines.h"
#include "MqttVarManager.h"
#include "MqttUtiles.h"
#include <cstring>
#include <PubSubClient.h>

MqttTopicAttay::MqttTopicAttay()
{
  n=0;
  nst=0;
}

char* MqttTopicAttay::Get(int i)
{
  return &str[(ind[i])];
}

int MqttTopicAttay::Get(char *topic)
{
  for(int i=0; i<n; i++)
  {
    if(!strcmp(topic,Get(i)))
      return i;
  }
  return (int)-1;
}

int MqttTopicAttay::Add(char *topic)
{
  int i=Get(topic);
  if(i>(int)0)
  {
    return i;
   }
  i=n;
  n=n+1;
  ind[i]=nst;
  nst=nst+strlen(topic)+1;
  strcpy(Get(i), topic);
  return i;
}

//*******************************************************************

MqttVar::MqttVar()
{
  flags=0;
  val.f=0;
  topic=0;
}

//*******************************************************************
MqttVarArray::MqttVarArray()
{
  n=0;
}

MqttVar* MqttVarArray:: Get(int i)
{
  return &(data[i]);
}
  
MqttVar* MqttVarArray::GetVar(int itopic)
{
  for(int i=0; i<n; i++)
  {
    if(data[i].topic==itopic)
      return &(data[i]);
  }
  return NULL;
}

int MqttVarArray::Add(MqttVar* var)
{
  data[n]=*var;
  n++;
  return n-1;
}
//*******************************************************************

MqttVarManager::MqttVarManager()
{
   
   tiempo_var=0;
   SetTimeRefres(30);
   nListenner=0;
}
void MqttVarManager::SetTimeRefres(int seg)
{
  incre_tvar=seg*1000;
}
void MqttVarManager::config(MqttVarArray *vArray, MqttTopicAttay* t)
{
  if(vArray)
    vars=vArray;
  else
    vars=&_v;
  if(t)
    topics=t;
  else
    topics=&_t;
}

void MqttVarManager::OnMqtt(char* topic, char* payload)
{
    char buf[32];
    #ifdef DEBUG_PS
    Serial.print("OnmqttVars: ");
  Serial.println(topic);
  Serial.print("val: ");
  Serial.println(payload);

  #endif
    sprintf(buf, "%s",topic);
    int nt=strlen(buf);
    int ng=strlen("/get");
   
    bool isGet=!strcmp("/get", &buf[nt-ng]);
    buf[nt-ng]=0;
    #ifdef DEBUG_PS
     Serial.print("OnmqttVars:Topiccompara:");
     Serial.println(buf);
     #endif
    byte f=MqttVar::OUT_VAR;
    if(isGet)
     {
        f=(byte)MqttVar::PRIV_VAR;
        #ifdef DEBUG_PS
        Serial.println("OnmqttVars: get detectado");
        #endif
     }
     else
     {
       if(strcmp("set", &buf[nt-ng+1]))
       {
        #ifdef DEBUG_PS
          Serial.println("OnmqttVars: Ni get ni set");
        #endif
        return;//no es ni get ni set
       }
        
       #ifdef DEBUG_PS
          Serial.println("OnmqttVars: set detectado");
        #endif
     
     }
   

    //comprueba variables
    MqttVar* v;
    int res=-1;
    for(int i=0; i<vars->n; i++)
    {
      v=vars->Get(i);
     
      if((v->flags & f) && !strcmp(topics->Get(v->topic),buf))
      {
        if(v->flags & MqttVar::FLOAT_VAR)
          {
            float ff=v->val.f;
            v->val.f=atof(payload);
            if(ff!=v->val.f)
              res=i;
          }
        else
        {
          int ii=v->val.i;
          v->val.i=atoi(payload);
           if(ii!=v->val.i)
              res=i;
        }
        if(res>0 || isGet)
          OnChange(i);
        break;//suponemos solo una variable con el mismo topic
      }
    }
    return;
}

void MqttVarManager::loop()
{
  if(MqttUtiles::pasa_incre(&tiempo_var, incre_tvar))
  {
         #ifdef DEBUG_PS
     Serial.println("Procesa vars");
     #endif
    PublicaVars();   
  }
}

void MqttVarManager::PublicaVar(int ivar)
{
  char buffer_t[32];
   char buffer_p[24];
    MqttVar* v=vars->Get(ivar);

  sprintf(buffer_t, "%s/get",topics->Get(v->topic));
  //Publica valor
  if(v->flags & MqttVar::FLOAT_VAR)
      dtostrf(v->val.f,3, 2, buffer_p);
  else
      sprintf(buffer_p, "%d", (int)v->val.i);
  client_qqtt->publish(buffer_t, buffer_p);
      
}


void MqttVarManager::PublicaVars()
{
   
   byte f=MqttVar::IN_VAR;
   MqttVar* v;
   for(int i=0; i<vars->n; i++)
   {
      v=vars->Get(i);
      if(v->flags & f)
      {
        PublicaVar(i);
      }
   }
}
void MqttVarManager::inicia(PubSubClient* client_mqtt)
{
  client_qqtt=client_mqtt;
}

void MqttVarManager::Suscribe()
{
   //suscribe a mqtt------------
   char buffer_t[32];
   MqttVar* v;
   for(int i=0; i<vars->n; i++)
   {
      v=vars->Get(i);
      if(v->flags & MqttVar::OUT_VAR)//suscribe al set
      {
        sprintf(buffer_t, "%s/set",topics->Get(v->topic));
        client_qqtt->subscribe(buffer_t);
      }
      if(v->flags & MqttVar::PRIV_VAR)//suscribe al get
      {
        sprintf(buffer_t, "%s/get",topics->Get(v->topic));
        client_qqtt->subscribe(buffer_t);
      }
   }
}
int MqttVarManager::AddVar(byte flags, char*topic)
{
  MqttVar v;
  v.flags=flags;
  v.topic=topics->Add(topic);
  return vars->Add(&v);
}
int MqttVarManager::AddInternalVarFloat( char*topic)
{
  return AddVar((byte)(MqttVar::PRIV_VAR|MqttVar::FLOAT_VAR ),topic);
}
int MqttVarManager::AddInternalVarInt( char*topic)
{
  return AddVar((byte)(MqttVar::PRIV_VAR),topic);
}
MqttVar* MqttVarManager::Get(int i)
{
  return vars->Get(i);
}
int MqttVarManager::GetId(char* topic)
{
   #ifdef DEBUG_PS

            Serial.println("MqttVarManager::GetId");
        #endif
  int itop= topics->Get(topic);
   #ifdef DEBUG_PS

            Serial.println("MqttVarManager::GetId busca var");
        #endif
  for(int i=0;i<vars->n; i++)
  {
    if(vars->Get(i)->topic==itop)
      return i;
  }
   #ifdef DEBUG_PS

            Serial.println("MqttVarManager::GetId variable no encontrada");
        #endif
  return -1;
}

void MqttVarManager::OnChange(int ivar)
{
 
   MqttVar* v=vars->Get(ivar);
   byte f= MqttVar::ACCION_VAR;
   if(v->flags & f)
   {
     PublicaVar(ivar);
   }
   for (int i=0; i<nListenner; i++)
   {
      onChangeListener[i]->OnVarChange(ivar);
   }
      
}
void MqttVarManager::AddListenner(MqttOnVarChangeListenner *pOnChangeListener)
{
  onChangeListener[nListenner++]=pOnChangeListener;
}
void MqttVarManager::ResetVolatileVar()
{
    for(int i=0; i<vars->n; i++)
   {
     MqttVar* v=vars->Get(i);
     if(v->flags& MqttVar::VOLATILE_VAR)
     {
       if(v->flags & MqttVar::FLOAT_VAR)
        v->val.f=0;
        else
         v->val.i=0;
     }
     
   }
}
void MqttVarManager::InvierteVar(int ivar)
{
     MqttVar* v=vars->Get(ivar);
     if(v->flags & MqttVar::FLOAT_VAR)
     {
        v->val.f=100.0-v->val.f;
     }
     else
        v->val.i=1-v->val.i;
     OnChange(ivar);
}
void MqttVarManager::SetVal(int ivar,MQTTvalor val)
{
    MqttVar* v=vars->Get(ivar);
    v->val=val;
    OnChange(ivar);
}
