//#include <ESP8266WiFi.h>//este para esp8266






#include "MqttSensManager.h"
#include "MqttVarManager.h"
#include "MqttUtiles.h"

MqttSensor::MqttSensor()
{
  ivar=-1;
  flags=0;
}
void MqttSensor::Set(MqttSensor *s)
{
  tipo=s->tipo;
  flags=s->flags;
  pin=s->pin;
  ivar=s->ivar;
  ie=s->ie;
}
//*******************************************************************
MqttSensArray::MqttSensArray()
{
  n=0;
}

MqttSensor* MqttSensArray:: Get(int i)
{
  return &(sens[i]);
}
MqttSensor* MqttSensArray::Ivar2Sen(int ivar)
{
  MqttSensor* res;
  for(int i=0; i<n; i++)
  {
    res=Get(i);
    if(res->ivar==ivar)
      return res;
  }
    #ifdef DEBUG_PS
          Serial.print("Sens::Ivar2Sen: no encontrada sensor de variable: ");
          Serial.println(ivar);
        #endif
  return NULL;
}

int MqttSensArray::Add(MqttSensor* var)
{
  sens[n].Set(var);
  n++;
  return n-1;
}
//*******************************************************************
MqttSensManager::MqttSensManager()
{
  
  n_inter=0;
  bloqueo_sens=false;
  tiempo_sens=0;
  SetTimeRefres(15);//por defecto 15 segundos
  n_inter=0;
  pMqttSensManager=this;
}
void MqttSensManager::SetTimeRefres(int seg)
{
  incre_tsens=seg*1000;
}
void MqttSensManager::Config(MqttVarManager* var)
{
  vars=var;
}

MqttSensor* MqttSensManager::Get(int i)
{
  return sens.Get(i);
}

void MqttSensManager::inicia()
{
  if(sens.n>0)
    vars->AddListenner(this);
}
void MqttSensManager::inicia(int i)
{
  
}
void MqttSensManager::loop()
{
  

  if(bloqueo_sens)
    return;
  procesaInterrupciones();

  if(MqttUtiles::pasa_incre(&tiempo_sens, incre_tsens))
  {
     #ifdef DEBUG_PS
     Serial.println("Procesa Sens");
     #endif
    procesaSens();   
  }
}
void MqttSensManager::AddAnalogIn(int pin, char* topic, bool valNegado)
{
   MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_ANALOG_IN;
  s.pin=pin;
  if(valNegado)
    s.flags=MqttSensor::FLAG_NEG;
  s.ivar=vars->AddVar((byte)(MqttVar::IN_VAR | MqttVar::FLOAT_VAR),topic);
  int isen=sens.Add(&s);
  //pinMode(s.pin, INPUT);
}
void MqttSensManager::AddDout(int pin, char* topic, bool defautlValor)
{
  MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_DIGI_OUT;
  s.pin=pin;
  s.ivar=vars->AddVar((byte)(MqttVar::IN_VAR|MqttVar::OUT_VAR|MqttVar::ACCION_VAR),topic);
  sens.Add(&s);
  pinMode(s.pin, OUTPUT);
  digitalWrite(s.pin, defautlValor);
  vars->Get(s.ivar)->val.i = defautlValor;
}
void MqttSensManager::AddDoutPulsador(int pin, char* topic, bool defautlValor, int seg)
{
    MqttSensor s;
    s.tipo = (int)MqttSensor::SENS_DIGI_OUT_PULSANTE;
    s.pin = pin;
    s.ivar = vars->AddVar((byte)(MqttVar::IN_VAR | MqttVar::OUT_VAR | MqttVar::ACCION_VAR), topic);
    s.ie.pul.t = seg * 1000;
    s.ie.pul.vd = defautlValor;
    sens.Add(&s);
    pinMode(s.pin, OUTPUT);
    digitalWrite(s.pin, defautlValor);
    vars->Get(s.ivar)->val.i = defautlValor;
}
void MqttSensManager::AddBuzz(int pin, char* topic)
{
  MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_BUZZ_OUT;
  s.pin=pin;
  s.ivar=vars->AddVar((byte)(MqttVar::IN_VAR|MqttVar::OUT_VAR|MqttVar::ACCION_VAR),topic);
  sens.Add(&s);
  pinMode(s.pin, OUTPUT);
}
void MqttSensManager::AddMelodia(char* m)
{
  if(buzz)
  {
    buzz->Add(m);
  }
}
void MqttSensManager::AddDin(int pin, char* topic)
{
  MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_DIGI_IN;
  s.pin=pin;
  s.ivar=vars->AddVar((byte)(MqttVar::IN_VAR|MqttVar::ACCION_VAR),topic);
  int isen=sens.Add(&s);
  pinMode(s.pin, INPUT);
  
  ConfiguraInterrupcion(isen);
  
}
void MqttSensManager::AddDinRetardOff(int pin, int seg,char* topic)
{
    MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_DIGI_IN;
  s.pin=pin;
  s.flags=MqttSensor::FLAG_RETARD_OFF;
  s.ie.retard.r=seg*1000;
  s.ivar=vars->AddVar((byte)(MqttVar::IN_VAR|MqttVar::ACCION_VAR),topic);
  s.ie.retard.val=vars->Get(s.ivar)->val.i;
  int isen=sens.Add(&s);
  pinMode(s.pin, INPUT);
  
  ConfiguraInterrupcion(isen);
}
void MqttSensManager::AddDinRetardOn(int pin, int seg,char* topic)
{
    MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_DIGI_IN;
  s.pin=pin;
  s.flags=MqttSensor::FLAG_RETARD_ON;
  s.ie.retard.r=seg*1000;
  s.ivar=vars->AddVar((byte)(MqttVar::IN_VAR|MqttVar::ACCION_VAR),topic);
  s.ie.retard.val=vars->Get(s.ivar)->val.i;
  int isen=sens.Add(&s);
  pinMode(s.pin, INPUT);
  
  ConfiguraInterrupcion(isen);
}
void MqttSensManager::AddDinAccion(int pin, char* topic)
{
  MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_DIGI_IN_PULSANTE;
  s.pin=pin;
  s.ivar=vars->AddVar((byte)MqttVar::ACCION_VAR,topic);
  int isen=sens.Add(&s);
  pinMode(s.pin, INPUT);
  ConfiguraInterrupcion(isen);
}
void MqttSensManager::AddHDT22(int pin, char* topic)
{
  char buffer_t[32];
  MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_DHT22;
  s.pin=pin;
  s.ie.dht.p=&cdht;
  sprintf(buffer_t, "%s/t", topic);
  s.ivar=vars->AddVar((byte)MqttVar::IN_VAR| MqttVar::FLOAT_VAR,buffer_t);//variable temperatura
  sprintf(buffer_t, "%s/h", topic);
  s.ie.dht.ivarH=vars->AddVar((byte)MqttVar::IN_VAR| MqttVar::FLOAT_VAR,buffer_t);//variable humedad
  sens.Add(&s);
}

void MqttSensManager::AddBMP180(int sda,int scl, char* topic)
{
  /*
  if(bmppillado)
  return;
  bmppillado=true;
  */
  
  char buffer_t[32];
  MqttSensor s;
  s.tipo=(int)MqttSensor::SENS_BMP180;
  s.pin=sda;
  s.ie.bmp.p=&bmp;
  s.ie.bmp.pinScl=scl;
  sprintf(buffer_t, "%s/t", topic);
  s.ivar=vars->AddVar((byte)MqttVar::IN_VAR | MqttVar::FLOAT_VAR,buffer_t);//variable temperatura
  sprintf(buffer_t, "%s/p", topic);
  s.ie.bmp.ivarP=vars->AddVar((byte)MqttVar::IN_VAR,buffer_t);//variable presion
  sprintf(buffer_t, "%s/a", topic);
  s.ie.bmp.ivarA=vars->AddVar((byte)MqttVar::IN_VAR| MqttVar::FLOAT_VAR,buffer_t);//variable altura
  sens.Add(&s);


  //inicia------------------
  Wire.begin( s.pin,s.ie.bmp.pinScl);
  int i=0;
  while(!bmp.begin(), i<300)
  {
     i++;
     delay(10);
  }
}
void MqttSensManager::procesaSens()
{
   for(int i=0; i<sens.n; i++)
      procesaSensor(i);

}
void MqttSensManager::procesaSensor(int i)
{
  MqttSensor *s=sens.Get(i);
  MqttVar *v=vars->Get(s->ivar);
  MQTTvalor val;
  switch((int)s->tipo)
  {
    case((int)MqttSensor::SENS_DHT22)://pilla temperatura y humedad
    {
      //MqttVar *vh=vars->Get(s->ie.dht.ivarH);
      float t,h;
      for(int i=0; i<4; i++)
      {
        if (s->ie.dht.p->read2(s->pin, &t, &h, NULL) != SimpleDHTErrSuccess)
        {
          delay(20);
          continue;
        }
        val.f = t;
        vars->SetVal(s->ivar, val);
        //v->val.f=t;
        val.f = h;
        vars->SetVal(s->ie.dht.ivarH, val);
        //vh->val.f=h;
        break;
      }
      break;
   }
   case((int)MqttSensor::SENS_BMP180)://pilla temperatura y humedad
   {
      //MqttVar *vp=vars->Get(s->ie.bmp.ivarP);
     // MqttVar *va=vars->Get(s->ie.bmp.ivarA);
      val.f = s->ie.bmp.p->readTemperature();
      vars->SetVal(s->ivar, val);
      val.f = s->ie.bmp.p->readPressure();
      vars->SetVal(s->ie.bmp.ivarP, val);
      val.f = s->ie.bmp.p->readAltitude();
      vars->SetVal(s->ie.bmp.ivarA, val);
      /*
      v->val.f=s->ie.bmp.p->readTemperature();
      vp->val.i=s->ie.bmp.p->readPressure();//pascales;
      va->val.f=s->ie.bmp.p->readAltitude();
      */
      break;
   }
   case((int)MqttSensor::SENS_ANALOG_IN)://pilla temperatura y humedad
   {
      if(s->flags & MqttSensor::FLAG_NEG)
          val.f =100.*((float)(1024- analogRead(s->pin)))/1024;
      else
          val.f =100.*((float)(analogRead(s->pin)))/1024;
      vars->SetVal(s->ivar, val);
      break;
   }
     /* case((int)MqttSensor::SENS_DIGI_IN):
   {
      if(s->flags & MqttSensor::FLAG_NEG)
       v->val.i=(byte)(1- digitalRead(s->pin));
      else
        v->val.i=(byte)digitalRead(s->pin);
     break;
   }*/
  default:
    {
      break;
    }
  }
}
void MqttSensManager::OnVarChange(int ivar)
{
    MqttSensor *s = sens.Ivar2Sen(ivar);
    if(s==NULL)
         return;
    MqttVar *v=vars->Get(ivar);
    #ifdef DEBUG_PS
    Serial.println("MqttSensManager::OnChange ");
    #endif
    switch(s->tipo)
    {
      case((int)MqttSensor::SENS_DIGI_OUT):
      {
         #ifdef DEBUG_PS
          Serial.println("Sens::OnVarChangeSensor Dout cambiado");
        #endif
        if(s->flags & MqttSensor::FLAG_NEG)
          digitalWrite( s->pin, (1-v->val.i));
        else
          digitalWrite( s->pin, v->val.i);
        break;
      }
      case((int)MqttSensor::SENS_DIGI_OUT_PULSANTE):
      {
          if ((v->val.i>0) != s->ie.pul.vd)
          {
#ifdef DEBUG_PS
              Serial.println("Sens::OnVarChangeSensor Dout Pulsante cambiado");
#endif
              if (s->flags & MqttSensor::FLAG_NEG)
                  digitalWrite(s->pin, (1 - v->val.i));
              else
                  digitalWrite(s->pin, v->val.i);
              delay(s->ie.pul.t);
              v->val.i = 1 - v->val.i;
              if (s->flags & MqttSensor::FLAG_NEG)
                  digitalWrite(s->pin, (1 - v->val.i));
              else
                  digitalWrite(s->pin, v->val.i);
              vars->OnChange(ivar, true);
          }
          break;
      }
      case((int)MqttSensor::SENS_BUZZ_OUT):
      {
         #ifdef DEBUG_PS
          Serial.println("Sens::OnVarChangeSensor buz cambiado");
        #endif
        if(v->val.i>0 && buzz)
         {
            buzz->Toca( s->pin, v->val.i-1);
            v->val.i=0;
            vars->OnChange(ivar, true);
         }
        
        break;
      }
      default:
        break;
    }
    #ifdef DEBUG_PS
          Serial.println("OnVarChangeSensor fin");
        #endif
}

void MqttSensManager::procesaInterrupciones()
{
    if(MqttChangeInterrup)
    {
      noInterrupts();
      MqttChangeInterrup=false;
      interrupts();
      for(int i=0; i<n_inter; i++)
      {
        if(!MqttChange_ind_interrup[i])
          continue;
        noInterrupts();
        MqttChange_ind_interrup[i]=false;
        interrupts();
        MqttSensor* s=sens.Get(ind_interrup[i]);
        //if(chg_interrup[i])
        {
          #ifdef DEBUG_PS
            Serial.println("Detectado cambio en interrupcion");
          #endif
          //lee variable
          MqttVar *v=vars->Get(s->ivar);
          byte val=digitalRead(s->pin);
          if(s->flags & MqttSensor::FLAG_RETARD_OFF && v->val.i!=val && val==0)
          {
            #ifdef DEBUG_PS
            Serial.println("Se aplica retardo al off");
            #endif
            s->ie.retard.val=val;
            s->ie.retard.t=millis();
          }
          else if(s->flags & MqttSensor::FLAG_RETARD_ON && v->val.i!=val && val!=0)
          {
            #ifdef DEBUG_PS
            Serial.println("Se aplica retardo al on");
            #endif
            s->ie.retard.val=val;
            s->ie.retard.t=millis();
          }
          else
          {
            ProcesaSenInterrupciones(ind_interrup[i]);
          }
        }
      }  
    }
   

   //comprueba sensores retrasados
   for(int i=0; i<n_inter; i++)
   {
      MqttSensor* s=sens.Get(ind_interrup[i]);
      if(!(s->flags & (MqttSensor::FLAG_RETARD_OFF | MqttSensor::FLAG_RETARD_ON)))
        continue;
      MqttVar *v=vars->Get(s->ivar);
      if(v->val.i==s->ie.retard.val)
        continue;
      if(!MqttUtiles::pasa_incre(&s->ie.retard.t, s->ie.retard.r))
        continue;
         #ifdef DEBUG_PS
            Serial.println("Se detecta cambio en sensor retardado");
        #endif
      ProcesaSenInterrupciones(ind_interrup[i]);
   }
}
void MqttSensManager::ProcesaSenInterrupciones(int isen)
{
    MqttSensor* s=sens.Get(isen);
    MqttVar *v=vars->Get(s->ivar);
    byte val=digitalRead(s->pin);
     switch((int)s->tipo)
     {
          case((int)MqttSensor::SENS_DIGI_IN):
          {
            //lee y llama a cambio si es necesario
            
            if(val!=v->val.i)
            {
              v->val.i=val;
              vars->OnChange(s->ivar, true);
            }
            break;
          }
          case((int)MqttSensor::SENS_DIGI_IN_PULSANTE):
          {
            //lee y llama a cambio si es necesario
            if(val!=v->val.i)
            {
              v->val.i=val;
              vars->OnChange(s->ivar, true);
            }
            
            //v->val.i=val;
            //vars->OnChange(s->ivar);
            
            break;
          }
          default:
            break;
     }
}

 //funciones auxiliares de interrupcion-------------------------------
 void MqttSensManager::OnInterrupcion(int i)
 {

  //MqttSensor* s=sens.Get(ind_interrup[i]);
  MqttChangeInterrup=true;
  MqttChange_ind_interrup[i]=true;
 }
 void MqttSensManager::ConfiguraInterrupcion(int isen)
 {
    #ifdef DEBUG_PS
            
            Serial.println("Configurando interrupcion");
        #endif
    MqttChange_ind_interrup[n_inter]=false;
    ind_interrup[n_inter++]=isen;
    
    int pin=sens.Get(isen)->pin;
    switch(n_inter-1)
  {
     case(0):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion0, CHANGE);
     break;
      case(1):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion1, CHANGE);
     break;
      case(2):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion2, CHANGE);
     break;
      case(3):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion3, CHANGE);
     break;
      case(4):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion4, CHANGE);
     break;
      case(5):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion5, CHANGE);
     break;
      case(6):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion6, CHANGE);
     break;
      case(7):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion7, CHANGE);
     break;
     /*
      case(8):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion8, CHANGE);
     break;
      case(9):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion9, CHANGE);
     break;
      case(10):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion10, CHANGE);
     break;
      case(11):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion11, CHANGE);
     break;
      case(12):
     attachInterrupt(digitalPinToInterrupt(pin), MqttSensManagerInterrupcion12, CHANGE);
    break;*/
  }
  
 }

 
 //chapuza que no se como hacerlo de otra manera
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion0()
 {
    pMqttSensManager->OnInterrupcion(0);
 }
 
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion1()
 {
     pMqttSensManager->OnInterrupcion(1);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion2()
 {
     pMqttSensManager->OnInterrupcion(2);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion3()
 {
     pMqttSensManager->OnInterrupcion(3);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion4()
 {
     pMqttSensManager->OnInterrupcion(4);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion5()
 {
    pMqttSensManager->OnInterrupcion(5);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion6()
 {
     pMqttSensManager->OnInterrupcion(6);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion7()
 {
     pMqttSensManager->OnInterrupcion(7);
 }
 /*
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion8()
 {
     pMqttSensManager->OnInterrupcion(8);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion9()
 {
     pMqttSensManager->OnInterrupcion(9);
 }
ICACHE_RAM_ATTR void MqttSensManagerInterrupcion10()
 {
    pMqttSensManager->OnInterrupcion(10);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion11()
 {
     pMqttSensManager->OnInterrupcion(11);
 }
 ICACHE_RAM_ATTR void MqttSensManagerInterrupcion12()
 {
    pMqttSensManager->OnInterrupcion(12);
 }*/
