// AdvDatabase.cpp - database
//
//  Public functions
//    loadObjectDescriptions
//    loadDescriptionArray
//    unloadObjectDescriptions
//    unloadDescriptionArray
//
//  Private functions

#include "stdafx.h"
#include "malloc.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#include "AdvDatabase.h"
#include "AdvIO.h"
#include "Encode.h"

/////////////////////
// Forward references
void freeTextLines
  (TEXTLINES*  pTextLines);

///////////////////
// Public functions

bool loadObjectDescriptions
  (AdvGlobalContext&    gc,                 // global context
   OBJECT_DESCRIPTOR*   objectArray,        // object description array
   long                 nArraySize,         // size of array
   char*                szFilespec,         // filespec to load from
   long&                nEntriesLoaded)     // buffer to receive # entries loaded
//
//  Loads an object description array with up to nArraySize descriptions from
//  the file szFilespec.
//
//  Returns true on success, false otherwise.
//
{
char  szDatabaseFilespec [255];   // database filespec

  // Open datafile - return if unable
  // strcpy (szDatabaseFilespec, gc.m_szExeDir);
  strcpy (szDatabaseFilespec, "C:\\");
  strcat (szDatabaseFilespec, szFilespec);
  FILE* fp = fopen (szDatabaseFilespec, "r");
  if (fp == NULL)
     {
       displayError (ERR_CANT_OPEN_FILE, szDatabaseFilespec, NULL, NULL);
       return (false);
     }

  // Create decoder pattern
  char  szSourceCharSet [80];
  char  szPatternCharSet [80];
  strcpy (szSourceCharSet, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,;!?@#$%^&*()_+={}[]|\\/");
  strcpy (szPatternCharSet, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,;!?@#$%^&*()_+={}[]|\\/");
  createEncoderPattern (ENCODER_KEY, szSourceCharSet, szPatternCharSet);
  strcpy (szSourceCharSet, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,;!?@#$%^&*()_+={}[]|\\/");

  // For each line read from file ...
  char      szSourceLine [MAX_ENCODER_LINE_LENGTH];
  long      nLineCounter = 0;
  long      nCurrentEntry = 0;
  long      nCurrentObject = 0;
  long      nCurrentState = 0;
  long      nPrevEntry = 0;

  while (fgets (szSourceLine, MAX_ENCODER_LINE_LENGTH - 1, fp) != NULL)
      {
        // Decode line
        nLineCounter++;
        szSourceLine [strlen (szSourceLine) - 1] = '\0';
        encodeLine (false, szSourceCharSet, szPatternCharSet, szSourceLine);

        // Get entry number - return if unable
        if (sscanf (szSourceLine, "%d", &nCurrentEntry) != 1)
           {
             displayError (ERR_INVALID_DATAFILE_ENTRY, szFilespec, szSourceLine, NULL);
             fclose (fp);
             return (false);
           }

        // Set object/state number
        if (nCurrentEntry > 0)
           {
             nCurrentObject = nCurrentEntry;
             nCurrentState = 0;
           }
        else
           nCurrentState = -nCurrentEntry;

        // Return if too many entries
        if (nCurrentObject > nArraySize)
           {
             displayError (ERR_TOO_MANY_ENTRIES, szFilespec, NULL, NULL);
             fclose (fp);
             return (false);
           }

        // Store inventory description
        if (nCurrentState == 0)
           {
             char*  pszInventory = (char *) malloc (strlen (szSourceLine) - 8 + 1);
             strcpy (pszInventory, & (szSourceLine [8]));
             objectArray [nCurrentEntry].pszInventory = pszInventory;
             continue;
           }

        // Store state description
        PTR_TEXTLINES  pTextLine = (TEXTLINES *) malloc (sizeof (TEXTLINES));
        pTextLine->pszText = (char *) malloc (strlen (szSourceLine) - 8 + 1);
        pTextLine->pNext = NULL;
        strcpy (pTextLine->pszText, & (szSourceLine [8]));

        // Storing new state ...
        if (nCurrentState > objectArray [nCurrentObject].nStates)
           {
             objectArray [nCurrentObject].stateDescriptions [nCurrentState - 1] = pTextLine;
             objectArray [nCurrentObject].nStates++;
             continue;
           }

        // Adding a line to an existing state
        PTR_TEXTLINES  pTextLinePrev = objectArray [nCurrentObject].stateDescriptions [nCurrentState - 1];
        while (pTextLinePrev->pNext != NULL)
               pTextLinePrev = pTextLinePrev->pNext;
        pTextLinePrev->pNext = pTextLine;
      }

  // Close datafile and return successfully
  fclose (fp);
  nEntriesLoaded = nCurrentObject;
  return (true);
}

void unloadObjectDescriptions
  (OBJECT_DESCRIPTOR*   descriptionArray,   // object description array
   long                 nArraySize)         // array size
//
//  Frees memory occupied by an object description array.
//
{
}

bool loadDescriptionArray
  (AdvGlobalContext&  gc,                 // global context
   PTR_TEXTLINES*     descriptionArray,   // description array
   long               nArraySize,         // size of array
   char*              szFilespec,         // filespec to load from
   long&              nEntriesLoaded)     // buffer to receive # entries loaded
//
//  Loads a description array with up to nArraySize descriptions from
//  the file szFilespec.
//
//  Returns true on success, false otherwise.
//
{
char  szDatabaseFilespec [255];   // database filespec

  // Open datafile - return if unable
  // strcpy (szDatabaseFilespec, gc.m_szExeDir);
  strcpy (szDatabaseFilespec, "C:\\");
  strcat (szDatabaseFilespec, szFilespec);
  FILE* fp = fopen (szDatabaseFilespec, "r");
  if (fp == NULL)
     {
       displayError (ERR_CANT_OPEN_FILE, szDatabaseFilespec, NULL, NULL);
       return (false);
     }

  // Create decoder pattern
  char  szSourceCharSet [80];
  char  szPatternCharSet [80];
  strcpy (szSourceCharSet, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,;!?@#$%^&*()_+={}[]|\\/");
  strcpy (szPatternCharSet, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,;!?@#$%^&*()_+={}[]|\\/");
  createEncoderPattern (ENCODER_KEY, szSourceCharSet, szPatternCharSet);
  strcpy (szSourceCharSet, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,;!?@#$%^&*()_+={}[]|\\/");

  // For each line read from file ...
  char      szSourceLine [MAX_ENCODER_LINE_LENGTH];
  long      nLineCounter = 0;
  long      nCurrentEntry = 0;
  long      nPrevEntry = 0;

  while (fgets (szSourceLine, MAX_ENCODER_LINE_LENGTH - 1, fp) != NULL)
      {
        // Decode line
        nLineCounter++;
        szSourceLine [strlen (szSourceLine) - 1] = '\0';
        encodeLine (false, szSourceCharSet, szPatternCharSet, szSourceLine);

        // Get entry number - return if unable
        if (sscanf (szSourceLine, "%d", &nCurrentEntry) != 1)
           {
             displayError (ERR_INVALID_DATAFILE_ENTRY, szFilespec, szSourceLine, NULL);
             fclose (fp);
             return (false);
           }

        // Return if too many entries
        if (nCurrentEntry > nArraySize)
           {
             displayError (ERR_TOO_MANY_ENTRIES, szFilespec, NULL, NULL);
             fclose (fp);
             return (false);
           }

        // Create TEXTLINES node - return if unable
        TEXTLINES*  pTextLine = (TEXTLINES *) malloc (sizeof (TEXTLINES));
        if (pTextLine == NULL)
           {
             char szNumber [8];
             sprintf (szNumber, "%d", nLineCounter);
             displayError (ERR_OUT_OF_MEMORY_READ_FILE, szNumber, szFilespec, NULL);
             return (false);
           }
        pTextLine->pNext = NULL;

        pTextLine->pszText = (char *) malloc (strlen (szSourceLine) - 8 + 1);
        if (pTextLine->pszText == NULL)
           {
             char szNumber [8];
             sprintf (szNumber, "%d", nLineCounter);
             displayError (ERR_OUT_OF_MEMORY_READ_FILE, szNumber, szFilespec, NULL);
             return (false);
           }
        strcpy (pTextLine->pszText, & (szSourceLine [8]));

        // Add TEXTLINES node to description array
        if (descriptionArray [nCurrentEntry] == NULL)
           descriptionArray [nCurrentEntry] = pTextLine;
        else
           {
             TEXTLINES* pPrevTextLine = descriptionArray [nCurrentEntry];
             while (pPrevTextLine->pNext != NULL)
                   pPrevTextLine = pPrevTextLine->pNext;
             pPrevTextLine->pNext = pTextLine;
           }
      }

  // Close datafile and return successfully
  fclose (fp);
  nEntriesLoaded = nCurrentEntry + 1;
  return (true);
}

void unloadDescriptionArray
  (PTR_TEXTLINES*   descriptionArray,   // description array
   long             nArraySize)         // size of array
//
//  Frees memory used by a description array.
//
{
  for (long nIndex=0; (nIndex < nArraySize); nIndex++)
      freeTextLines (descriptionArray[nIndex]);
}

////////////////////
// Private functions

void freeTextLines
  (TEXTLINES*   pTextLines)   // list of text lines
//
//  Frees a linked list of text lines.
//
{
  if (pTextLines != NULL)
     {
       // First free rest of list
       if (pTextLines->pNext != NULL)
          {
            freeTextLines (pTextLines->pNext);
            pTextLines->pNext = NULL;
          }

       // Then free this node
       free (pTextLines->pszText);
       free (pTextLines);
     }
}
