// Change History
// 12/03/03 AV Development: Code Cleanup. LFieldLength is not used

#include <io.h>
#include <stdio.h>
#include <string.h>

//#include <algorith>

#include "drs/drs_fieldmap.h"
#include "drs/drs_setting.h"
#include "drs/drs_progress.h"

//Constructor: file line + number of states in line
DRS_FieldMapEntry::DRS_FieldMapEntry( byte *instr, uint iStates)
  : iStateCount(iStates), m_iMaxLength( 0 )
{
  States.resize(iStates, NULL);
  byte * p = instr;
  uint len;

  for( uint i = 0; i < iStates; i++)
    {
    byte * delim;
    if( i < iStates - 1)
      {
      delim = ( i < iStates - 1) ? std::strstr( (char *) p, "::") : instr + std::strlen(instr);
      if( !delim) throw AT_Corrupt_Err( *this, instr);
      *delim = 0;
      }
    len = std::strlen(p);
    if( len > m_iMaxLength)
      m_iMaxLength = len;
    States[i] = new byte [len + 1];
    strcpy( States[i], p);
    p = delim + 2;
    }
}

//Assignment
DRS_FieldMapEntry const & DRS_FieldMapEntry::operator =( DRS_FieldMapEntry const &rEntry)
{
  //Clear existing mem
  for( uint i = 0; i < iStateCount; i++)
    delete [] States[i];

  m_iMaxLength = rEntry.m_iMaxLength;
  States.resize(iStateCount = rEntry.StateCount(), NULL);
  for( uint i = 0; i < iStateCount; i++)
    {
    States[i] = new byte [std::strlen(rEntry.State(i))+1];
    strcpy( States[i], rEntry.State(i));
    }

  return *this;
}

DRS_FieldMapEntry::~DRS_FieldMapEntry()
{
  //Clear existing mem
  for( uint i = 0; i < iStateCount; i++)
    delete [] States[i];
}

DRS_FieldMap::DRS_FieldMap( AT_String sFile, AT_String sSection, DRS_Setting BaseKey, byte *sMapFile)
  : iStateCount(0), m_iMaxEntryLength(0)
{
  DRS_Setting key( BaseKey);
  key += "StateCount";
  iStateCount = GetPrivateProfileInt( sSection, *key, 0, sFile);
  if( !iStateCount) throw AT_Corrupt_Err( *this, *key);

  aaStateDescriptors = new DRS_DescriptorSerialize [iStateCount];
  for( uint i = 0; i < iStateCount; i++)
    {
    key = BaseKey; key += "State"; key += i;
    aaStateDescriptors[i] = DRS_DescriptorSerialize( sFile, sSection, key);
    }

  //Read FieldMapEntries
  FILE *hFile = fopen( (const char *)sMapFile, (const char *) "rt");
  if( ! hFile) throw AT_File_Open_Err( *this, sMapFile);

  try
  {
  byte instr[256];
  //long lFileLength = filelength( fileno(hFile));
  while( !feof( hFile) && fgets( (char *)instr, 255, hFile))
    {
    DRS_FieldMapEntry * Entry = new DRS_FieldMapEntry( UTL_StringClean(instr), iStateCount);
    if( Entry->MaxLength() > m_iMaxEntryLength )
      m_iMaxEntryLength = Entry->MaxLength();
      
    vEntries.push_back( Entry);
    }
  }
  catch( AT_Error &err)
  {
    //clean-up and rethrow
    fclose( hFile);
    throw;
  }
  fclose( hFile);

  //Create sorted states
  aaSortedStates.push_back(std::vector<uint>(iStateCount, 0));
  for( uint i = 0; i < iStateCount; ++i)
    {
    aaSortedStates[i].resize(vEntries.size());
    for( uint j = 0; j < vEntries.size(); ++j)
      aaSortedStates[i][j] = j; //vEntries[j].State(i);
    }
  //Sort each list
  //Cannot use qsort as cannot pass member function as cmp routine.
  for( uint iSortingState = 0; iSortingState < iStateCount; ++iSortingState)
    SortState( aaSortedStates[iSortingState].begin(), iSortingState);

}

//Get entry by MapID: mapped data field retrieval
DRS_FieldMapEntry const & DRS_FieldMap::Entry( uint iEntry) const
{
  AT_Assert( (iEntry < Size()), *this, "Entry");
  return *vEntries[iEntry];
}

//Get entry by order in sorted state: mapped index selection
DRS_FieldMapEntry const & DRS_FieldMap::Entry( uint iEntry, uint iState) const
{
  AT_Assert( (iState < iStateCount), *this, "State");
  AT_Assert( (iEntry < Size()), *this, "Entry");
  return *vEntries[aaSortedStates[iState][iEntry]];
}

DRS_Descriptor const & DRS_FieldMap::State( uint iState) const
{
  AT_Assert( (iState < iStateCount), *this, "State");
  return aaStateDescriptors[iState];
}

uint DRS_FieldMap::StateEntryToFieldMapEntry( uint iState, uint iEntry) const
{
  AT_Assert( iState < iStateCount, *this, "State");
  AT_Assert( iEntry < vEntries.size(), *this, "State");
  return aaSortedStates[iState][iEntry];
}

class stateCmp
{
public :
  stateCmp
    (const std::vector<DRS_FieldMapEntry *>& v,
     uint *indexes,
     uint iS) :
      vEntries(v),
      entryIndexes(indexes),
      iState(iS)
  {
  }

  bool operator()
    (uint a,
     uint b)
  {
    return vEntries[entryIndexes[a]]->State(iState) <
           vEntries[entryIndexes[b]]->State(iState);
  }

private :
  const std::vector< DRS_FieldMapEntry *>& vEntries;
  uint *entryIndexes;
  const uint iState;
};

DRS_FieldMap::~DRS_FieldMap()
{
  uint i, cnt = vEntries.size();
  for(i = 0; i < cnt; ++i)
    delete vEntries[i];
}

void DRS_FieldMap::SortState( uint EntryIndexes[], uint iState)
{
  uint n = vEntries.size();

  stateCmp cmp(vEntries, EntryIndexes, iState);
  std::stable_sort(&EntryIndexes[0], &EntryIndexes[n], cmp);

  #if 0
  uint cycles = 0;
  for( int gap = n/2; 0 < gap; gap /= 2)
    {
    for( int i = gap; i < n; i++) cycles++;
    }
  uint curcycle = 0;
  for( int gap = n/2; 0 < gap; gap /= 2)
    {
    uint lProgress = (uint)(n - (gap * 2));
    for( int i = gap; i < n; i++)
      {
      curcycle += 1;
      oProgressWindow.Update( curcycle, cycles);
      for( int j = i - gap; 0 <= j; j-=gap)
        {
        if( std::strcmp( vEntries[EntryIndexes[j]].State(iState),
                    vEntries[EntryIndexes[j+gap]].State(iState)) > 0)
          {
          uint iTemp = EntryIndexes[j];
          EntryIndexes[j] = EntryIndexes[j+gap];
          EntryIndexes[j+gap] = iTemp;
          }
        }
      }
    }
  #endif
}


