// TM.cpp: implementation of the CTM class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CTMS.h"
#include "TM.h"

class CCTMSApp;

//////////////////////////////////////////////////////////////////////
// Thread funciton wich handles asynchronous communication
//////////////////////////////////////////////////////////////////////
static DWORD WINAPI ThreadFuncIG745(void *parameter)
{

  CTM *tm = (CTM *)parameter;


  //keep on running until the end....
  while (!tm->ThreadShutdown())
  {

    //do the communication
    tm->Communication();

    //don't use all the system time!!!
    Sleep( 50);
  } //shutdown wanted

  //end of thread
  return 0;
}



//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTM::CTM( char *id)
{

  PHOSTENT ph;
  char section[80];
  char key[80];
  CString sVal;
  int iVal;
  CString sIp;

  memset( (void *)para_ParaS, 0, sizeof(para_ParaS));
  memset( (void *)para_StatisticalS, 0, sizeof(para_StatisticalS));

  m_time[1] = m_time[0] = 0;
  m_iLifeTime = 0;
  m_iSequenceNr = 0;
  m_iConnected = 0;

  strncpy( m_sId, id+2, 2);
  m_sId[2] = '\0';
  m_sSocket = INVALID_SOCKET;
  m_lThread = 0;
  SetConnectionState( 0);
  m_iSendRecv = 0;

  strcpy( section, "TM-sim");
  strcpy( key, "IPaddress");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
  sIp = sVal;

  strcpy( key, "IM-name");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
  m_sImName = sVal;

  //protocol specific information
  strcpy( section, "PROTOCOL");
  strcpy( key, "Source");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "BC", true);
  strncpy( m_sSource, sVal, 2);

  strcpy( key, "Destination");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "IM", true);
  strncpy( m_sDestination, sVal, 2);

  strcpy( key, "Version");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "02", true);
  strncpy( m_sProtocolVersion, sVal, 2);

  strcpy( key, "Terminator");
  iVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetInteger( key, section, 10, true);
  m_sTerminator = (char)iVal;
    
  strcpy( key, "Delimiter");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, ";", true);
  m_sDelimiter = (char)sVal[0];

  strcpy( key, "LifeSignMsg");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "00", true);
  strncpy( m_sIdLifeSign, sVal, 2);

  strcpy( key, "ExceptionMsg");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "21", true);
  strncpy( m_sIdException, sVal, 2);
  
  strcpy( key, "CommandMsg");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "21", true);
  strncpy( m_sIdCommand, sVal, 2);

  strcpy( key, "StatusMsg");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "11", true);
  strncpy( m_sIdStatus, sVal, 2);

  strcpy( key, "ParameterMsg");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "02", true);
  strncpy( m_sIdParameter, sVal, 2);

  strcpy( key, "ParameterWriteMsg");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "03", true);
  strncpy( m_sIdParameter2, sVal, 2);

  strcpy( key, "StatisticalMsg");
  sVal = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "12", true);
  strncpy( m_sIdStatistical, sVal, 2);

  //TM specific information
  strcpy( section, id);
  strcpy( key, "AliveTime");
  m_sAliveTime = ((CCTMSApp *)AfxGetApp())->theINIFile.GetInteger( key, section, 45);
  m_sAliveTime *= 1000;

  strcpy( key, "RemotePort");
  m_iRemotePort = ((CCTMSApp *)AfxGetApp())->theINIFile.GetInteger( key, section, 7366, true);

  strcpy( key, "Name");
  m_sName = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, section, true);

  //find our default IP-address
  char buf[ 80];

  //get our own IP address
  if (gethostname ( buf, 80)) buf[0] = '\0';
  //if (gethostname ( buf, 80)) return FALSE;

  ph = gethostbyname( (char *)buf);

  //set out IP address
  if (ph)
    memcpy( (char *)&(m_wTMAddress.sin_addr), ph->h_addr_list[0], ph->h_length);

  m_wTMAddress.sin_family = AF_INET;
  //m_wAddress.sin_addr.s_addr = INADDR_ANY;

  if (sIp.GetLength() > 0)
  {

    int x = sIp.Find('.', 0);
    char *p = sIp.GetBuffer( 15);

    memset( &m_Ip, 0, sizeof( m_Ip));
    m_Ip.ip1 = (char)atoi( p);

    if (x > 0) 
    {
      
      m_Ip.ip2 = (char)atoi( &p[x+1]);
      x = sIp.Find('.', x+1);

      if (x > 0) 
      {

        m_Ip.ip3 = (char)atoi( &p[x+1]);
        x = sIp.Find('.', x+1);

        if (x > 0) 
         m_Ip.ip4 = (char)atoi( &p[x+1]);
      }
    }

    //check ini file, may user overides the hostname
    m_wTMAddress.sin_addr.S_un.S_un_b.s_b1 = m_Ip.ip1;
    m_wTMAddress.sin_addr.S_un.S_un_b.s_b2 = m_Ip.ip2;
    m_wTMAddress.sin_addr.S_un.S_un_b.s_b3 = m_Ip.ip3;
    m_wTMAddress.sin_addr.S_un.S_un_b.s_b4 = m_Ip.ip4;
  }    

  IniReadParameterI( "Command", para_Command, text_Command);
  IniReadParameterI( "Status", para_Status, text_Status);

  IniReadParameterI( "ParameterB", para_ParaB, text_ParaB);
  IniReadParameterI( "ParameterI", para_ParaI, text_ParaI);
  IniReadParameterL( "ParameterL", para_ParaL, text_ParaL);
  IniReadParameterR( "ParameterR", para_ParaR, text_ParaR);
  IniReadParameterS( "ParameterS", para_ParaS[0], text_ParaS);

  IniReadParameterI( "StatisticalB", para_StatisticalB, text_StatisticalB);
  IniReadParameterI( "StatisticalI", para_StatisticalI, text_StatisticalI);
  IniReadParameterL( "StatisticalL", para_StatisticalL, text_StatisticalL);
  IniReadParameterR( "StatisticalR", para_StatisticalR, text_StatisticalR);
  IniReadParameterS( "StatisticalS", para_StatisticalS[0], text_StatisticalS);

  //start communication thread
  Thread();
}



CTM::~CTM()
{

  unsigned long  ExitCode = (m_lThread == 0) ? 0: STILL_ACTIVE; 


  //let the thread close
  m_lThread = 0;

  //wait for the thread to close
  while (ExitCode == STILL_ACTIVE)
  {

    if (!GetExitCodeThread( m_hThreadHandle, &ExitCode)) break;
    Sleep( 10);
  } 

  //destroy the thread references
  if (m_hThreadHandle) CloseHandle( m_hThreadHandle);
}



/////////////////////////////////////////////////////////////////////////////
// Connect to TM, first sends connect, then waits for response.
/////////////////////////////////////////////////////////////////////////////
int CTM::Connect2TM(int port)
{
/*
     //fill structures with sockets to observe
      FD_ZERO( &efds);
      FD_SET( m_sSocket[ local*MAX_SOCK], &efds);
      FD_ZERO( &wfds);
      FD_SET( m_sSocket[ local*MAX_SOCK], &wfds);

      //connect is pending, wait for completion
      if ((i = select( 0, NULL, &wfds, &efds, &t)) == SOCKET_ERROR)
      {

        //declare all sockets invalid
        for (i = local*MAX_SOCK; i < ((local+1)*MAX_SOCK); i++)
          DeleteSocket( i);

        //try agein
        m_iConnectionState[ local] = 0;
      }
      else
      {

        //receive the port numbers
        if (i) 
        {
        
          //connection establshed?
          if (FD_ISSET( m_sSocket[ local*MAX_SOCK], &wfds))
            m_iConnectionState[ local] = 4;

          //just disconnect all the sockets and try again    
          if (FD_ISSET( m_sSocket[ local*MAX_SOCK], &efds))
            m_iConnectionState[ local] = 3;
        }
      }
      break;
*/

  int i;
//  FD_SET rfds;
//  FD_SET wfds;
//  FD_SET efds;
//  TIMEVAL t = {0, 0};
  unsigned char  buf[ 1024];
//  int len = 0;
//  int sock_idx;
//  int port_idx;

  
  //retrieve IP-address form INI-file, this is the default address
  //m_wTDIAddress.sin_addr.S_un.S_addr = inet_addr ( m_oINIFile.GetString( "IPTDILocal", "CTMS", "0.0.0.0"));

  //IP address defined in ini file, use this one
  //Address 0.0.0.0 will return FALSE, this means were gone find a network card
  //if (m_wTDIAddress.sin_addr.S_un.S_addr) return TRUE;

  //find our default IP-address
  PHOSTENT ph;

  //get our own IP address
  if (gethostname ( (char *)buf, 80)) buf[0] = '\0';
  //if (gethostname ( buf, 80)) return FALSE;

  ph = gethostbyname( (char *)buf);

  //set out IP address
  if (ph)
    memcpy( (char *)&(m_wTMAddress.sin_addr), ph->h_addr_list[0], ph->h_length);

  m_wTMAddress.sin_addr.S_un.S_un_b.s_b1 = m_Ip.ip1;
  m_wTMAddress.sin_addr.S_un.S_un_b.s_b2 = m_Ip.ip2;
  m_wTMAddress.sin_addr.S_un.S_un_b.s_b3 = m_Ip.ip3;
  m_wTMAddress.sin_addr.S_un.S_un_b.s_b4 = m_Ip.ip4;

  m_wTMAddress.sin_family = AF_INET;
  //m_wAddress.sin_addr.s_addr = INADDR_ANY;

  //local we don't care about the port number
  m_wTMAddress.sin_port = htons( (u_short)0);

  //create a socket
  CreateSocket();

  //bind the socket to the local port
  if (!(i = bind( m_sSocket, (SOCKADDR *)&m_wTMAddress, sizeof( m_wTMAddress))))
  {

    m_wRemoteAddress.sin_port = htons( (u_short)port);
    m_wRemoteAddress.sin_family = AF_INET;
    m_wRemoteAddress.sin_addr.s_addr = INADDR_ANY;

    ph = gethostbyname( m_sImName);
    if (ph)
      memcpy( (char *)&(m_wRemoteAddress.sin_addr), ph->h_addr_list[0], ph->h_length);

    //connect to remote CTMS
    if ((i = connect( m_sSocket, (SOCKADDR *) &m_wRemoteAddress, sizeof( m_wRemoteAddress))))
    {


      i = WSAGetLastError();
      if (i == WSAEWOULDBLOCK) 
      {

        //Sleep( 5000);
        return TRUE;
        //i = connect( m_sSocket, (SOCKADDR *) &m_wRemoteAddress, sizeof( m_wRemoteAddress));
        //i = WSAGetLastError();
      }

    //check if connection is pending
    //if (WSAGetLastError() == WSAEWOULDBLOCK) m_iConnectionState[ local] = 2;
    return FALSE;
    }
  }
  else
  {
    //just get the error, and destroy socket
    i = WSAGetLastError();
    DestroySocket();
  }

  //we are now connected on TCP/IP level
  return TRUE;
} //Connect2TM


/////////////////////////////////////////////////////////////////////////////
// Open a socket for use, set all options etc.
// An index is supplied to get all four connections (1 .. 4) and zero
// for the common connection.
/////////////////////////////////////////////////////////////////////////////
void CTM::CreateSocket()
{

  struct LINGER;
  unsigned long opt; 

  //only if we have a closed socket
  if (m_sSocket != INVALID_SOCKET) return;

  //open the socket
  m_sSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_IP);

  //set the options we need
  if (m_sSocket != INVALID_SOCKET)
  {

    opt = TRUE;
    setsockopt( m_sSocket, SOL_SOCKET, SO_DONTLINGER, (char *)&opt, sizeof( opt));

    //non blocking mode
    opt = (unsigned long)-1;
    ioctlsocket( m_sSocket, FIONBIO, &opt);
  }
}

/////////////////////////////////////////////////////////////////////////////
// Disconnect and close socket
/////////////////////////////////////////////////////////////////////////////
void CTM::DestroySocket()
{

  //disconnect and close socket
  if (m_sSocket != INVALID_SOCKET)
  {
    shutdown( m_sSocket, FD_READ|FD_WRITE);
    closesocket( m_sSocket);
  }

  m_sSocket = INVALID_SOCKET;
}

//Communication function, just continiously call this function
void CTM::Communication()
{
  int type;
  char buf[4096];

  m_time[1] = m_time[0];
  m_time[0] = clock();
  
  m_iLifeTime += ((m_time[0] - m_time[1]) > 1000 ? 1000: (m_time[0] - m_time[1]));
  

  switch (GetConnectState())
  {
    case 0: //no connection
      if (m_iLifeTime >= m_sAliveTime)
        if (Connect2TM( m_iRemotePort)) SetConnectionState( 1);
      break;
    case 1: //connection in progress
      CheckConnection();

    case 2: //normal connection, send lifesign, and go to normal mode
      if (SendLifeSign()) SetConnectionState( 3);
      else SetConnectionState( 0);
      break;
    case 3: //normal connection, send lifesign, and go to normal mode
      if (m_iLifeTime >= m_sAliveTime)
      {

        if (SendLifeSign()) SetConnectionState( 3);
        else SetConnectionState( 0);
      }

        RecvMessage( buf, &type);
        break;
    default:
      SetConnectionState( 0);
      break;
  }

  if ((m_iLifeTime >= m_sAliveTime) || (m_iLifeTime < 0))
    m_iLifeTime = 0;
}


//////////////////////////////////////////////////////////////////////
// Thread function, used only to startup a thread
//////////////////////////////////////////////////////////////////////
int CTM::Thread()
{

  
  //create the thread with function ThreadFuncIG745
  if (m_lThread == 0)
    m_hThreadHandle = CreateThread( NULL, 0, ThreadFuncIG745, this, 0, &m_lThread);

  return m_lThread;
}

//////////////////////////////////////////////////////////////////////
// Report if thread should be shutting down
//////////////////////////////////////////////////////////////////////
int CTM::ThreadShutdown()
{


  //just report if the thread id exists
  if (!m_lThread) return TRUE;
  return FALSE;
}


/////////////////////////////////////////////////////////////////////////////
// Check connection request
/////////////////////////////////////////////////////////////////////////////
void CTM::CheckConnection()
{

  int i;
//  FD_SET rfds;
  FD_SET wfds;
  FD_SET efds;
  TIMEVAL t = {0, 0};
  //int len = 0;

  
  //fill structures with sockets to observe
  FD_ZERO( &efds);
  FD_SET( m_sSocket, &efds);
  FD_ZERO( &wfds);
  FD_SET( m_sSocket, &wfds);

  //connect is pending, wait for completion
  if ((i = select( 0, NULL, &wfds, &efds, &t)) == SOCKET_ERROR)
  {

    //i = WSAGetLastError();

    //declare socket invalid
    DestroySocket();
    SetConnectionState( 0);
  }
  else
  {

    //Check the reaction on connection request
    if (i) 
    {
        
      //connection establshed?
      if (FD_ISSET( m_sSocket, &wfds))
        SetConnectionState( 2);

      //just disconnect all the sockets and try again    
      if (FD_ISSET( m_sSocket, &efds))
      {

        DestroySocket();
        SetConnectionState( 0);
      }
    }
  }
} //CheckConnection

int CTM::SendLifeSign()
{

  int datalen = 0;
  char buf[80];

  BuildHeader( buf, DS_LIFESIGN, datalen);
 
  if (send( m_sSocket, (char *)buf, datalen + 16, 0) == SOCKET_ERROR)
  {

    DestroySocket();
    return 0;
  }

  SetSendBit( 1);
  return -1;
} //SendLifeSign

int CTM::SendCommand(int seq)
{

  int datalen = 0;
  char buf[80];

  BuildHeader( buf, DS_COMMAND, datalen, seq);
 
  if (send( m_sSocket, (char *)buf, datalen + 16, 0) == SOCKET_ERROR)
  {

    DestroySocket();
    return 0;
  }

  SetSendBit( 1);
  return -1;
} //SendCommand


int CTM::SendStatus(int seq)
{

  int datalen = 0;
  char buf[4096];
  char tmp[ 10];
  int i;

  for (i=0; i < 10000; i++)
    if (para_Status[ i] >= 0) datalen++;

  //build header
  BuildHeader( buf, DS_STATUS, 6*datalen+3, seq);

  buf[ 15] = 'B';
  sprintf( tmp, "%02d", datalen);
  buf[16] = tmp[0];
  buf[17] = tmp[1];

  for (i=0, datalen=0; i < 10000; i++)
  {

    if (para_Status[ i] >= 0) 
    {
     
      //fill in the index number
      sprintf( tmp, "%04d", i);
      buf[18 + 6*datalen] = tmp[0];
      buf[19 + 6*datalen] = tmp[1];
      buf[20 + 6*datalen] = tmp[2];
      buf[21 + 6*datalen] = tmp[3];

      //set the value in the buffer
      buf[22 + 6*datalen] = GetIndex( i, STAT_BOOL)[0];
      //add the delimter
      buf[23 + 6*datalen] = m_sDelimiter;
      datalen++;
    }
  }
 
  //now fill in the terminator
  buf[18 + 6*datalen] = m_sTerminator;
  buf[19 + 6*datalen] = m_sTerminator;
  buf[20 + 6*datalen] = m_sTerminator;

  if (send( m_sSocket, (char *)buf, 6*datalen + 4 + 15, 0) == SOCKET_ERROR)
  {

    DestroySocket();
    return 0;
  }

  SetSendBit( 1);
  return -1;
} //SendStatus

int CTM::SendParameter(int seq, char *recv, int upd)
{

  //recv buffer start met type, gevlgd door aantal
  int datalen = 0;
  char buf[4096];
  char tmp[ 30];
  int count;
  int missed = 0;
  void *para;
  int tp;
  int x;
  CString sTmp;

  tmp[0] = recv[1];
  tmp[1] = recv[2];
  tmp[2] = '\0';
  count = atoi( tmp);

  //length of one parameter depends on the type
  switch (recv[0])
  {

    case 'B': datalen = 5 + 1; para = (void *)para_ParaB; tp = PARA_BOOL; break;
    case 'I': datalen = 5 + 3; para = (void *)para_ParaI; tp = PARA_INT; break;
    case 'L': datalen = 5 + 6; para = (void *)para_ParaL; tp = PARA_LONG; break;
    case 'R': datalen = 5 + 17; para = (void *)para_ParaR; tp = PARA_REAL; break;
    case 'S': datalen = 5 + 20; para = (void *)para_ParaS; tp = PARA_STRING; break;
    default: datalen = 0; tp = 0; break;
  }

  //for (int i=0; i < 10000; i++)
  //  if (para_Status[ i] >= 0) datalen++;

  //build header
  BuildHeader( buf, (upd == 0) ? DS_PARAMETER: DS_PARAMETER, count*datalen+3, seq);

  buf[ 15] = recv[0];
  //sprintf( tmp, "%02d", count);
  buf[16] = recv[1];
  buf[17] = recv[2];

  int offset = (upd == 0) ? 5: datalen;

  for (int i=0, k=0, z=0; i < count; i++)
  {
    tmp[0] = recv[i*offset+3];
    tmp[1] = recv[i*offset+4];
    tmp[2] = recv[i*offset+5];
    tmp[3] = recv[i*offset+6];
    tmp[4] = '\0';
    k = atoi( tmp);

    sTmp = GetIndex( k, tp);

    if (strlen(sTmp) > 0) 
    {
     
      //update the internal parameter vlaue if we need to
      if (upd)
      {
         for (x=0; x < (datalen - 5); x++)
           tmp[x] = recv[i*offset+7+x];
         
         tmp[x] = '\0';
         sTmp = tmp;
         SetIndex( k, tp, sTmp);
      }

      

      //fill in the index number
      sprintf( tmp, "%04d", k);
      buf[18 + z*datalen] = tmp[0];
      buf[19 + z*datalen] = tmp[1];
      buf[20 + z*datalen] = tmp[2];
      buf[21 + z*datalen] = tmp[3];

      //set the value in the buffer
      for (x=0; x < (datalen - 5); x++)
        if (x >= sTmp.GetLength()) buf[22+z*datalen + x] = ' ';
        else buf[22 + z*datalen + x] = sTmp.GetAt(x);

      //add the delimter
      buf[23 + z*datalen + (datalen - 6)] = m_sDelimiter;
      //datalen++;
      z++;
    }
    else
      missed++;
  }
 
  count -= missed;

  //now fill in the terminator
  buf[18 + count*datalen] = m_sTerminator;
  sprintf( tmp, "%02d", count);
  buf[16] = tmp[0];
  buf[17] = tmp[1];
  sprintf( tmp, "%03d", count*datalen+3);
  buf[10] = tmp[0];
  buf[11] = tmp[1];
  buf[12] = tmp[2];
  
  if (send( m_sSocket, (char *)buf, count*datalen + 3 + 16, 0) == SOCKET_ERROR)
  {

    DestroySocket();
    return 0;
  }

  SetSendBit( 1);
  return -1;
} //SendParameter

int CTM::SendStatistical(int seq, char *recv, int del)
{

  //recv buffer start met type, gevlgd door aantal
  int datalen = 0;
  char buf[4096];
  char tmp[ 30];
  int count;
  int missed = 0;
  void *para;
  int tp;
  int x;
  CString sTmp;

  tmp[0] = recv[1];
  tmp[1] = recv[2];
  tmp[2] = '\0';
  count = atoi( tmp);

  //length of one parameter depends on the type
  switch (recv[0])
  {

    case 'B': datalen = 5 + 1; para = (void *)para_ParaB; tp = INFO_BOOL; break;
    case 'I': datalen = 5 + 3; para = (void *)para_ParaI; tp = INFO_INT; break;
    case 'L': datalen = 5 + 6; para = (void *)para_ParaL; tp = INFO_LONG; break;
    case 'R': datalen = 5 + 17; para = (void *)para_ParaR; tp = INFO_REAL; break;
    case 'S': datalen = 5 + 20; para = (void *)para_ParaS; tp = INFO_STRING; break;
    default: datalen = 0; tp = 0; break;
  }

  //for (int i=0; i < 10000; i++)
  //  if (para_Status[ i] >= 0) datalen++;

  //build header
  BuildHeader( buf, DS_STATINFO, count*datalen+3, seq);

  buf[ 15] = recv[0];
  //sprintf( tmp, "%02d", count);
  buf[16] = recv[1];
  buf[17] = recv[2];

  int offset = 5;

  for (int i=0, k=0, z=0; i < count; i++)
  {
    tmp[0] = recv[i*offset+3];
    tmp[1] = recv[i*offset+4];
    tmp[2] = recv[i*offset+5];
    tmp[3] = recv[i*offset+6];
    tmp[4] = '\0';
    k = atoi( tmp);

    sTmp = GetIndex( k, tp);
    if (del) SetIndex( k, tp, "0");

    if (strlen(sTmp) > 0) 
    {
     
      //fill in the index number
      sprintf( tmp, "%04d", k);
      buf[18 + z*datalen] = tmp[0];
      buf[19 + z*datalen] = tmp[1];
      buf[20 + z*datalen] = tmp[2];
      buf[21 + z*datalen] = tmp[3];

      //set the value in the buffer
      for (x=0; x < (datalen - 5); x++)
        buf[22 + z*datalen + x] = sTmp.GetAt(x);

      //add the delimter
      buf[23 + z*datalen + (datalen - 6)] = m_sDelimiter;
      //datalen++;
      z++;
    }
    else
      missed++;
  }
 
  count -= missed;

  //now fill in the terminator
  buf[18 + count*datalen] = m_sTerminator;
  sprintf( tmp, "%02d", count);
  buf[16] = tmp[0];
  buf[17] = tmp[1];
  sprintf( tmp, "%03d", count*datalen+3);
  buf[10] = tmp[0];
  buf[11] = tmp[1];
  buf[12] = tmp[2];
  
  if (send( m_sSocket, (char *)buf, count*datalen + 3 + 16, 0) == SOCKET_ERROR)
  {

    DestroySocket();
    return 0;
  }

  SetSendBit( 1);
  return -1;
} //SendStatistical


int CTM::SendException(char *code, int level, char *description)
{

  int datalen = 14 + 16 + 1 + 50;
  char buf[1024];
  char tmp[20];
  int i;
  int hdr = PROT_HEADER_LEN - 1;

  BuildHeader( buf, DS_EXCEPTION, datalen);

  GetDateTime( tmp);
  for (i = 0; i < 14; i++)
    buf[ hdr + i] = tmp[ i];
  
  for (i = 0; i < 16; i++)
    buf[ hdr + 14 + i] = code[ i];
  
  sprintf( tmp, "%01d", level); 
  buf[ hdr + 14 + 16] = tmp[ 0];

  for (i = 0; i < 50; i++)
    buf[ hdr + 14 + 16 + 1 + i] = description[ i];

  if (send( m_sSocket, (char *)buf, datalen + PROT_HEADER_LEN, 0) == SOCKET_ERROR)
  {

    DestroySocket();
    return 0;
  }

  SetSendBit( 1);
  return -1;
} //SendLifeSign

void CTM::SetSendBit( int Snd) 
{
  
  if (Snd) m_iSendRecv |= 0x2; 
  else m_iSendRecv &= 0x1;

  if (Snd) ((CCTMSApp *)AfxGetApp())->SetSendBit( 1);
};

void CTM::SetRecvBit( int Rcv) 
{
  
  if (Rcv) m_iSendRecv |= 0x1; 
  else m_iSendRecv &= 0x2;
                             
  if (Rcv) ((CCTMSApp *)AfxGetApp())->SetRecvBit( 1);
};

void CTM::BuildHeader(char *buffer, int type, int datalen, int seq)
{

  //fill bytes 0 and 1 with source id
  buffer[ 0] = m_sSource[ 0];
  buffer[ 1] = m_sSource[ 1];

  //fill bytes 2 and 3 with destination id
  buffer[ 2] = m_sDestination[ 0];
  buffer[ 3] = m_sDestination[ 1];


  //fill bytes 4 and 5 with message number
  switch (type)
  {

    case DS_COMMAND:        
      buffer[ 4] = m_sIdCommand[ 0]; 
      buffer[ 5] = m_sIdCommand[ 1]; 
      break;

    case DS_STATUS:
      buffer[ 4] = m_sIdStatus[ 0]; 
      buffer[ 5] = m_sIdStatus[ 1]; 
      break;

    case DS_EXCEPTION:
      buffer[ 4] = m_sIdException[ 0]; 
      buffer[ 5] = m_sIdException[ 1]; 
      break;

    case DS_PARAMETER:
      buffer[ 4] = m_sIdParameter[ 0]; 
      buffer[ 5] = m_sIdParameter[ 1]; 
      break;

    case DS_PARAWRITE:
      buffer[ 4] = m_sIdParameter2[ 0]; 
      buffer[ 5] = m_sIdParameter2[ 1]; 
      break;

    case DS_STATINFO:
      buffer[ 4] = m_sIdStatistical[ 0]; 
      buffer[ 5] = m_sIdStatistical[ 1]; 
      break;

    case DS_LIFESIGN:        
    default:       
      buffer[ 4] = m_sIdLifeSign[ 0]; 
      buffer[ 5] = m_sIdLifeSign[ 1]; 
      break;
  }

  //fill bytes 6 and 7 with version
  buffer[ 6] = m_sProtocolVersion[ 0];
  buffer[ 7] = m_sProtocolVersion[ 1];

  //fill bytes 8 and 9 with sequence number
  if (type == DS_LIFESIGN)
    buffer[ 8] = buffer[ 9] = '0';
  else
    if (seq == 0) 
      sprintf( &buffer[8], _T("%02d"), GetSequenceNr());
    else 
      sprintf( &buffer[8], _T("%02d"), seq);

  //fill bytes 10, 11 and 12 with data length
  if (datalen > 999) datalen = 999;
  sprintf( &buffer[ 10], _T("%03d"), datalen);

  //fill bytes 13 and 14 with subsystem id
  buffer[ 13] = m_sId[ 0];
  buffer[ 14] = m_sId[ 1];

  //add terminator
  buffer[ 15 + datalen] = m_sTerminator;
}


void CTM::GetDateTime(char *buf)
{

  char tmp[20];
  SYSTEMTIME stim;
  int i;

  GetSystemTime( &stim);

  sprintf( tmp, "%04d", stim.wYear); 
  for (i = 0; i < 4; i++)
    buf[ i] = tmp[ i];

  sprintf( tmp, "%02d", stim.wMonth); 
  for (i = 0; i < 2; i++)
    buf[ 4 + i] = tmp[ i];

  sprintf( tmp, "%02d", stim.wDay); 
  for (i = 0; i < 2; i++)
    buf[ 6 + i] = tmp[ i];

  sprintf( tmp, "%02d", stim.wHour); 
  for (i = 0; i < 2; i++)
    buf[ 8 + i] = tmp[ i];

  sprintf( tmp, "%02d", stim.wMinute); 
  for (i = 0; i < 2; i++)
    buf[ 10 + i] = tmp[ i];

  sprintf( tmp, "%02d", stim.wSecond); 
  for (i = 0; i < 2; i++)
    buf[ 12 + i] = tmp[ i];
} //GetDateTime


// Check if a new message is received
// returns: -1 error, connection can be terminated
//          0 no message received
//          > 0 message indentifier,, buffer has complete message
int CTM::RecvMessage( char *buffer, int *type)
{

  int rlen = 0;
  int error;
  FD_SET rfds;
  TIMEVAL t = { 0, 0};
  //TIMEVAL *tval = NULL;


  //start receiving a header
  while (rlen < PROT_HEADER_LEN)
  {

    //wait for data
    FD_ZERO( &rfds);
    FD_SET( m_sSocket, &rfds);

    error = select( 0, &rfds, NULL, NULL, &t);

    if ((error == SOCKET_ERROR) || (error == 0))
    {

      //timeout reached, update device status
      if (error == 0) return 0;

      //trace the winsock error
      //if ((error == SOCKET_ERROR) && device)
      //  CodeTrace( _T("SOCKET_ERROR"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, 
      //             WSAGetLastError(), device->GetName());

      return ERR_RX_FAILED; //read error
    }

    //check for stop condition
    //if (Imx_MT_Get_Stop()) return ERR_RX_FAILED;

    //inhibit send actions
    //if (device) device->Lock();

    //receive the header
    error = recv( m_sSocket, &buffer[ rlen], 16, 0);

    //release device for send actions
    //if (device) device->Release();

    //evaluate the received data
    if (!error || (error == SOCKET_ERROR ))
    {

      return ERR_RX_FAILED;
    }
    else 
      rlen += error; //number of received bytes

    //just wait once, otherwise wait 100msec and try once again
    if (t.tv_usec) break;
    t.tv_usec = 100;
  }

  //we have data
  SetRecvBit( 1);

  //we need at least a header
  if (rlen < PROT_HEADER_LEN) return 0;

  //evaluate the header, assume header is ok and extract message type
  *type = GetType( buffer, PROT_HEADER_LEN);

  char tmp[40];
  int count = 0;
  int del_offset = 0;
  int del = 0;
  int i, k;

  //read data
  tmp[ 0] = buffer[ 10];
  tmp[ 1] = buffer[ 11];
  tmp[ 2] = buffer[ 12];
  tmp[ 3] = '\0';
  //strcpy( tmp, "000");
  count = atoi(tmp); //index 17 en 18
  del_offset = count;
  //count++;

  if (count > 0) 
  {

    error = recv( m_sSocket, &buffer[ rlen], count, 0);

    //evaluate the received data
    if (!error || (error == SOCKET_ERROR ))
      return ERR_RX_FAILED;
    else 
      rlen += error; //number of received bytes
  }

  switch (*type)
  {
    case DS_COMMAND:

      tmp[ 0] = buffer[ 16];
      tmp[ 1] = buffer[ 17];
      tmp[ 2] = '\n';
      count = atoi(tmp); //index 17 en 18

      for (i = 0, k = 0; i < count; i++)      
      {
        
        tmp[0] = buffer[ 18 + i*6];
        tmp[1] = buffer[ 19 + i*6];
        tmp[2] = buffer[ 20 + i*6];
        tmp[3] = buffer[ 21 + i*6];
        tmp[4] = '\0';
        tmp[5] = buffer[ 22 + i*6];

        k = atoi( tmp);
        if (GetCommand( k) >= 0) SetCommand( k, tmp[5]);
        //index = 4 bytes
      //val = 1 byte
      }

      tmp[0] = buffer[8];
      tmp[1] = buffer[9];
      tmp[2] = '\0';
      count = atoi( tmp);

      //reply
      SendCommand( count);
      break;

    case DS_STATUS:
      //tm sends status info in return, use the same sequence number
      tmp[0] = buffer[8];
      tmp[1] = buffer[9];
      tmp[2] = '\0';
      count = atoi( tmp);
      SendStatus( count);
      break;

    case DS_PARAMETER:
    //case DS_STATINFO:
      tmp[0] = buffer[8];
      tmp[1] = buffer[9];
      tmp[2] = '\0';
      count = atoi( tmp);
      SendParameter( count, &buffer[15], 0);
      break;

    case DS_PARAWRITE:
      tmp[0] = buffer[8];
      tmp[1] = buffer[9];
      tmp[2] = '\0';
      count = atoi( tmp);
      SendParameter( count, &buffer[15], -1);
      break;

    case DS_STATINFO:
      tmp[0] = buffer[8];
      tmp[1] = buffer[9];
      tmp[2] = '\0';
      count = atoi( tmp);

	  if (buffer[ 14 + del_offset] == '1') del = 1;
      SendStatistical( count, &buffer[15], del);
      break;
    
    case DS_LIFESIGN:
    default:
      break;
  }
  //now check if everything is ok, including the expected message type
  //if (error = ImBasCheckRxBuffer( buffer, PROT_HEADER_LEN, *type))
  //{

    //code trace for invalid protocol data
  //  CodeTrace( _T("DEVICE_INVRX"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, buffer, PROT_HEADER_LEN, error);

    //save protocol error on device
  //  if (device) device->SetProtocolError( error);

    //read data untill terminator is received
  //  int check = rlen > 0 ? rlen - 1: 0;
  //  if (!rlen) buffer[ rlen] = '0';

  //  while (buffer[ check] != ImBasGetTerminator())
  //  {

      //wait for data
  //    FD_ZERO( &rfds);
  //    FD_SET( sock, &rfds);
  //    t.tv_sec = 0;
  //    t.tv_usec = 0;
  //    error = select( 0, &rfds, NULL, NULL, &t);
      
  //    if (!error || error == SOCKET_ERROR)
  //    {

        //build device name for logging purposes
  //      CString DevName = (device) ? device->GetName() : Xlate( "UNKNOWN_DEVID", ImBasGetSystemId( buffer, PROT_HEADER_LEN));

        //trace the winsock error
  //      if (error == SOCKET_ERROR)
  //        CodeTrace( _T("SOCKET_ERROR"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, WSAGetLastError());
  //      else
  //        CodeTrace( _T("RCV_TIMEOUT"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, DevName);

  //      break;
  //    }

  //    recv( sock, &buffer[ rlen++], 1, 0);
  //    check = rlen - 1;
  //  } 

    //code trace for invalid protocol data
    //if (rlen > 1)
    //  CodeTrace( _T("DEVICE_INVRX"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, buffer, rlen-1, ERR_RECVLEN);

  //  rlen = 0; //invalid header, try again

    //give a value for message type: unknown type
  //  *type = 0;
  //  if (m_iDisconnectProtocolErrors) return ERR_RX_FAILED;
  //  else return 0;
  //}

  //header is received and is looking fine, receive data
  //while (rlen < (PROT_HEADER_LEN + ImBasGetDataLength( buffer, PROT_HEADER_LEN) + 1))
  //{

    //wait for data
  //  FD_ZERO( &rfds);
  //  FD_SET( sock, &rfds);
  //  select( 0, &rfds, NULL, NULL, &t);

    //receive data
  //  error = recv( sock, &buffer[ rlen], PROT_HEADER_LEN + ImBasGetDataLength( buffer, PROT_HEADER_LEN) + 1 - rlen, 0);

    //evaluate the received data
  //  if (!error || (error == SOCKET_ERROR ))
  //  {

      //build device name for logging purposes
  //    CString DevName = (device) ? device->GetName() : Xlate( "UNKNOWN_DEV");

  //    if (!error)
  //      CodeTrace( _T("SOCKET_CLOSED"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, device->GetName());
  //    else
  //      CodeTrace( _T("SOCKET_ERROR"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, WSAGetLastError(), device->GetName());

  //    return ERR_RX_FAILED;
  //  }
  //  else 
  //    rlen += error; //number of received bytes
  //}

  //CodeTrace( _T("DEVICE_RX"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, buffer, rlen);

  //check received message, this time only for terminator...
  //if (error = ImBasCheckRxBuffer( buffer, rlen, *type))
  //{

    //save the protocol error on the device
  //  if (device) device->SetProtocolError( error);

    //invalidate the message type
  //  *type = 0;

  //  if (m_iDisconnectProtocolErrors) return error;
  //}

   //done, all data received
   return *type;
} //RecvMessage


//int MyFlTask::ImBasCheckRxBuffer(char *buffer, int MsgLength, int MsgType)
//{

  //first the fixed items are checked, it is assumed that we are
  //dealing with an incoming message

//  if (MsgLength < 2) return 0;

  //source field in header
  //if ((buffer[ 0] != 'B') || (buffer[ 1] != 'C')) return ERR_INVALID_SOURCE;
//  if ((buffer[ 0] != m_sDestination[ 0]) || (buffer[ 1] != m_sDestination[ 1])) return ERR_INVALID_SOURCE;

//  if (MsgLength < 4) return 0;

  //destination field in header
  //if ((buffer[ 2] != 'I') || (buffer[ 3] != 'M')) return ERR_INVALID_DESTINATION;
//  if ((buffer[ 2] != m_sSource[ 0]) || (buffer[ 3] != m_sSource[ 1])) return ERR_INVALID_DESTINATION;

//  if (MsgLength < 6) return 0;

/*
  m_sIdLifeSign = _T("00");     //00
  m_sIdCommand = _T("01");      //01
  m_sIdParameter = _T("02");    //02
  m_sIdSetParameter = _T("03"); //03
  m_sIdStatus = _T("11");       //11
  m_sIdStatistical = _T("12");  //12
  m_sIdException = _T("21");    //21
*/

  //find the data length of the message
//  int len = ImBasGetDataLength( buffer, MsgLength);
//  int dlen;
//  int i;

  //message types
//  switch (MsgType)
//  {

//    case DS_COMMAND_BOOL:
//    case DS_COMMAND_INT:
//    case DS_COMMAND_LONG:
//    case DS_COMMAND_REAL:
//    case DS_COMMAND_CHAR:
//      if ((buffer[ 4] != m_sIdCommand[ 0]) || (buffer[ 5] != m_sIdCommand[ 1])) 
//        return ERR_INVALID_TYPE;  
//      break;

//    case DS_PARAMETER_BOOL:
//    case DS_PARAMETER_INT:
//    case DS_PARAMETER_LONG:
//    case DS_PARAMETER_REAL:
//    case DS_PARAMETER_CHAR:
//      if ((buffer[ 4] != m_sIdParameter[ 0]) || ((buffer[ 5] != m_sIdParameter[ 1]) && (buffer[ 5] != m_sIdSetParameter[ 1]))) 
//        return ERR_INVALID_TYPE;  
//      break;

//    case DS_STATUS_BOOL:
//    case DS_STATUS_INT:
//    case DS_STATUS_LONG:
//    case DS_STATUS_REAL:
//    case DS_STATUS_CHAR:
//      if ((buffer[ 4] != m_sIdStatus[ 0]) || (buffer[ 5] != m_sIdStatus[ 1])) 
//        return ERR_INVALID_TYPE;
//      break;

//    case DS_STATINFO_BOOL:
//    case DS_STATDEL_BOOL:
//    case DS_STATINFO_INT:
//    case DS_STATDEL_INT:
//    case DS_STATINFO_LONG:
//    case DS_STATDEL_LONG:
//    case DS_STATINFO_REAL:
//    case DS_STATDEL_REAL:
//    case DS_STATINFO_CHAR:
//    case DS_STATDEL_CHAR:
//      if ((buffer[ 4] != m_sIdStatistical[ 0]) || (buffer[ 5] != m_sIdStatistical[ 1]))
//        return ERR_INVALID_TYPE;  
//      break;

//    case DS_EXCEPTION:
//      if ((buffer[ 4] != m_sIdException[ 0]) || (buffer[ 5] != m_sIdException[ 1]))
//        return ERR_INVALID_TYPE;  

      //check the datalength
//      for ( i = 0, dlen = 0; i < 10; i++)
//        dlen += m_iExceptionSize[ i];

//      if (len != dlen) return ERR_DATA_LENGTH;
//      break;

//    case DS_LIFESIGN:
//      if ((buffer[ 4] != m_sIdLifeSign[ 0]) || (buffer[ 5] != m_sIdLifeSign[ 1]))
//        return ERR_INVALID_TYPE;  
//      break;

//    default: return ERR_INVALID_TYPE;
//  }

//  if (MsgLength < 8) return 0;

  //version number
//  if (strncmp( &buffer[ 6], (LPCTSTR)m_sProtocolVersion, 2))
//    return ERR_INVALID_VERSION;

//  if (MsgLength < 10) return 0;

  //check sequence number
//  if (MsgType == DS_LIFESIGN)
//  {

//    if ((buffer[ 8] != '0') || (buffer[ 9] != '0'))
//      return ERR_INVALID_SEQUENCE;  
//  }

//  if ((len >= 0) && (MsgLength > (len + PROT_HEADER_LEN)))
//  {

//    if (buffer[ len + PROT_HEADER_LEN] != ImBasGetTerminator())
//      return ERR_INVALID_TERMINATOR;
//  }

//  return 0;
//}


/////////////////////////////////////////////////////////////////////////////
// Descripton: Retrieve the datalength from the data buffer
// 
// Parameters: 
// 
// Returns: 
// 
// Comment: 
// 
/////////////////////////////////////////////////////////////////////////////
int CTM::GetDataLength( char *buf, int length)
{

  //if length data is not included in buffer return negtive
  if (length < 13) return -1;

  //get length
  CString len = _T("000");
  len.SetAt( 0, buf[ 10]);
  len.SetAt( 1, buf[ 11]);
  len.SetAt( 2, buf[ 12]);

  return atoi( len);
}

/////////////////////////////////////////////////////////////////////////////
// Description: Retrieve the message type from the data buffer
// 
// Parameter: *buf - Character buffer in which th emessage is received.
// Parameter: length - Length of the character buffer 'buf'.
// 
// Returns: The type of the message as an integer, note that the value is derived
// from the received message and therefor only the base (or default) type of the 
// message is returned. These types are only the boolean data types for the message.
// 
// Comment: 
//
/////////////////////////////////////////////////////////////////////////////
int CTM::GetType( char *buf, int length)
{

  //if length data is not included in buffer return negtive
  if (length < 6) return -1;

  //get type
  CString type = _T("00");
  type.SetAt( 0, buf[ 4]);
  type.SetAt( 1, buf[ 5]);
  
  switch (atoi( type))
  {

    case  0: return DS_LIFESIGN;   //life sign
    case  1: return DS_COMMAND;    //command
    case  2: return DS_PARAMETER;  //parameter data
    case  3: return DS_PARAWRITE;  //parameter data
    case 11: return DS_STATUS;     //status 
    case 12: return DS_STATINFO;   //statistical info
    case 21: return DS_EXCEPTION;  //exception
    default: break;
  }

  return -1; //return invalid message type
}

int CTM::IsConnected()
{

  if (m_iConnection >= 3) return -1;
  return 0;
}

int CTM::GetSequenceNr()
{

  if (m_iSequenceNr >= 99) m_iSequenceNr = 1;
  else m_iSequenceNr++;

  return m_iSequenceNr;
}

CString CTM::GetIndex(int idx, int type)
{

  CString sIndex = "";

  if ((idx < 0) || (idx > 9999)) return sIndex;

  switch (type)
  {

    case PARA_BOOL: 
      if (para_ParaB[ idx] >= 0) sIndex.Format( "%1d", para_ParaB[ idx]); break;
    case PARA_INT: 
      if (para_ParaI[ idx] >= 0) sIndex.Format( "%03d", para_ParaI[ idx]); break;
    case PARA_LONG: 
      if (para_ParaL[ idx] >= 0) sIndex.Format( "%06ld", para_ParaL[ idx]); break;
    case PARA_REAL: 
      if (para_ParaR[ idx] >= 0) sIndex.Format( "%17.8f", para_ParaR[ idx]); break;
    case PARA_STRING: sIndex.Format( "%.20s", para_ParaS[ idx]); break;

    case INFO_BOOL: 
      if (para_StatisticalB[ idx] >= 0) sIndex.Format( "%1d", para_StatisticalB[ idx]); break;
    case INFO_INT: 
      if (para_StatisticalI[ idx] >= 0) sIndex.Format( "%03d", para_StatisticalI[ idx]); break;
    case INFO_LONG: 
      if (para_StatisticalL[ idx] >= 0) sIndex.Format( "%06ld", para_StatisticalL[ idx]); break;
    case INFO_REAL: 
      if (para_StatisticalR[ idx] >= 0) sIndex.Format( "%17.8f", para_StatisticalR[ idx]); break;
    case INFO_STRING: sIndex.Format( "%.20s", para_StatisticalS[ idx]); break;
  
    case COMM_BOOL: 
      if (para_Command[ idx] >= 0) sIndex.Format( "%1d", para_Command[ idx]); break;

    case STAT_BOOL: 
      if (para_Status[ idx] >= 0) sIndex.Format( "%1d", para_Status[ idx]); break;
    default: break;
  }

  return sIndex;
} //GetIndex


CString CTM::SetIndex(int idx, int type, CString sVal)
{

  CString sIndex = "";

  if ((idx < 0) || (idx > 9999)) return sIndex;

  switch (type)
  {

    case PARA_BOOL: 
      if (para_ParaB[ idx] >= 0) para_ParaB[ idx] = atoi(sVal); break;
    case PARA_INT: 
      if (para_ParaI[ idx] >= 0) para_ParaI[ idx] = atoi(sVal); break;
    case PARA_LONG: 
      if (para_ParaL[ idx] >= 0) para_ParaL[ idx]= atol(sVal); break;
    case PARA_REAL: 
      if (para_ParaR[ idx] >= 0) para_ParaR[ idx] = atof(sVal); break;
    case PARA_STRING: strcpy( para_ParaS[ idx], sVal); break;

    case INFO_BOOL: 
      if (para_StatisticalB[ idx] >= 0) para_StatisticalB[ idx] = atoi(sVal); break;
    case INFO_INT: 
      if (para_StatisticalI[ idx] >= 0) para_StatisticalI[ idx] = atoi(sVal); break;
    case INFO_LONG: 
      if (para_StatisticalL[ idx] >= 0) para_StatisticalL[ idx] = atol(sVal); break;
    case INFO_REAL: 
      if (para_StatisticalR[ idx] >= 0) para_StatisticalR[ idx] = atof(sVal); break;
    case INFO_STRING: strcpy( para_StatisticalS[ idx], sVal); break;
  
    case COMM_BOOL: 
      if (para_Command[ idx] >= 0) para_Command[ idx] = atoi(sVal); break;

    case STAT_BOOL: 
      if (para_Status[ idx] >= 0) para_Status[ idx] = atoi(sVal); break;
    default: break;
  }

  return sVal;
} //GetIndex

int CTM::GetCommand(int idx)
{

  if ((idx < 0) || (idx > 9999)) return -1;
  return para_Command[ idx];
}

int CTM::SetCommand(int idx, int val)
{

  if ((idx < 0) || (idx > 9999)) return -1;
  para_Command[ idx] = (val == 48) ? 0: 1;
  return para_Command[ idx];
}

void CTM::IniReadParameterI( char *IniCmd, int *para, CString *sTxt)
{

  CString sCmd[6];
  CString sVal[6];
  char key[80];
  char key2[80];
  char section[80];
  int i = 0;
  int wd = 0;

  strcat( strcpy( section, "TM"), m_sId);
  
  for (i = 0; i < 6; i++)
  {
    if (i == 0) strcpy( key, IniCmd);
    else sprintf( key, strcat( strcpy(key, IniCmd), "%01d"), i);

    wd = i ? 0: -1;
    strcat( strcpy(key2, key), "Val");

    sCmd[i] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", wd);
    sVal[i] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key2, section, "", wd);
  }

  int k = 0;
  int m = 0;
  int x = 0;
  int y = 0;
  int p = 0;
  int q = 0;
  char nr[10];

  for (i=0; i < 10000; i++) para[ i] = -1;

  for (i = 0; i < 6; i++)
  {

    if (sCmd[i].GetLength() > 0)
    {

      p = q = 0;

      do 
      {

        x = sCmd[i].Find( ',', p);
        y = sVal[i].Find( ',', q);
        memset( (void *)nr, 0, sizeof(nr));

        if ((x >= 0) && ((x-p) < 10))
        {

          m = atoi( sCmd[i].Mid( p, x - p));
          if (y < 0) y = sVal[i].GetLength();
          k = (y > q) ? atoi( sVal[i].Mid( q, y - q)): 0;

          para[ m] = k;
          sprintf( key, strcat( strcpy(key2, IniCmd), "txt%d"), m);

          sTxt[m] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
        }
        else
          if (x < 0)
          {
            
            m = atoi( sCmd[i].Mid( p, sCmd[i].GetLength() - p));
            if (y < 0) y = sVal[i].GetLength();
            k = (y > q) ? atoi( sVal[i].Mid( q, y - q)): 0;
            para[ m] = k;
            sprintf( key, strcat( strcpy(key2, IniCmd), "txt%d"), m);
            sTxt[m] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
          }

        p = x + 1;
        q = y + 1;
      } while (x >= 0);
    }
  }
}

void CTM::IniReadParameterL( char *IniCmd, long *para, CString *sTxt)
{

  CString sCmd[6];
  CString sVal[6];
  char key[80];
  char key2[80];
  char section[80];
  int i = 0;
  int wd = 0;

  strcat( strcpy( section, "TM"), m_sId);
  
  for (i = 0; i < 6; i++)
  {
    if (i == 0) strcpy( key, IniCmd);
    else sprintf( key, strcat( strcpy(key, IniCmd), "%01d"), i);

    strcat( strcpy(key2, key), "Val");

    wd = i ? 0: -1;
    sCmd[i] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", wd);
    sVal[i] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key2, section, "", wd);
  }

  int k = 0;
  int m = 0;
  int x = 0;
  int y = 0;
  int p = 0;
  int q = 0;
  char nr[10];

  for (i=0; i < 10000; i++) para[ i] = -1;

  for (i = 0; i < 6; i++)
  {

    if (sCmd[i].GetLength() > 0)
    {

      p = q = 0;

      do 
      {

        x = sCmd[i].Find( ',', p);
        y = sVal[i].Find( ',', q);
        memset( (void *)nr, 0, sizeof(nr));

        if ((x >= 0) && ((x-p) < 10))
        {

          m = atoi( sCmd[i].Mid( p, x - p));
          if (y < 0) y = sVal[i].GetLength();
          k = (y > q) ? atol( sVal[i].Mid( q, y - q)): 0;

          para[ m] = k;
          sprintf( key, strcat( strcpy(key2, IniCmd), "txt%d"), m);
          sTxt[m] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
        }
        else
          if (x < 0)
          {
            
            m = atoi( sCmd[i].Mid( p, sCmd[i].GetLength() - p));
            if (y < 0) y = sVal[i].GetLength();
            k = (y > q) ? atol( sVal[i].Mid( q, y - q)): 0;
            para[ m] = k;
            sprintf( key, strcat( strcpy(key2, IniCmd), "txt%d"), m);
            sTxt[m] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
          }

        p = x + 1;
        q = y + 1;
      } while (x >= 0);
    }
  }
}

void CTM::IniReadParameterR( char *IniCmd, double *para, CString *sTxt)
{

  CString sCmd[6];
  CString sVal[6];
  char key[80];
  char key2[80];
  char section[80];
  int i = 0;
  int wd = 0;

  strcat( strcpy( section, "TM"), m_sId);
  
  for (i = 0; i < 6; i++)
  {
    if (i == 0) strcpy( key, IniCmd);
    else sprintf( key, strcat( strcpy(key, IniCmd), "%01d"), i);

    strcat( strcpy(key2, key), "Val");

    wd = i ? 0: -1;
    sCmd[i] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", wd);
    sVal[i] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key2, section, "", wd);
  }

  double k = 0;
  int m = 0;
  int x = 0;
  int y = 0;
  int p = 0;
  int q = 0;
  char nr[10];

  for (i=0; i < 10000; i++) para[ i] = -1;

  for (i = 0; i < 6; i++)
  {

    if (sCmd[i].GetLength() > 0)
    {

      p = q = 0;

      do 
      {

        x = sCmd[i].Find( ',', p);
        y = sVal[i].Find( ',', q);
        memset( (void *)nr, 0, sizeof(nr));

        if ((x >= 0) && ((x-p) < 10))
        {

          m = atoi( sCmd[i].Mid( p, x - p));
          if (y < 0) y = sVal[i].GetLength();
          k = (y > q) ? atof( sVal[i].Mid( q, y - q)): 0;

          para[ m] = k;
          sprintf( key, strcat( strcpy(key2, IniCmd), "txt%d"), m);
          sTxt[m] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
        }
        else
          if (x < 0)
          {
            
            m = atoi( sCmd[i].Mid( p, sCmd[i].GetLength() - p));
            if (y < 0) y = sVal[i].GetLength();
            k = (y > q) ? atof( sVal[i].Mid( q, y - q)): 0;
            para[ m] = k;
            sprintf( key, strcat( strcpy(key2, IniCmd), "txt%d"), m);
            sTxt[m] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
          }

        p = x + 1;
        q = y + 1;
      } while (x >= 0);
    }
  }
}


void CTM::IniReadParameterS( char *IniCmd, char *para, CString *sTxt)
{

  CString sCmd[6];
  CString sVal[6];
  char key[80];
  char key2[80];
  char section[80];
  int i = 0;
  int wd = 0;

  strcat( strcpy( section, "TM"), m_sId);
  
  for (i = 0; i < 6; i++)
  {
    if (i == 0) strcpy( key, IniCmd);
    else sprintf( key, strcat( strcpy(key, IniCmd), "%01d"), i);

    strcat( strcpy(key2, key), "Val");

    wd = i ? 0: -1;
    sCmd[i] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", wd);
    sVal[i] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key2, section, "", wd);
  }

  CString k = "";
  int m = 0;
  int x = 0;
  int y = 0;
  int p = 0;
  int q = 0;
  char nr[10];

  //for (i=0; i < 10000; i++) para[ i] = -1;

  for (i = 0; i < 6; i++)
  {

    if (sCmd[i].GetLength() > 0)
    {

      p = q = 0;

      do 
      {

        x = sCmd[i].Find( ',', p);
        y = sVal[i].Find( ',', q);
        memset( (void *)nr, 0, sizeof(nr));

        if ((x >= 0) && ((x-p) < 10))
        {

          m = atoi( sCmd[i].Mid( p, x - p));
          if (y < 0) y = sVal[i].GetLength();
          k = (y > q) ? sVal[i].Mid( q, y - q): "                    ";

          strncpy( &para[ m*20], k, 20);
          sprintf( key, strcat( strcpy(key2, IniCmd), "tx%dt"), m);
          sTxt[m] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
        }
        else
          if (x < 0)
          {
            
            m = atoi( sCmd[i].Mid( p, sCmd[i].GetLength() - p));
            if (y < 0) y = sVal[i].GetLength();
            k = (y > q) ? sVal[i].Mid( q, y - q): "                    ";
            strncpy( &para[ m*20], k, 20);
            sprintf( key, strcat( strcpy(key2, IniCmd), "txt%d"), m);
            sTxt[m] = ((CCTMSApp *)AfxGetApp())->theINIFile.GetString( key, section, "", true);
          }

        p = x + 1;
        q = y + 1;
      } while (x >= 0);
    }
  }
}

CString CTM::GetTMip()
{

  CString sTmp;

  sTmp.Format( "%d.%d.%d.%d", m_wTMAddress.sin_addr.S_un.S_un_b.s_b1, 
               m_wTMAddress.sin_addr.S_un.S_un_b.s_b2, 
               m_wTMAddress.sin_addr.S_un.S_un_b.s_b3,
               m_wTMAddress.sin_addr.S_un.S_un_b.s_b4);

  return sTmp;
}

CString CTM::GetIMip()
{

  CString sTmp;

  sTmp.Format( "%d.%d.%d.%d", m_wRemoteAddress.sin_addr.S_un.S_un_b.s_b1, 
               m_wRemoteAddress.sin_addr.S_un.S_un_b.s_b2, 
               m_wRemoteAddress.sin_addr.S_un.S_un_b.s_b3,
               m_wRemoteAddress.sin_addr.S_un.S_un_b.s_b4);

  return sTmp;
}

CString CTM::GetIndexText(int idx, int type, char *buf)
{

CString sTmp = "";

  switch (type)
  {
    case PARA_BOOL: sTmp = text_ParaB[idx];
                    sprintf( buf, "Parameter %d (B)", idx); break;
    case STAT_BOOL: sTmp = text_Status[idx];
                    sprintf( buf, "Status %d", idx); break;
    case INFO_BOOL: sTmp = text_StatisticalB[idx]; 
                    sprintf( buf, "Statistical info %d (B)", idx); break;
    case COMM_BOOL: sTmp = text_Command[idx]; 
                    sprintf( buf, "Command %d", idx); break;
    case INFO_INT: sTmp = text_StatisticalI[idx]; 
                    sprintf( buf, "Statistical info %d (I)", idx); break;
    case PARA_INT:  sTmp = text_ParaI[idx]; 
                    sprintf( buf, "Parameter %d (I)", idx); break;
    case INFO_LONG: sTmp = text_StatisticalL[idx]; 
                    sprintf( buf, "Statistical info %d (L)", idx); break;
    case PARA_LONG:  sTmp = text_ParaL[idx]; 
                    sprintf( buf, "Parameter %d (L)", idx); break;
    case INFO_REAL: sTmp = text_StatisticalR[idx]; 
                    sprintf( buf, "Statistical info %d (R)", idx); break;
    case PARA_REAL:  sTmp = text_ParaR[idx]; 
                    sprintf( buf, "Parameter %d (R)", idx); break;
    case INFO_STRING: sTmp = text_StatisticalS[idx]; 
                    sprintf( buf, "Statistical info %d (S)", idx); break;
    case PARA_STRING:  sTmp = text_ParaS[idx]; 
                    sprintf( buf, "Parameter %d (S)", idx); break;
    default: sTmp = ""; break;
             //strcpy( buf, "????? %d"); break;
  }
  return sTmp;
}

CString CTM::GetName()
{

  return m_sName;
}
