#include <Arduino.h>
#include <CCM.h>


const char PROGMEM *UECSattrChar[] = {
  UECSccmFix1, UECSccmFix2, UECSccmFix3, UECSccmFix4,};
  
PROGMEM const char *UECSCCMLEVEL[]={
  UECS_A1S0, UECS_A1S1, UECS_A10S0, UECS_A10S1, UECS_A1M0, UECS_A1M1, UECS_S1S, UECS_S1M, UECS_B0_, UECS_B1_, };

boolean UECSparseRec(char * _packetBuffer, char* _tempStr20, struct UECSTEMPCCM *_tempCCM){
  int bufsize = strlen(_packetBuffer);
  int point = 0;
  int _point = 0;     
  // <?xml ------------  <type=" 
  if((_point = UECScheckPacketPGM(point, _packetBuffer, bufsize, &(UECSccmFix0[0]), 42)) != -1){ 
    point = _point + 1; 
  }
  else{ 
    _tempCCM->attribute[0] = -1; 
    return false;
  }
  if((_point = UECScheckPacketPGM(point, _packetBuffer, bufsize, &(UECSccmFix00[0]), 12)) != -1){ 
    point = _point + 1; 
  }
  else{ 
    _tempCCM->attribute[0] = -1; 
    return false;
  }   
  // type attribute   
  _point = point;
  boolean checkType = false;
  while(_point < bufsize && (_point - point) < MAX_TYPE_CHAR){
    if(_packetBuffer[_point] == 34){
      _tempCCM->type[_point - point] = 0;
      checkType = true;
      break;
    }
    _tempCCM->type[_point - point] = _packetBuffer[_point];
    _point++;
  } 
  if(!checkType){
    _tempCCM->attribute[0] = -1;
    return false;  
  }
  point = _point;
  // attribute
  for(int i = 0; i < 4; i++){
    strcpy_P(_tempStr20, (char*)pgm_read_word(&(UECSattrChar[i])));
    if((_point = UECScheckPacket(point, _packetBuffer, bufsize, _tempStr20, UECSattrCharNum[i])) != -1){ 
      point = _point + 1; 
    }
    else{ 
      _tempCCM->attribute[0] = -1; 
      return false;
    }
    _tempCCM->attribute[i] = 0;
    while(point < bufsize){
      if((_packetBuffer[point] >= 48) && (_packetBuffer[point] <= 57)){
        _tempCCM->attribute[i] = _tempCCM->attribute[i] * 10 +  (_packetBuffer[point] - 0x30);
      }
      else if(_packetBuffer[point] == 10 ||_packetBuffer[point] == 13 || _packetBuffer[point] == 32){
      }
      else if(_packetBuffer[point] == 34){
        break;
      }
      else{
        _tempCCM->attribute[0] = -1;
        //          return false;
        return i;
      }
      point++;  
    }
  } 
  // "\">"
  if((_point =  UECScheckPacketPGM(point, _packetBuffer, bufsize, &(UECSccmFix5[0]), 2)) != -1){ 
    point = _point + 1;
  }
  else{ 
    _tempCCM->attribute[0] = -1; 
    return false;
  }
  // value 
  signed long value = 0;
  unsigned char decimal= 0;
  signed char minus = 0;
  signed char keta = 0;
  boolean checkValue = false;
  while(point < bufsize){
    if(minus == 0){
      if(_packetBuffer[point] == '-'){
        minus = -1;   
      }
      else if((_packetBuffer[point] >= '0') && (_packetBuffer[point] <= '9')){
        minus = 1;
        keta++;
        value = value * 10 + (_packetBuffer[point] - 0x30);
      }
      else{
        break; 
      }
    }
    else if(_packetBuffer[point] == 10 || _packetBuffer[point] == 13 || _packetBuffer[point] == 32){
    }
    else{
      if((_packetBuffer[point] >= '0') && (_packetBuffer[point] <= '9')){
        keta++;
        value = value * 10 + (_packetBuffer[point] - 0x30);
      }
      else if(_packetBuffer[point] == '.' && keta != 0){
        decimal = keta;
      }
      else if(_packetBuffer[point] == '<'){
        if(keta != 0 && decimal != keta){
          if(decimal != 0){
            decimal = keta - decimal;
          }
          value = minus * value;
          checkValue = true;
          break;  
        }
        else{
          break;  
        }
      }
      else{
        break; 
      }
    }
    point++;
  }
  if(!checkValue){
    _tempCCM->attribute[0] = -1;
    return false;
  }
  _tempCCM->value = value;
  _tempCCM->decimal = decimal;
  // "</DATA><IP>" 
  if((_point =  UECScheckPacketPGM(point, _packetBuffer, bufsize, &(UECSccmFix6[0]), 11)) != -1){ 
    point = _point + 1;
  }
  else{
    _tempCCM->attribute[0] = -1; 
    return false;
  }
  // IP(NoCheck) 
  boolean ipCheck = false;
  while(point < bufsize){
    if(_packetBuffer[point] == '<'){
      ipCheck = true;
      break;
    }
    point++;  
  }
  if(!ipCheck){
    _tempCCM->attribute[0] = -1;
    return false;
  }
  //    
  if((_point =  UECScheckPacketPGM(point, _packetBuffer, bufsize, &(UECSccmFix7[0]), 12)) != -1){ 
    point = _point + 1;
  }
  else{
    _tempCCM->attribute[0] = -1; 
    return false;
  }
  return true;
}

void UECSgetCCMSend(char* _packetBuffer, char* _tempStr20, struct UECSCCM* _ccm, struct UECSOriginalAttribute* _orgAttribute){
  char* point;
  point = UECSaddPGMChar(&(UECSccmFix0[0]), 42, _packetBuffer);
  point = UECSaddPGMChar(&(UECSccmFix00[0]), 12, point++);   
//  strcpy_P(_tempStr20, _ccm.type);  
//  point = UECSaddChar(_tempStr20, point++);
  point = UECSaddTempChar(_ccm->type, _tempStr20, point++);
  
  point = UECSaddPGMChar(&(UECSccmFix1[0]), 8, point++); 
  sprintf(_tempStr20, "%d", _ccm->baseAttribute[0]);
  point = UECSaddChar(_tempStr20, point++);
  
  point = UECSaddPGMChar(&(UECSccmFix2[0]), 10, point++);
  sprintf(_tempStr20, "%d", _ccm->baseAttribute[1]);
  point = UECSaddChar(_tempStr20, point++);
  
  point = UECSaddPGMChar(&(UECSccmFix3[0]), 9, point++);
  sprintf(_tempStr20, "%d", _ccm->baseAttribute[2]);
  point = UECSaddChar(_tempStr20, point++);
  
  point = UECSaddPGMChar(&(UECSccmFix4[0]), 12, point++);
  sprintf(_tempStr20, "%d", _ccm->attribute[3]);
  point = UECSaddChar(_tempStr20, point++);
  
  point = UECSaddPGMChar(&(UECSccmFix5[0]), 2, point++);
  dtostrf(((double)_ccm->value) / pow(10, _ccm->decimal), -1, _ccm->decimal, _tempStr20);
  point = UECSaddChar(_tempStr20, point++);
  point = UECSaddPGMChar(&(UECSccmFix6[0]), 11, point++);
  sprintf(_tempStr20, "%d.%d.%d.%d", _orgAttribute->ip[0], _orgAttribute->ip[1], _orgAttribute->ip[2], _orgAttribute->ip[3]);
  point = UECSaddChar(_tempStr20, point++);
  point = UECSaddPGMChar(&(UECSccmFix7[0]), 12, point++);
  *(++point) = 0;
}

void UECSupRecCCM(UECSCCM* _ccm, UECSTEMPCCM* _ccmRec, unsigned long _recmillis){
  boolean success = false;

    _ccm->attribute[0] = _ccmRec->attribute[0];
    _ccm->attribute[1] = _ccmRec->attribute[1];    
    _ccm->attribute[2] = _ccmRec->attribute[2];
    _ccm->attribute[3] = _ccmRec->attribute[3];
    _ccm->address[0] = _ccmRec->address[0];
    _ccm->address[1] = _ccmRec->address[1];     
    _ccm->address[2] = _ccmRec->address[2];     
    _ccm->address[3] = _ccmRec->address[3];
    _ccm->value = _ccmRec->value;
    _ccm->recmillis = _recmillis;
    _ccm->flagStimeRfirst = true;

}

void UECScheckUpDate(UECSCCM _ccmList[], int _maxccm, UECSTEMPCCM* _tempCCM, char* _tempStr20, unsigned long _time){
	//Serial.print("[UECScheckUpDate]\n");
	//Serial.print("_time=");Serial.print(_time);Serial.print("\n");
	
	
  if(_tempCCM->attribute[0] != -1){
    for(unsigned char i = 0; i < _maxccm; i++){ 
      if(_ccmList[i].ccmLevel != NONE && _ccmList[i].sender == false){
        strcpy_P(_tempStr20, _ccmList[i].type);
        if(strcmp(_tempStr20, _tempCCM->type) == 0){
          boolean up = false;
          if((_tempCCM->attribute[0] == 0 || _tempCCM->attribute[0] == _ccmList[i].baseAttribute[0]) && (_tempCCM->attribute[1] == 0 || _tempCCM->attribute[1] == _ccmList[i].baseAttribute[1]) && (_tempCCM->attribute[2] == 0 || _tempCCM->attribute[2] == _ccmList[i].baseAttribute[2])){
            if(!_ccmList[i].validity){
              up = true;      
            }
            else if(_tempCCM->attribute[3] < _ccmList[i].attribute[3]){
              up = true;
            }
            else{
              if(_tempCCM->attribute[0] == _ccmList[i].attribute[0]){
                if(_tempCCM->attribute[1] == _ccmList[i].attribute[1]){
                  if(_tempCCM->attribute[2] == _ccmList[i].attribute[2]){
                    if(_tempCCM->address <= _ccmList[i].address){
                      up = true; 
                    } 
                  }
                  else if (_tempCCM->attribute[2] == _ccmList[i].baseAttribute[2]){
                    up = true;
                  }                         
                }
                else if (_tempCCM->attribute[1] == _ccmList[i].baseAttribute[1]){
                  up = true;
                }                       
              }
              else if (_tempCCM->attribute[0] == _ccmList[i].baseAttribute[0]){
                up = true;
              } 
            }
            if(up){
              if(_ccmList[i].sender == false && _ccmList[i].ccmLevel != NONE){
              
              

              
              
              
              
              
                UECSupRecCCM(&_ccmList[i], _tempCCM, _time);
              }
            }
          }
        }  
      }  
    }
  }  
}

/********************************/
/* 16529 Response   *************/
/********************************/

boolean UECSresNodeScan(UECSCCM _ccmList[], int _maxccm, char* _buffer, char* _tempStr20, const char* _name, const char* _vender, const char* _uecsid, UECSOriginalAttribute* _orgAttribute){
  int bufsize = strlen(_buffer);
  boolean check = false; 
  int point = 0;
  int _point = 0;     
  //<?xml ------------ 
  if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFix0[0]), 42)) != -1){ 
    point = _point + 1; 
  }
  else{
    return false;
  }

  if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRN1A[0]), 9)) != -1){  // <NODESCAN
    point = _point + 1;
    if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRN2A[0]), 19)) != -1){ // ></NODESCAN></UECS>
      check = true;

    }
    else if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRN2B[0]), 9)) != -1){  // /></UECS>
      check = true;

    }else{

      return false;
      
    }
    //NODESCANRES
    char* pointer = 0;
    pointer = UECSaddPGMChar(&(UECSccmFix0[0]), 42, _buffer);
    pointer = UECSaddPGMChar(&(UECSccmFixSN1[0]), 12, pointer++); 
    pointer = UECSaddPGMChar(&(_name[0]), 11, pointer++);
    pointer = UECSaddPGMChar(&(UECSccmFixSN2[0]), 15, pointer++); 
    pointer = UECSaddPGMChar(&(_vender[0]), 10, pointer++);
    pointer = UECSaddPGMChar(&(UECSccmFixSN3[0]), 17, pointer++); 
    pointer = UECSaddPGMChar(&(_uecsid[0]), 12, pointer++);
    pointer = UECSaddPGMChar(&(UECSccmFixSN4[0]), 13, pointer++); 
    sprintf(_tempStr20, "%d.%d.%d.%d", _orgAttribute->ip[0], _orgAttribute->ip[1], _orgAttribute->ip[2], _orgAttribute->ip[3]);
    pointer = UECSaddChar(_tempStr20, pointer++);
    pointer = UECSaddPGMChar(&(UECSccmFixSN5[0]), 10, pointer++);
    sprintf(_tempStr20, "%02x%02x%02x%02x%02x%02x", _orgAttribute->mac[0], _orgAttribute->mac[1], _orgAttribute->mac[2], _orgAttribute->mac[3], _orgAttribute->mac[4], _orgAttribute->mac[5]);
    pointer = UECSaddChar(_tempStr20, pointer++);
    pointer = UECSaddPGMChar(&(UECSccmFixSN6[0]), 20, pointer++);
    *(++pointer) = 0;
  }
  else if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRC1A[0]), 8)) != -1){    // <CCMSCAN
    point = _point + 1;
    int num = 0;
    if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRC2A[0]), 9)) != -1){       // /></UECS>
       check = true;
       num = 1;  
    }else if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRC2B[0]), 18)) != -1){   // ></CCMSCAN></UECS>
       check = true;
       num = 1;
    }else if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRC2C[0]), 7)) != -1){    // " page="" 
       point = _point + 1;
       while(point < bufsize){
         if((_buffer[point] >= '0') && (_buffer[point] <= '9')){
           num = num * 10 +  (_buffer[point] - 0x30);
         }
         else if(_buffer[point] == 10 || _buffer[point] == 13 || _buffer[point] == 32){
         }
         else if(_buffer[point] == 34){
           check = true;
           if(_maxccm < num){
             return false;
           }
           break;
         }
         else{
           return false;
         }
         point++;  
       }
       if(check){
         point++;
         if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRC2A[0]), 9)) != -1){
           
         }else if((_point = UECScheckPacketPGM(point, _buffer, bufsize, &(UECSccmFixRC2B[0]), 18)) != -1){
           
         }else{
           check = false;
         }
       }else{
         return false; 
       }     
    }else{
       return false;  
    }  // page loop
    if(check){
      // CCMSCANRES
      char* pointer = 0;
      pointer = UECSaddPGMChar(&(UECSccmFix0[0]), 42, _buffer);
      pointer = UECSaddPGMChar(&(UECSccmFixSC1[0]), 14, pointer++);
      unsigned int ccmNum = 0;
      for(int i = 0; i < _maxccm; i++){
        if(_ccmList[i].ccmLevel != NONE){
          ccmNum++;                 
        }
      }
      unsigned int resNum =0 ;
      if(num > 0 && num <= ccmNum){
        for(int i = 0; i < _maxccm; i++){   
          if(_ccmList[i].ccmLevel != NONE){
            resNum++;
            if(resNum == num){
              sprintf(_tempStr20, "%d", num);
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFixSC2[0]), 9, pointer++);
              sprintf(_tempStr20, "%d", ccmNum);
              pointer = UECSaddChar(_tempStr20, pointer++);

              pointer = UECSaddPGMChar(&(UECSccmFix5[0]), 2, pointer++);                         
              sprintf(_tempStr20, "%s", "1");
              pointer = UECSaddChar(_tempStr20, pointer++) ;                        
              pointer = UECSaddPGMChar(&(UECSccmFixSC3[0]), 18, pointer++); 
              sprintf(_tempStr20, "%d", num);
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFix1[0]), 8, pointer++);
              sprintf(_tempStr20, "%d", _ccmList[i].baseAttribute[0]);
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFix2[0]), 10, pointer++);                          
              sprintf(_tempStr20, "%d", _ccmList[i].baseAttribute[1]);
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFix3[0]), 9, pointer++);                          
              sprintf(_tempStr20, "%d", _ccmList[i].baseAttribute[2]);
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFix4[0]), 12, pointer++);                          
              sprintf(_tempStr20, "%d", _ccmList[i].attribute[3]);
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFixSC4[0]), 8, pointer++);                          
              sprintf(_tempStr20, "%d", _ccmList[i].decimal);
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFixSC5[0]), 8, pointer++);                          
              strcpy_P(_tempStr20, _ccmList[i].unit);
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFixSC6[0]), 6, pointer++);   
              if(_ccmList[i].sender){
                sprintf(_tempStr20, "%s", "S");  
              }
              else{
                sprintf(_tempStr20, "%s", "R");  
              }              
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFixSC7[0]), 6, pointer++);                          
              strcpy_P(_tempStr20, (char*)pgm_read_word(&(UECSCCMLEVEL[_ccmList[i].ccmLevel])));
              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddPGMChar(&(UECSccmFix5[0]), 2, pointer++);
//              strcpy_P(_tempStr20, _ccmList[i].type);
//              pointer = UECSaddChar(_tempStr20, pointer++);
              pointer = UECSaddTempChar(_ccmList[i].type, _tempStr20, pointer++);
 
              pointer = UECSaddPGMChar(&(UECSccmFixSC8[0]), 13, pointer++);                             
              *(++pointer) = 0;
              check = true;
            }                 
          }
        }      
      }    
    }
  }   
  if(check){ 

     return true;
  }else{

    return false;
  }
}

void UECSautomaticSendAndValidManager(UECSCCM* _ccm, unsigned char _counter60s, unsigned long _nowmillis){

	
  if(_ccm->ccmLevel != NONE){ 
    if(_ccm->sender){
      if(_ccm->ccmLevel == UECS_A_1S_0 || _ccm->ccmLevel == UECS_A_1S_1 || _ccm->ccmLevel == UECS_S_1S_0){
        _ccm->flagStimeRfirst = true;
       }
       else if((_counter60s % 10 == 0) && (_ccm->ccmLevel == UECS_A_10S_0 || _ccm->ccmLevel == UECS_A_10S_1)){
         _ccm->flagStimeRfirst = true;
       }
       else if(_counter60s == 0 && (_ccm->ccmLevel == UECS_A_1M_0 || _ccm->ccmLevel == UECS_A_1M_1 || _ccm->ccmLevel == UECS_S_1M_0)){
         _ccm->flagStimeRfirst = true;
       }
       else{
         _ccm->flagStimeRfirst = false;
       }
    }else{
       if((_nowmillis - _ccm->recmillis > _ccm->validmillis * 3) || (_ccm->flagStimeRfirst == false)){
         _ccm->validity = false;  
       }
       else{
         _ccm->validity = true;
       }       
    }
  } 
}

