///////////////////////////////////////////////////////////////////////////////
/// @file deConfigFile.cpp
///
/// @brief Non-deFile Config File Class
///
/// @author Hootie
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Oct 2001
/// @author Hootie
/// @remarks Rearchitecture II
///
///////////////////////////////////////////////////////////////////////////////


//=================================================================================
// Includes
//=================================================================================

#include "deShared.hpp"



//=================================================================================
// deConfigFile::deConfigFile()
//
// Constructor 
//=================================================================================
deConfigFile::deConfigFile(char *FullFilePath)
{
   CreationResult = deFALSE;
   FileBuffer = NULL;
   TotalConfigEntries = 0;
   CurrentEntry = -1;
   unsigned int FileSize = 0;
   ConfigKeys = NULL;
   ConfigValues = NULL;


   if (FullFilePath == NULL || strlen(FullFilePath) == 0)
      return;

   FileSize = LoadFileBuffer(FullFilePath);

   if (FileSize == 0)
      return;

   if (!ParseFileBuffer())
   {
      delete FileBuffer;
      return;
   }

   CreationResult = deTRUE;
}



//=================================================================================
// deConfigFile::LoadFileBuffer()
//
// Load the config file into the buffer.
//=================================================================================
unsigned int deConfigFile::LoadFileBuffer(char *FullFilePath)
{
   deWinFile ConfigFile;
   unsigned int FileSize = 0;
   unsigned int FileBytesRead = 0;

   if (!ConfigFile.Open(FullFilePath, DEWINFILE_READONLY, DEWINFILE_EXISTS))
   {
      // error - File open error
      return 0;
   }

   FileSize = ConfigFile.GetSize();

   if (FileSize == 0)
   {
      // error - Config file empty

      if (!ConfigFile.Close())
      {
         // error - File close problem
      }

      return 0;
   }

   FileBuffer = new char[FileSize];

   if (!FileBuffer)
   {
      // error - Could not get memory for buffer
      return 0;
   }

   FileBytesRead = ConfigFile.Read(FileBuffer, FileSize);

   if (FileBytesRead != FileSize)
   {
      // error - Something wrong with the read

      if (!ConfigFile.Close())
      {
         // error - File close problem
      }

      delete FileBuffer;
      return 0;
   }

   if (!ConfigFile.Close())
   {
      // error - File close problem
      delete FileBuffer;
      return 0;
   }

   return FileSize;
}



//=================================================================================
// deConfigFile::ParseFileBuffer()
//
// Parses the config file and fills in the pointer tables.
//=================================================================================
deBoolean deConfigFile::ParseFileBuffer(void)
{
   char *Pointer = NULL;

   ConfigKeys = new deDynamicArray(sizeof(char *), 100);
   ConfigValues = new deDynamicArray(sizeof(char *), 100);

   TotalConfigEntries++;

   Pointer = strtok((char *)FileBuffer, "=");

   if (!Pointer)
   {
      //error - not a valid config file
      delete ConfigKeys;
      delete ConfigValues;
      TotalConfigEntries = 0;
      return deFALSE;
   }

   ConfigKeys->SetElement(&Pointer, 0);

   Pointer = strtok(NULL, "\r\n");

   if (!Pointer)
   {
      //error - not a valid config file
      delete ConfigKeys;
      delete ConfigValues;
      TotalConfigEntries = 0;
      return deFALSE;
   }

   ConfigValues->SetElement(&Pointer, 0);

   for(;;)
   {
      TotalConfigEntries++;

      Pointer = strtok(NULL, "=");

      if (!Pointer)
      {
         TotalConfigEntries--;
         break;
      }

      Pointer = (char *)((long)Pointer + 1);

      ConfigKeys->SetElement(&Pointer, TotalConfigEntries - 1);

      Pointer = strtok(NULL, "\r\n");

      if (!Pointer)
      {
         TotalConfigEntries--;
         break;
      }

      ConfigValues->SetElement(&Pointer, TotalConfigEntries - 1);
   }

   CurrentEntry = 0;
   return deTRUE;
}



//=================================================================================
// deConfigFile::~deConfigFile()
//
// Destructor 
//=================================================================================
deConfigFile::~deConfigFile()
{
   if (FileBuffer)
   {
      delete FileBuffer;
   }

   if (ConfigKeys)
   {
      delete ConfigKeys;
   }

   if (ConfigValues)
   {
      delete ConfigValues;
   }
}



//=================================================================================
// deConfigFile::FindKeyValue()
//
// Return the value for a specified key.
//=================================================================================
char *deConfigFile::FindKeyValue(const char *KeyName)
{
   int looper = 0;
   char **Pointer;


   if (KeyName == NULL || strlen(KeyName) == 0 ||
       TotalConfigEntries == 0)
      return NULL;

   for(looper = 0; looper < TotalConfigEntries; looper++)
   {
      Pointer = (char **)ConfigKeys->GetElement(looper);

      if (strcmp(*Pointer, KeyName) == 0)
         break;
   }

   if (looper > (TotalConfigEntries - 1))
      return NULL;

   CurrentEntry = looper;
   Pointer = (char **)ConfigValues->GetElement(looper);
   return *Pointer;
}



//=================================================================================
// deConfigFile::FindNextKeyValue()
//
// Return the value for a next specified key.
//=================================================================================
char *deConfigFile::FindNextKeyValue(const char *KeyName)
{
   int looper = 0;
   char **Pointer;


   if (KeyName == NULL || strlen(KeyName) == 0 ||
       TotalConfigEntries == 0)
      return NULL;

   for (looper = (CurrentEntry + 1); looper < TotalConfigEntries; looper++)
   {
      Pointer = (char **)ConfigKeys->GetElement(looper);

      if (strcmp(*Pointer, KeyName) == 0)
         break;
   }

   if (looper > (TotalConfigEntries - 1))
      return NULL;

   CurrentEntry = looper;
   Pointer = (char **)ConfigValues->GetElement(looper);
   return *Pointer;
}



//=================================================================================
// deConfigFile::GetFirstKeyValue()
//
// Return first key and value in config file. 
//=================================================================================
deBoolean deConfigFile::GetFirstKeyValue(char **KeyName, char **KeyValue)
{
   char **Pointer;


   if (TotalConfigEntries == 0)
   {
      KeyName = NULL;
      KeyValue = NULL;
      return deFALSE;
   }

   CurrentEntry = 0;

   Pointer = (char **)ConfigKeys->GetElement(0);
   *KeyName = *Pointer;
   Pointer = (char **)ConfigValues->GetElement(0);
   *KeyValue = *Pointer;

   return deTRUE;
}



//=================================================================================
// deConfigFile::GetNextKeyValue()
//
// Returns next key and value in config file.
//=================================================================================
deBoolean deConfigFile::GetNextKeyValue(char **KeyName, char **KeyValue)
{
   char **Pointer;


   if (TotalConfigEntries == 0 || TotalConfigEntries == (CurrentEntry + 1))
   {
      KeyName = NULL;
      KeyValue = NULL;
      return deFALSE;
   }

   CurrentEntry++;

   Pointer = (char **)ConfigKeys->GetElement(CurrentEntry);
   *KeyName = *Pointer;
   Pointer = (char **)ConfigValues->GetElement(CurrentEntry);
   *KeyValue = *Pointer;

   return deTRUE;
}



//=================================================================================
// deConfigFile::GetPreviousKeyValue()
//
// Returns next key and value in config file.
//=================================================================================
deBoolean deConfigFile::GetPreviousKeyValue(char **KeyName, char **KeyValue)
{
   char **Pointer;


   if (TotalConfigEntries == 0 || CurrentEntry == 0)
   {
      KeyName = NULL;
      KeyValue = NULL;
      return deFALSE;
   }

   CurrentEntry--;

   Pointer = (char **)ConfigKeys->GetElement(CurrentEntry);
   *KeyName = *Pointer;
   Pointer = (char **)ConfigValues->GetElement(CurrentEntry);
   *KeyValue = *Pointer;

   return deTRUE;
}

