/*******************************************************************************
 * Copyright (c) 2005 - 2015 ACIN, Profactor GmbH, fortiss GmbH
 *                      2018 Johannes Kepler University
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Alois Zoitl, Rene Smodic, Thomas Strasser, Gerhard Ebenhofer,
 *   Oliver Hummer, Ingo Hegny, Michael Hofmann, Martin Melik Merkumians
 *    - initial API and implementation and/or initial documentation
 *   Monika Wenger
 *    - fix: apostrophes are deleted in parseWriteConnectionData
 *   Jens Reimann
 *    - Enhance bootfile loading behavior
 *    Alois Zoitl - introduced new CGenFB class for better handling generic FBs
 *******************************************************************************/
#include <string.h>
#include "DEV_MGR.h"
#ifdef FORTE_ENABLE_GENERATED_SOURCE_CPP
#include "DEV_MGR_gen.cpp"
#endif
#include "../../core/device.h"
#include <stdio.h>
#include <stdlib.h>
#include "ForteBootFileLoader.h"
#include "../../core/utils/string_utils.h"

DEFINE_FIRMWARE_FB(DEV_MGR, g_nStringIdDEV_MGR)

const CStringDictionary::TStringId DEV_MGR::scm_anDataInputNames[] = {g_nStringIdQI, g_nStringIdID, g_nStringIdRESP};

const CStringDictionary::TStringId DEV_MGR::scm_anDataInputTypeIds[] = {g_nStringIdBOOL, g_nStringIdWSTRING, g_nStringIdSTRING};

const CStringDictionary::TStringId DEV_MGR::scm_anDataOutputNames[] = {g_nStringIdQO, g_nStringIdSTATUS, g_nStringIdDST, g_nStringIdRQST};

const CStringDictionary::TStringId DEV_MGR::scm_anDataOutputTypeIds[] = {g_nStringIdBOOL, g_nStringIdSTRING, g_nStringIdSTRING, g_nStringIdSTRING};

const TForteInt16 DEV_MGR::scm_anEIWithIndexes[] = {0, -1};
const TDataIOID DEV_MGR::scm_anEIWith[] = {0, 1, 255};
const CStringDictionary::TStringId DEV_MGR::scm_anEventInputNames[] = {g_nStringIdINIT, g_nStringIdREQ};

const TDataIOID DEV_MGR::scm_anEOWith[] = {0, 1, 255, 2, 3, 255};
const TForteInt16 DEV_MGR::scm_anEOWithIndexes[] = {0, -1, 3};
const CStringDictionary::TStringId DEV_MGR::scm_anEventOutputNames[] = {g_nStringIdINITO, g_nStringIdCNF};

const SFBInterfaceSpec DEV_MGR::scm_stFBInterfaceSpec = {
  2,  scm_anEventInputNames,  scm_anEIWith,  scm_anEIWithIndexes,
  2,  scm_anEventOutputNames,  scm_anEOWith, scm_anEOWithIndexes,  3,  scm_anDataInputNames, scm_anDataInputTypeIds,
  4,  scm_anDataOutputNames, scm_anDataOutputTypeIds,
  0, 0
};

const char * const DEV_MGR::scm_sMGMResponseTexts[13] = { "RDY", "BAD_PARAMS", "LOCAL_TERMINATION", "SYSTEM_TERMINATION", "NOT_READY", "UNSUPPORTED_CMD", "UNSUPPORTED_TYPE", "NO_SUCH_OBJECT", "INVALID_OBJECT", "INVALID_OPERATION", "INVALID_STATE", "OVERFLOW", "INVALID_DST" };

void DEV_MGR::executeEvent(int paEIID){
  if(scm_nEventINITID == paEIID){
#ifdef FORTE_SUPPORT_BOOT_FILE
    if((true == QI()) && (false == QO())){
      //this is the first time init is called try to load a boot file
      ForteBootFileLoader loader(*this);
      if(loader.isOpen() && LOAD_RESULT_OK == loader.loadBootFile()){
          DEVLOG_INFO("Bootfile correctly loaded\n");
      }
    }
#endif
    CCommFB::executeEvent(paEIID);  //initialize the underlying server FB
  }else{
    if(cg_nExternalEventID == paEIID && //we received a message on the network let the server correctly handle it
        forte::com_infra::e_ProcessDataOk == CCommFB::receiveData()){ //the message was correctly received
      executeRQST();
      //send response
      CCommFB::sendData();
    }
  }
}

void DEV_MGR::executeRQST(void){
  mCommand.mAdditionalParams.clear();
  EMGMResponse resp = parseAndExecuteMGMCommand(DST().getValue(), RQST().getValue());

#ifdef FORTE_SUPPORT_MONITORING
  if (0 != mCommand.mMonitorResponse.length()) {
    generateMonitorResponse(resp, mCommand);
  } else
#endif //FORTE_SUPPORT_MONITORING
  if(0 < mCommand.mAdditionalParams.length()){
    generateLongResponse(resp, mCommand);
  }
  else{
    generateResponse(mCommand.mID, resp);
  }
}

char *DEV_MGR::parseRequest(char *paRequestString, forte::core::SManagementCMD &paCommand){
//first check if it is an management request
  char *acCommandStart = 0;
  static const int scnCommandLength[] = {7, 7, 6, 5, 5, 6, 5, 6, 6};

  if(!strncmp("<Request ID=\"", paRequestString, 13)){
    int i = 13;
    int j;
    paCommand.mID = &(paRequestString[i]);
    for(j = 0; paRequestString[i] != '\"'; ++i, ++j){
      if(j >= 7){
        return 0;
      }
    }
    paRequestString[i] = '\0'; //close ID
    ++i;
    acCommandStart = strchr((&paRequestString[i]), '\"');
    if(acCommandStart != 0){
      acCommandStart++; //this is the real start of the command
      if(!strncmp("CREATE", acCommandStart, 6)){
        paCommand.mCMD = cg_nMGM_CMD_Create_Group;
      }
      else if(!strncmp("DELETE", acCommandStart, 6)){
        paCommand.mCMD = cg_nMGM_CMD_Delete_Group;
      }
      else if(!strncmp("START", acCommandStart, 5)){
        paCommand.mCMD = cg_nMGM_CMD_Start;
      }
      else if(!strncmp("STOP", acCommandStart, 4)){
        paCommand.mCMD = cg_nMGM_CMD_Stop;
      }
      else if(!strncmp("KILL", acCommandStart, 4)){
        paCommand.mCMD = cg_nMGM_CMD_Kill;
      }
      else if(!strncmp("RESET", acCommandStart, 5)){
        paCommand.mCMD = cg_nMGM_CMD_Reset;
      }
      else if(!strncmp("READ", acCommandStart, 4)){
        paCommand.mCMD = cg_nMGM_CMD_Read;
      }
      else if(!strncmp("WRITE", acCommandStart, 5)){
        paCommand.mCMD = cg_nMGM_CMD_Write;
      }
#ifdef FORTE_SUPPORT_QUERY_CMD
      else if(!strncmp("QUERY", acCommandStart, 5)){
        paCommand.mCMD = cg_nMGM_CMD_Query_Group;
      }
#endif
      else{
        return 0;
      }
      acCommandStart += scnCommandLength[paCommand.mCMD];
    }
  }
  return acCommandStart;
}

#ifdef FORTE_DYNAMIC_TYPE_LOAD
bool DEV_MGR::parseXType(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand, const char *paRequestType) {
  bool retVal = false;
  size_t nReqLength = strlen(paRequestType);
  if(!strncmp(paRequestType, paRequestPartLeft, nReqLength)){
    paRequestPartLeft = &(paRequestPartLeft[nReqLength]);
    if('*' != paRequestPartLeft[0]){
      int i = parseIdentifier(paRequestPartLeft, paCommand.mFirstParam);
      paRequestPartLeft = (-1 == i) ? 0 : strchr(&(paRequestPartLeft[i + 1]), '>');
    }
    if(0 != paRequestPartLeft){
      paRequestPartLeft++;
      char* endOfRequest = strchr(paRequestPartLeft, '<');
      *endOfRequest = '\0';
      forte::core::util::transformEscapedXMLToNonEscapedText(paRequestPartLeft);
      paCommand.mAdditionalParams = paRequestPartLeft;
      retVal = true;
    }
  }
  return retVal;
}
#endif

bool DEV_MGR::parseFBData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  bool retVal = false;

  if(!strncmp("FB Name=\"", paRequestPartLeft, 9)){
    char *acBuf = &(paRequestPartLeft[9]);
    int i = 0;
    if(acBuf[0] != '*'){
      i = parseIdentifier(acBuf, paCommand.mFirstParam);
      acBuf = (-1 == i) ? 0 : strchr(&(acBuf[i + 1]), '\"');
    }
    else{
      acBuf = strchr(&(acBuf[i + 2]), '\"');
    }

    if(acBuf != 0){
      if(acBuf[1] != '*'){
        ++acBuf;
        i = parseIdentifier(acBuf, paCommand.mSecondParam);
        if(-1 != i){
          acBuf = strchr(&(acBuf[i + 1]), '\"');
          if(acBuf != 0){
            // We have an application name given
            ++acBuf;
            TForteUInt16 nBufLength = static_cast<TForteUInt16>(strcspn(acBuf, "\"") + 1);
            paCommand.mAdditionalParams.assign(acBuf, nBufLength);
          }
        }
        else{
          return false;
        }
      }
      retVal = true;
    }
  }
  return retVal;
}

int DEV_MGR::parseIdentifier(char *paIdentifierStart, forte::core::TNameIdentifier &paIdentifier){
  for(char *runner = paIdentifierStart, *start = paIdentifierStart; '\0' != *runner; ++runner){
    if('.' == *runner){
      *runner = '\0';
      if(!paIdentifier.pushBack(CStringDictionary::getInstance().insert(start))){
        return -1;
      }
      *runner = '.';
      start = runner + 1;
    } else if ('"' == *runner){
      *runner = '\0';
      if(!paIdentifier.pushBack(CStringDictionary::getInstance().insert(start))){
        return -1;
      }
      *runner = '"';
      return static_cast<int>(runner - paIdentifierStart);
    }
  }
  return -1;
}

bool DEV_MGR::parseConnectionData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  bool bRetVal = false;
  if(!strncmp("Connection Source=\"", paRequestPartLeft, sizeof("Connection Source=\"") - 1)){
    int i = parseIdentifier(&(paRequestPartLeft[19]), paCommand.mFirstParam);
    if(-1 != i){
      char *acBuf = strchr(&(paRequestPartLeft[i + 21]), '\"');
      if(acBuf != 0){
        parseIdentifier(&(acBuf[1]), paCommand.mSecondParam);
        bRetVal = (-1 != i);
      }
    }
  }
  return bRetVal;
}

bool DEV_MGR::parseWriteConnectionData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  bool retVal = false;
  if(!strncmp("Connection Source=\"", paRequestPartLeft, sizeof("Connection Source=\"") - 1)){
    paRequestPartLeft = &(paRequestPartLeft[19]);

    char* endOfSource = strchr(paRequestPartLeft, '\"');
    if(0 == endOfSource){
      return false;
    }
    *endOfSource = '\0';
    forte::core::util::transformEscapedXMLToNonEscapedText(paRequestPartLeft);
    paCommand.mAdditionalParams = paRequestPartLeft;
    *endOfSource = '"'; // restore the string
    paRequestPartLeft = strchr(endOfSource + 1, '\"');
    if(0 != paRequestPartLeft){
      retVal = (-1 != parseIdentifier(&paRequestPartLeft[1], paCommand.mFirstParam));
    }
  }
  return retVal;
}

void DEV_MGR::parseCreateData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  paCommand.mCMD = cg_nMGM_CMD_INVALID;
  if(0 != paRequestPartLeft){
      switch (paRequestPartLeft[0]){
#ifdef FORTE_DYNAMIC_TYPE_LOAD
        case 'A': // we have an Adapter to Create
          if(parseXType(paRequestPartLeft, paCommand, "AdapterType Name=\"")){
            paCommand.mCMD = cg_nMGM_CMD_Create_AdapterType;
          }
          break;
#endif
        case 'F': // we have an FB to Create
          if(parseFBData(paRequestPartLeft, paCommand)){
            paCommand.mCMD = cg_nMGM_CMD_Create_FBInstance;
          }
#ifdef FORTE_DYNAMIC_TYPE_LOAD
          else if(parseXType(paRequestPartLeft, paCommand, "FBType Name=\"")){
            paCommand.mCMD = cg_nMGM_CMD_Create_FBType;
          }
#endif
          break;
        case 'C': // we have an Connection to Create
          if(parseConnectionData(paRequestPartLeft, paCommand)){
            paCommand.mCMD = cg_nMGM_CMD_Create_Connection;
          }
          break;
#ifdef FORTE_SUPPORT_MONITORING
        case 'W': // we have an Watch to Add
          if(parseMonitoringData(paRequestPartLeft, paCommand)){
            paCommand.mCMD = cg_nMGM_CMD_Monitoring_Add_Watch;
          }
          break;
#endif //FORTE_SUPPORT_MONITORING
        default:
          break;
      }
  }
}

void DEV_MGR::parseDeleteData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  paCommand.mCMD = cg_nMGM_CMD_INVALID;
  if(0 != paRequestPartLeft){
    switch (paRequestPartLeft[0]){
      case 'F': // we have an FB to delete
        if(parseFBData(paRequestPartLeft, paCommand)){
          paCommand.mCMD = cg_nMGM_CMD_Delete_FBInstance;
        }
        break;
      case 'C': // we have an Connection to delete
        if(parseConnectionData(paRequestPartLeft, paCommand)){
          paCommand.mCMD = cg_nMGM_CMD_Delete_Connection;
        }
        break;
#ifdef FORTE_SUPPORT_MONITORING
      case 'W': // we have an Watch to remove
        if(parseMonitoringData(paRequestPartLeft, paCommand)){
           paCommand.mCMD = cg_nMGM_CMD_Monitoring_Remove_Watch;
        }
        break;
#endif // FORTE_SUPPORT_MONITORING
      default:
        break;
    }
  }
}

void DEV_MGR::parseAdditionalStateCommandData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  if(0 != paRequestPartLeft && '/' != paRequestPartLeft[0] && //if we have an additional xml token parse if it is an FB definition
    !parseFBData(paRequestPartLeft, paCommand)) {
    paCommand.mCMD = cg_nMGM_CMD_INVALID;
  }
}

void DEV_MGR::parseReadData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  paCommand.mCMD = cg_nMGM_CMD_INVALID;
  if(0 != paRequestPartLeft){
#ifdef FORTE_SUPPORT_MONITORING
    if('W' == paRequestPartLeft[0]){
          paCommand.mCMD = cg_nMGM_CMD_Monitoring_Read_Watches;
    } else
#endif // FORTE_SUPPORT_MONITORING
      if(parseConnectionData(paRequestPartLeft, paCommand)){
        paCommand.mCMD = cg_nMGM_CMD_Read;
      }
  }
}

void DEV_MGR::parseWriteData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  //We need an additional xml connection token parse if it is an connection definition
  paCommand.mCMD = cg_nMGM_CMD_INVALID;
  if(0 != paRequestPartLeft && parseWriteConnectionData(paRequestPartLeft, paCommand)){
#ifdef FORTE_SUPPORT_MONITORING
    char *pch = strstr(paRequestPartLeft, "force=\"");
    if (0 != pch) {
      if (!strncmp(&pch[7], "true", sizeof("true") - 1)) {
        paCommand.mCMD = cg_nMGM_CMD_Monitoring_Force;
      } else if (!strncmp(&pch[7], "false", sizeof("false") - 1)) {
        paCommand.mCMD = cg_nMGM_CMD_Monitoring_ClearForce;
      }
    } else if ((2 == paCommand.mAdditionalParams.length()) &&
      (('$' == paCommand.mAdditionalParams.getValue()[0]) &&
        (('e' == paCommand.mAdditionalParams.getValue()[1]) ||('E' == paCommand.mAdditionalParams.getValue()[1]) ))){
      paCommand.mCMD = cg_nMGM_CMD_Monitoring_Trigger_Event;
    }else if ((3 == paCommand.mAdditionalParams.length()) &&
      (('$' == paCommand.mAdditionalParams.getValue()[0]) &&
       (('e' == paCommand.mAdditionalParams.getValue()[1]) ||('E' == paCommand.mAdditionalParams.getValue()[1]) ) &&
       (('r' == paCommand.mAdditionalParams.getValue()[2]) ||('R' == paCommand.mAdditionalParams.getValue()[2]) ) )){
      paCommand.mCMD = cg_nMGM_CMD_Monitoring_Reset_Event_Count;
    }else
#endif // FORTE_SUPPORT_MONITORING
      paCommand.mCMD = cg_nMGM_CMD_Write;
  }
}

#ifdef FORTE_SUPPORT_QUERY_CMD
void DEV_MGR::parseQueryData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  paCommand.mCMD = cg_nMGM_CMD_INVALID;
  if(0 != paRequestPartLeft){
    switch (paRequestPartLeft[0]){
      case 'F': // query fb or fb type list
        if(!strncmp(paRequestPartLeft, "FBT", sizeof("FBT") - 1)){
          if(parseTypeListData(paRequestPartLeft, paCommand)){
            paCommand.mCMD = cg_nMGM_CMD_QUERY_FBTypes;
          }
#ifdef FORTE_DYNAMIC_TYPE_LOAD
          else if(parseXType(paRequestPartLeft, paCommand, "FBType Name=\"")){
            paCommand.mCMD = cg_nMGM_CMD_QUERY_FBType;
          }
#endif
          else {
            paCommand.mCMD = cg_nMGM_CMD_Query_Group;
          }
        }else if(parseFBData(paRequestPartLeft, paCommand)){
          paCommand.mCMD = cg_nMGM_CMD_QUERY_FB;
        }
        break;
      case 'C': // query connection list
        if(parseConnectionData(paRequestPartLeft, paCommand)){
          paCommand.mCMD = cg_nMGM_CMD_QUERY_Connection;
        }
        break;
      case 'D': // query datatype list
        if(!strncmp(paRequestPartLeft, "DataType", sizeof("DataType") - 1)){
          if(parseTypeListData(paRequestPartLeft, paCommand)){
            paCommand.mCMD = cg_nMGM_CMD_QUERY_DTTypes;
          } else {
            paCommand.mCMD = cg_nMGM_CMD_Query_Group;
          }
        }
        break;
      case 'A': // query adaptertype list
        if(!strncmp(paRequestPartLeft, "AdapterT", sizeof("AdapterT") - 1)){
          if(parseTypeListData(paRequestPartLeft, paCommand)){
            paCommand.mCMD = cg_nMGM_CMD_QUERY_AdapterTypes;
          }
#ifdef FORTE_DYNAMIC_TYPE_LOAD
          else if(parseXType(paRequestPartLeft, paCommand, "AdapterType Name=\"")){
            paCommand.mCMD = cg_nMGM_CMD_QUERY_AdapterType;
          }
#endif
          else {
            paCommand.mCMD = cg_nMGM_CMD_Query_Group;
          }
        }

        break;
      default:
        break;
    }
  }
}

bool DEV_MGR::parseTypeListData(char *paRequestPartLeft, forte::core::SManagementCMD &){
  bool retVal = true;

  if (!strncmp("DataType Name=\"", paRequestPartLeft, sizeof("DataType Name=\"") - 1)) {
    if(paRequestPartLeft[15] != '*'){ //does not support query for DataType-Declaration
      retVal = false;
    }
  }
  else if(!strncmp("FBType Name=\"", paRequestPartLeft, sizeof("FBType Name=\"") - 1)){
    if(paRequestPartLeft[13] != '*'){ //supports query for FBType-Declaration only for DynamicTypeLoad profile (LUA enabled)
      retVal = false;
    }
  }
  else if(!strncmp("AdapterType Name=\"", paRequestPartLeft, sizeof("AdapterType Name=\"") - 1)){
    if(paRequestPartLeft[18] != '*'){ //does not support query for AdapterType-Declaration
      retVal = false;
    }
  }
  return retVal;
}
#endif

void DEV_MGR::generateResponse(const char *paID, EMGMResponse paResp){
  RESP().clear();
  RESP().append("<Response ID=\"");
  if (0 != paID) {
    RESP().append(paID);
  }
  RESP().append("\"");
  if(e_RDY != paResp){
    RESP().append(" Reason=\"");
    RESP().append(scm_sMGMResponseTexts[paResp]);
    RESP().append("\"");
  }
  RESP().append(" />");
}

void DEV_MGR::generateLongResponse(EMGMResponse paResp, forte::core::SManagementCMD &paCMD){
  RESP().clear();
  RESP().reserve(static_cast<TForteUInt16>(255 + (paCMD.mAdditionalParams.length())));
  RESP().append("<Response ID=\"");
  if (0 != paCMD.mID) {
    RESP().append(paCMD.mID);
  }
  RESP().append("\"");
  if(e_RDY != paResp){
    RESP().append(" Reason=\"");
    RESP().append(scm_sMGMResponseTexts[paResp]);
    RESP().append("\">\n  ");
  }
  else{
    RESP().append(">\n  ");
    if(paCMD.mCMD == cg_nMGM_CMD_Read){
      RESP().append("<Connection Source=\"");
      appedIdentifierName(RESP(), paCMD.mFirstParam);
      RESP().append("\" Destination=\"");
      RESP().append(paCMD.mAdditionalParams.getValue());
      RESP().append("\" />");
    }
#ifdef FORTE_SUPPORT_QUERY_CMD
    else if(paCMD.mCMD == cg_nMGM_CMD_QUERY_Connection){
      if ((paCMD.mFirstParam.isEmpty()) &&
          (paCMD.mSecondParam.isEmpty())) { //src & dst = *
          RESP().append(paCMD.mAdditionalParams.getValue());
      }
      else { //either src or dst = * (both != * should be treated by generateResponse
        RESP().append("<EndpointList>\n    ");
        RESP().append(paCMD.mAdditionalParams.getValue());
        RESP().append("\n  </EndpointList>");
      }
    }
    else if(paCMD.mCMD == cg_nMGM_CMD_QUERY_FB){
      if(!paCMD.mFirstParam.isEmpty()) {  //Name != "*"
        if(!paCMD.mSecondParam.isEmpty()){ //Type != "*"
          RESP().append("<FBStatus Status=\"");
          RESP().append(paCMD.mAdditionalParams.getValue());
          RESP().append("\" />");
        } else { //Type == "*"
          RESP().append("<FB Name=\"");
          appedIdentifierName(RESP(), paCMD.mFirstParam);
          RESP().append("\" Type=\"");
          RESP().append(paCMD.mAdditionalParams.getValue());
          RESP().append("\" />");
        }
      }
      else{
        RESP().append("<FBList>\n    ");
        RESP().append(paCMD.mAdditionalParams.getValue());
        RESP().append("\n  </FBList>");
      }
    }
    else if(paCMD.mCMD == cg_nMGM_CMD_QUERY_FBTypes || paCMD.mCMD == cg_nMGM_CMD_QUERY_AdapterTypes){
      RESP().append("<NameList>\n    ");
      RESP().append(paCMD.mAdditionalParams.getValue());
      RESP().append("\n  </NameList>");
    }
    else if(paCMD.mCMD == cg_nMGM_CMD_QUERY_DTTypes){
      RESP().append("<DTList>\n    ");
      RESP().append(paCMD.mAdditionalParams.getValue());
      RESP().append("\n  </DTList>");
    }
    else if(paCMD.mCMD == cg_nMGM_CMD_QUERY_FBType){
      RESP().append("<FBType Comment=\"generated\" ");
      RESP().append(paCMD.mAdditionalParams.getValue());
      RESP().append("  </FBType>");
    }
    else if(paCMD.mCMD == cg_nMGM_CMD_QUERY_AdapterType){
      RESP().append("<AdapterType Comment=\"generated\" ");
      RESP().append(paCMD.mAdditionalParams.getValue());
      RESP().append("   <Service Comment=\"generated\" LeftInterface=\"SOCKET\" RightInterface=\"PLUG\"/>\n</AdapterType>");
    }
#endif
  }
  RESP().append("\n</Response>");
}

void DEV_MGR::appedIdentifierName(CIEC_STRING& paDest, forte::core::TNameIdentifier &paIdentifier){
  if(!paIdentifier.isEmpty()){
    for(forte::core::TNameIdentifier::CIterator runner(paIdentifier.begin());
        runner != paIdentifier.end(); ++runner){
      paDest.append(CStringDictionary::getInstance().get(*runner));
      paDest.append(".");
    }
    paDest.append(CStringDictionary::getInstance().get(paIdentifier.back()));
  }
}

DEV_MGR::DEV_MGR(CStringDictionary::TStringId paInstanceNameId, CResource *paSrcRes) :
    CCommFB(paInstanceNameId, paSrcRes, forte::com_infra::e_Server),
    m_poDevice(paSrcRes->getDevice()) {
  setupFBInterface(&scm_stFBInterfaceSpec, m_anFBConnData, m_anFBVarsData);
  mCommand.mAdditionalParams.reserve(255);
  mCommand.mAdditionalParams.clear();
}

DEV_MGR::~DEV_MGR(){
  freeAllData();
  m_pstInterfaceSpec = 0;  //block any wrong cleanup in the generic fb base class of CBaseCommFB
}

EMGMResponse DEV_MGR::parseAndExecuteMGMCommand(char *paDest, char *paCommand){
  EMGMResponse eResp = e_INVALID_OBJECT;
  if(0 != strchr(paCommand, '>')){
    mCommand.mDestination = (strlen(paDest) != 0) ? CStringDictionary::getInstance().insert(paDest) : CStringDictionary::scm_nInvalidStringId;
    mCommand.mFirstParam.clear();
    mCommand.mSecondParam.clear();
    if ( 255 <= mCommand.mAdditionalParams.getCapacity()) {
      mCommand.mAdditionalParams.reserve(255);
    }
    mCommand.mID=0;
#ifdef FORTE_SUPPORT_MONITORING
  mCommand.mMonitorResponse.clear();
#endif // FORTE_SUPPORT_MONITORING
    char *acRequestPartLeft = parseRequest(paCommand, mCommand);
    if(0 != acRequestPartLeft){
      acRequestPartLeft = strchr(acRequestPartLeft, '<');
      if(0 != acRequestPartLeft){
        acRequestPartLeft++; //point to the next character after the <
      }
      // we got the command for execution
      // now check the rest of the data
      switch (mCommand.mCMD){
        case cg_nMGM_CMD_Create_Group: // create something
          parseCreateData(acRequestPartLeft, mCommand);
          break;
        case cg_nMGM_CMD_Delete_Group: //delete something
          parseDeleteData(acRequestPartLeft, mCommand);
          break;
        case cg_nMGM_CMD_Start:
        case cg_nMGM_CMD_Stop:
        case cg_nMGM_CMD_Kill:
        case cg_nMGM_CMD_Reset:
          parseAdditionalStateCommandData(acRequestPartLeft, mCommand);
          break;
        case cg_nMGM_CMD_Read:
          parseReadData(acRequestPartLeft, mCommand);
          break;
        case cg_nMGM_CMD_Write:
          parseWriteData(acRequestPartLeft, mCommand);
          break;
#ifdef FORTE_SUPPORT_QUERY_CMD
        case cg_nMGM_CMD_Query_Group: // query something
          parseQueryData(acRequestPartLeft, mCommand);
#endif
          break;
        default:
          break;
      }

      if(cg_nMGM_CMD_INVALID != mCommand.mCMD) {
          eResp = m_poDevice.executeMGMCommand(mCommand);
      }
    }
    else {
      eResp = e_UNSUPPORTED_CMD;
    }
  }
  return eResp;
}

#ifdef FORTE_SUPPORT_MONITORING

bool DEV_MGR::parseMonitoringData(char *paRequestPartLeft, forte::core::SManagementCMD &paCommand){
  bool bRetVal = false;
  if(!strncmp("Watch Source=\"", paRequestPartLeft, sizeof("Watch Source=\"") - 1)){
    int i = parseIdentifier(&(paRequestPartLeft[14]), paCommand.mFirstParam);
    if(-1 != i){
      char *acBuf = strchr(&(paRequestPartLeft[i + 16]), '\"');
      if(acBuf != 0){
        parseIdentifier(&(acBuf[1]), paCommand.mSecondParam);
        bRetVal = (-1 != i);
      }
    }
  }
  return bRetVal;
}

void DEV_MGR::generateMonitorResponse(EMGMResponse paResp, forte::core::SManagementCMD &paCMD){
  RESP().clear();
  if(e_RDY != paResp){
    RESP().append("<Response ID=\"");
    RESP().append(paCMD.mID);
    RESP().append("\"");
    RESP().append(" Reason=\"");
    RESP().append(scm_sMGMResponseTexts[paResp]);
    RESP().append("\">\n  ");
    RESP().append("\n</Response>");
  }else{
    TForteUInt16 size = static_cast<TForteUInt16>(paCMD.mMonitorResponse.length() + strlen(paCMD.mID) + 74);
    RESP().reserve(size);

    RESP().clear();
    RESP().append("<Response ID=\"");
    RESP().append(paCMD.mID);
    RESP().append("\"");
    RESP().append(">\n  ");
    if(paCMD.mCMD == cg_nMGM_CMD_Monitoring_Read_Watches) {
      RESP().append("<Watches>\n    ");
      RESP().append(paCMD.mMonitorResponse.getValue());
      RESP().append("\n  </Watches>");
    }
    RESP().append("\n</Response>");
  }
  paCMD.mMonitorResponse.clear();
}

#endif // FORTE_SUPPORT_MONITORING

bool DEV_MGR::executeCommand(char *paDest, char *paCommand){
  EMGMResponse eResp = parseAndExecuteMGMCommand(paDest, paCommand);
  if(eResp != e_RDY){
    DEVLOG_ERROR("Boot file error. DEV_MGR says error is %s\n", DEV_MGR::scm_sMGMResponseTexts[eResp]);
  }
  return (eResp == e_RDY);
}
