// 7kXMLParsor.cpp: implementation of the C7kXMLParsor class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "7kXMLParsor.h"
#include "7k.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

C7kXMLParsor::C7kXMLParsor()
{
  m_dwSystems = 0;
  m_pXML      = NULL;
}

C7kXMLParsor::~C7kXMLParsor()
{
  if(m_pXML)
    delete m_pXML;
  m_pXML = NULL;
}

DWORD C7kXMLParsor::Set7001Info(char *pInfo)
{
  DWORD length;

  if(!pInfo)
    return 0;
 
  length = strlen(pInfo);

  if(length > 1024 * 1024) // Realistic length?
    return 0;

  if(m_pXML)
    delete m_pXML;
  m_pXML = new char[length + 1];

  m_dwLength = length;

  strcpy(m_pXML, pInfo);

  return 1;
}

DWORD C7kXMLParsor::FindTag(char *pName)
{
  DWORD start, found, tag_length, found_tag_length, i, found_start;

  if(!m_pXML || !pName)
    return 0;

  tag_length = strlen(pName);

  while(1)
  {
    if(m_dwRecIdx >= m_dwLength)
      return 0;

    // Start of tag?
    if(m_pXML[m_dwRecIdx] == '<')
    {
      start = m_dwRecIdx + 1;
      found_start = 1;
    }

    // Found start tag and ' '?
    if(m_pXML[m_dwRecIdx] == ' ' && found_start)
    {
      // Check length, performance improvement.
      found_tag_length = m_dwRecIdx - start;
      if(found_tag_length == tag_length)
      {
        found = 1;

        for(i=0; i<found_tag_length; i++)
        {
          if(m_pXML[start + i] != pName[i])
          {
            // Not tag we are looking for.
            found = 0;
            break;
          }
        }
        if(found)
        {
          // We found the tag.
          //m_dwRecIdx = start;
          return 1;
        }
      }
      found_start = 0;
    }

    m_dwRecIdx ++;
  }

  return 0;
}

DWORD C7kXMLParsor::FindAttribute(char *pAttribute)
{
  DWORD length, start = 0, end, avoid = 0;

  if(!m_pXML)
    return 0;

  length = strlen(pAttribute);

  while(1)
  {
    if(m_pXML[m_dwRecIdx] == '>')
      return 0;

    if(m_pXML[m_dwRecIdx] == '\"')
      avoid = (avoid + 1) % 2;

    if(!avoid)
    {
      if(m_pXML[m_dwRecIdx] != ' ' && !start && m_pXML[m_dwRecIdx] != '\"')
        start = m_dwRecIdx;

      if(m_pXML[m_dwRecIdx] == '=' && start)
      {
        end = m_dwRecIdx - 1;
       
        if((end - start + 1) == length)
        {
          if(!_strnicmp(&m_pXML[start], pAttribute, end - start + 1))
          {
            m_dwRecIdx = end + 3;
            return 1;
          }
        }

        start = 0;
      }

    }

    m_dwRecIdx ++;
  }

  return 1;
}



DWORD C7kXMLParsor::GetAttributeData(char *pValue, DWORD dwValueLength)
{
  DWORD i = 0;

  if(!m_pXML)
    return 0;

  while(1)
  {
    if(i >= dwValueLength || m_dwRecIdx >= m_dwLength)
      return 0;

    if(m_pXML[m_dwRecIdx] == '\"')
    {
      pValue[i] = '\0';
      return 1;
    }
    pValue[i] = m_pXML[m_dwRecIdx];

    i++;
    m_dwRecIdx ++;
  }

  return 1;
}

DWORD C7kXMLParsor::GetAttributeValue(char *pTagName, char *pAttribute, char *pValue, DWORD dwValueLength)
{  
  m_dwRecIdx = 0;
  if(FindTag(pTagName))
  {
    if(FindAttribute(pAttribute))
    {
      if(GetAttributeData(pValue, dwValueLength))
      {
        return 1;
      }
    }
  }

  return 0;
}

DWORD C7kXMLParsor::GetText(char * pTagName, char *pText, DWORD dwValueLength)
{
  DWORD start, length;

  if(!m_pXML)
    return 0;

  m_dwRecIdx = 0;
  if(FindTag(pTagName))
  {
    while(1)
    {
      if(m_pXML[m_dwRecIdx] == '>')
        break;
      m_dwRecIdx++;
    }
    start = m_dwRecIdx + 1;

    while(1)
    {
      if(m_pXML[m_dwRecIdx] == '<')
        break;
      m_dwRecIdx++;
    }

    length = m_dwRecIdx - start;
    if((length + 1) > dwValueLength)
      return 0;

    memcpy(pText, &m_pXML[start], length);
    pText[length] = '\0';
  }

  return 1;
}

DWORD C7kXMLParsor::GetDeviceID(DWORD *pDeviceID)
{
  char data[64];

  if(!GetAttributeValue("Name", "deviceid", data, 64))
    return 0;
 
  *pDeviceID = atoi(data);

  return 1;
}

DWORD C7kXMLParsor::GetEnumerator(WORD *pEnumerator)
{
  char data[64];

  if(!GetAttributeValue("Name", "enumerator", data, 64))
    return 0;
 
  *pEnumerator = atoi(data);

  return 1;
}

DWORD C7kXMLParsor::GetMinRange(double *pMinRange)
{
  char data[64];

  if(!GetAttributeValue("Range", "min", data, 64))
    return 0;
 
  *pMinRange = atof(data);

  return 1;
}


DWORD C7kXMLParsor::GetMaxRange(double *pMaxRange)
{
  char data[64];

  if(!GetAttributeValue("Range", "max", data, 64))
    return 0;
 
  *pMaxRange = atof(data);

  return 1;
}


DWORD C7kXMLParsor::GetMinGain(double *pMinGain)
{
  char data[64];

  if(!GetAttributeValue("Gain", "min", data, 64))
    return 0;
 
  *pMinGain = atof(data);

  return 1;
}


DWORD C7kXMLParsor::GetMaxGain(double *pMaxGain)
{
  char data[64];

  if(!GetAttributeValue("Gain", "max", data, 64))
    return 0;
 
  *pMaxGain = atof(data);

  return 1;
}


DWORD C7kXMLParsor::GetMinPower(double *pMinPower)
{
  char data[64];

  if(!GetAttributeValue("Power", "min", data, 64))
    return 0;
 
  *pMinPower = atof(data);

  return 1;
}


DWORD C7kXMLParsor::GetMaxPower(double *pMaxPower)
{
  char data[64];

  if(!GetAttributeValue("Power", "max", data, 64))
    return 0;
 
  *pMaxPower = atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetMinPulseLength(double *pMinPulseLength)
{
  char data[64];

  if(!GetAttributeValue("TxPulseLength", "min", data, 64))
    return 0;
 
  *pMinPulseLength = atof(data);

  return 1;
}


DWORD C7kXMLParsor::GetMaxPulseLength(double *pMaxPulseLength)
{
  char data[64];

  if(!GetAttributeValue("TxPulseLength", "max", data, 64))
    return 0;
 
  *pMaxPulseLength = atof(data);

  return 1;
}


DWORD C7kXMLParsor::GetSystemText(char *pText, DWORD dwTextLength)
{
  return GetText("Name", pText, dwTextLength);
}

DWORD C7kXMLParsor::GetRxFirstBeamPos(double *pFirst)
{
  char data[64];

  if(!GetAttributeValue("RxBeamPosition", "first", data, 64))
    return 0;
 
  *pFirst = atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetRxLastBeamPos(double *pLast)
{
  char data[64];

  if(!GetAttributeValue("RxBeamPosition", "last", data, 64))
    return 0;
 
  *pLast = atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetSonarType(DWORD *pSonarType)
{
  char data[64];

  if(!GetAttributeValue("SonarType", "type", data, 64))
    return 0;
 
  *pSonarType = atoi(data);

  return 1;
}

DWORD C7kXMLParsor::GetArrayType(DWORD *pArrayType)
{
  char data[64];

  if(!GetAttributeValue("ArrayType", "type", data, 64))
    return 0;
 
  *pArrayType = atoi(data);

  return 1;
}

DWORD C7kXMLParsor::GetRxElements(DWORD *pRxElements)
{
  DWORD min, max;

  char data[64];

  if(!GetAttributeValue("RxElements", "min", data, 64))
    return 0;

  min = atoi(data);

  if(!GetAttributeValue("RxElements", "max", data, 64))
    return 0;
 
  max = atoi(data);

  *pRxElements = max - min + 1;

  return 1;
}

DWORD C7kXMLParsor::GetRxBeams(DWORD *pRxBeams)
{
  DWORD min, max;
  char data[64];

  *pRxBeams = 0;

  if(!GetAttributeValue("RxBeams", "min", data, 64))
    return 0;

  min = atoi(data);

  if(!GetAttributeValue("RxBeams", "max", data, 64))
    return 0;
 
  max = atoi(data);

  *pRxBeams = max - min + 1;

  return 1;
}

DWORD C7kXMLParsor::GetRxBeamSpacing(float *pBeamSpacing, BOOL * pUniform)
{
  char data[64];

  if(!GetAttributeValue("RxBeamSpacing", "uniform", data, 64))
    return 0;

  if(_strnicmp(data, "yes", strlen(data)))
    *pUniform = FALSE;
  else
    *pUniform = TRUE;

  // TODO: implement non uniform case.

  if(!GetAttributeValue("RxBeamSpacing", "angles", data, 64))
    return 0;
 
  *pBeamSpacing = (float)atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetRxBeamWidth(float * pAcross, BOOL * pUniformAcross, float * pAlong, BOOL * pUniformAlong)
{
  DWORD i, pos, value_index, beams;
  float x;
  char * data = new char[1024*1024];
  char value[64];

  if(!GetRxBeams(&beams))
    return 0;

  if(!GetAttributeValue("RxBeamWidth", "uniformacross", data, 64))
    return 0;

  if(_strnicmp(data, "yes", strlen(data)))
    *pUniformAcross = FALSE;
  else
    *pUniformAcross = TRUE;

  if(!GetAttributeValue("RxBeamWidth", "uniformalong", data, 64))
    return 0;

  if(_strnicmp(data, "yes", strlen(data)))
    *pUniformAlong = FALSE;
  else
    *pUniformAlong = TRUE;

  if(!GetAttributeValue("RxBeamWidth", "across", data, 1024 * 1024))
    return 0;
 
  if(*pUniformAcross)
  {
    x = (float)atof(data);
    for(i=0;i<beams;i++)
      pAcross[i] = x;  
  }
  else
  { 
    pos = 0;
    for(i=0;i<beams;i++)
    {
      value_index = 0;
      while(data[pos] != ' ' && data[pos] != '\0')
      {
        value[value_index] = data[pos];
        value_index ++;
        pos ++;
      }
      pos++;

      value[value_index] = '\0';
      pAcross[i] = (float)atof(value);  
    }
  }

  if(!GetAttributeValue("RxBeamWidth", "along", data, 64))
    return 0;
 
  *pAlong = (float)atof(data);

  delete data;
  data = NULL;

  return 1;
}

DWORD C7kXMLParsor::GetRxBeamPositions(double *pFirstBeam, double *pLastBeam)
{
  char data[64];

  if(!GetAttributeValue("RxBeamPosition", "first", data, 64))
    return 0;
 
  *pFirstBeam = atof(data);

  if(!GetAttributeValue("RxBeamPosition", "last", data, 64))
    return 0;
 
  *pLastBeam = atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetTxBeams(DWORD *pTxBeams)
{
  DWORD min, max;

  char data[64];

  if(!GetAttributeValue("TxBeams", "min", data, 64))
    return 0;

  min = atoi(data);

  if(!GetAttributeValue("TxBeams", "max", data, 64))
    return 0;
 
  max = atoi(data);

  *pTxBeams = max - min + 1;

  return 1;
}

DWORD C7kXMLParsor::GetTxBeamWidth(double * pMaxx, double * pMinx, double * pMaxz, double * pMinz, BOOL * pVariable)
{
  char data[4096];

  if(!GetAttributeValue("TxBeamWidth", "variable", data, 64))
    return 0;

  if(_strnicmp(data, "yes", strlen(data)))
    *pVariable = FALSE;
  else
    *pVariable = TRUE;

  if(!GetAttributeValue("TxBeamWidth", "maxx", data, 64))
    return 0;
 
  *pMaxx = (double)atof(data);

  if(!GetAttributeValue("TxBeamWidth", "minx", data, 64))
    return 0;
 
  *pMinx = (double)atof(data);
  
  if(!GetAttributeValue("TxBeamWidth", "maxz", data, 64))
    return 0;
 
  *pMaxz = (double)atof(data);

  if(!GetAttributeValue("TxBeamWidth", "minz", data, 64))
    return 0;
 
  *pMinz = (double)atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetTxBeamSpacing(float *pBeamSpacing, BOOL * pUniform)
{
  char data[64];

  if(!GetAttributeValue("TxBeamSpacing", "uniform", data, 64))
    return 0;

  if(_strnicmp(data, "yes", strlen(data)))
    *pUniform = FALSE;
  else
    *pUniform = TRUE;

  // TODO: implement non uniform case.

  if(!GetAttributeValue("TxBeamSpacing", "angles", data, 64))
    return 0;
 
  *pBeamSpacing = (float)atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetFrequency(double *pMinFrequency, double *pMaxFrequency, BOOL *pChirp)
{
  char data[64];

  if(!GetAttributeValue("Frequency", "chirp", data, 64))
    return 0;

  if(_strnicmp(data, "yes", strlen(data)))
    *pChirp = FALSE;
  else
    *pChirp = TRUE;

  if(!GetAttributeValue("Frequency", "min", data, 64))
    return 0;
 
  *pMinFrequency = (float)atof(data);

  if(!GetAttributeValue("Frequency", "max", data, 64))
    return 0;
 
  *pMaxFrequency = (float)atof(data);


  return 1;
}

DWORD C7kXMLParsor::GetSampleRate(float *pSampleRate)
{
  char data[64];

  if(!GetAttributeValue("SampleRate", "rate", data, 64))
    return 0;
 
  *pSampleRate = (float)atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetPower(float *pMinPower, float *pMaxPower)
{
  char data[64];

  if(!GetAttributeValue("Power", "min", data, 64))
    return 0;
 
  *pMinPower = (float)atof(data);

  if(!GetAttributeValue("Power", "max", data, 64))
    return 0;
 
  *pMaxPower = (float)atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetGain(float *pMinGain, float *pMaxGain)
{
  char data[64];

  if(!GetAttributeValue("Gain", "min", data, 64))
    return 0;
 
  *pMinGain = (float)atof(data);

  if(!GetAttributeValue("Gain", "max", data, 64))
    return 0;
 
  *pMaxGain = (float)atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetPulseLength(float *pMinPulseLength, float *pMaxPulseLength)
{
  char data[64];

  if(!GetAttributeValue("TxPulseLength", "min", data, 64))
    return 0;
 
  *pMinPulseLength = (float)atof(data);

  if(!GetAttributeValue("TxPulseLength", "max", data, 64))
    return 0;
 
  *pMaxPulseLength = (float)atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetRange(float *pMinRange, float *pMaxRange)
{
  char data[64];

  if(!GetAttributeValue("Range", "min", data, 64))
    return 0;
 
  *pMinRange = (float)atof(data);

  if(!GetAttributeValue("Range", "max", data, 64))
    return 0;
 
  *pMaxRange = (float)atof(data);

  return 1;
}

DWORD C7kXMLParsor::GetPingRate(double *pMinPingRate, double *pMaxPingRate)
{
  char data[64];

  try
  {
    if(!GetAttributeValue("PingRate", "min", data, 64))
      throw 0;
 
    *pMinPingRate = (double)atof(data);

    if(!GetAttributeValue("PingRate", "max", data, 64))
      throw 0;
 
    *pMaxPingRate = (double)atof(data);
  }
  catch(...)
  {
    *pMinPingRate = 1.0;
    *pMaxPingRate = 1.0;

    return 0;
  }

  return 1;
}

DWORD C7kXMLParsor::GetTxBeamSteeringParams(DWORD *pSteerable, double *pMaxX, double *pMinX, double *pMaxZ, double *pMinZ)
{
  char data[64];

  try
  {
    if(!GetAttributeValue("TxBeamSteering", "steerable", data, 64))
      throw 0;
 
    if(!_strnicmp(data, "yes", strlen(data)))
      *pSteerable = 1;
    else
      *pSteerable = 0;
    
    if(!*pSteerable)
    {
      *pMaxX = 0.0;
      *pMinX = 0.0;
      *pMaxZ = 0.0;
      *pMinZ = 0.0;
      return 1;
    }

    if(!GetAttributeValue("TxBeamSteering", "maxx", data, 64))
      throw 0;

    *pMaxX = (double)atof(data);

    if(!GetAttributeValue("TxBeamSteering", "minx", data, 64))
      throw 0;

    *pMinX = (double)atof(data);

    if(!GetAttributeValue("TxBeamSteering", "maxz", data, 64))
      throw 0;

    *pMaxZ = (double)atof(data);

    if(!GetAttributeValue("TxBeamSteering", "minz", data, 64))
      throw 0;

    *pMinZ = (double)atof(data);

  }
  catch(...)
  {
    *pSteerable = 0;
    *pMaxX      = 0.0;
    *pMinX      = 0.0;
    *pMaxZ      = 0.0;
    *pMinZ      = 0.0;

    return 0;
  }

  return 1;
}

DWORD C7kXMLParsor::GetTxStabilizationTypes(DWORD *pTypes)
{
  char data[64];

  if(!GetAttributeValue("TxBeamStabilization", "type", data, 64))
  {
    *pTypes = 0;
    return 0;
  }
 
  *pTypes = atoi(data);

  return 1;
}

DWORD C7kXMLParsor::GetRxStabilizationTypes(DWORD *pTypes)
{
  char data[64];

  if(!GetAttributeValue("RxBeamStabilization", "type", data, 64))
  {
    *pTypes = 0;
    return 0;
  }
 
  *pTypes = atoi(data);

  return 1;

}
