///////////////////////////////////////////////////////////////////////////////
/// @file deLog.cpp
///
/// @brief Error and Logging 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 Dec 2001
/// @author Hootie
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////


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

#include <windows.h> // for DllMain
#include "deLogDestiny.hpp"
#include "deArray.hpp"



//=================================================================================
// Local Function Prototypes
//=================================================================================

static deBoolean ProcessRegistryEntries(void);
static deBoolean LoadErrorMessages(deTArray<deString*> Array, deConfigFile *ConfigFile);
static deBoolean CreateLog(void);
static deBoolean DestroyLog(void);



//=================================================================================
// Log Types
//
// These are the types of Log objects currently supported. The values of these
// strings are the possible values for parameter "LogType" in the config
// file.  Except for bug fixes in the existing types, it would be a good idea to 
// create brand new types for anything new.  That will keep backward compatibility
// in tact.
//=================================================================================

char DestinyLogType[] = "Destiny";



//=================================================================================
// Global DLL Memory
//=================================================================================

deConfigFile *ConfigFile = NULL;
deTArray<deString*> DestinyErrors;
deTArray<deString*> UserErrors;
char ErrorFileDir[_MAX_PATH + 1] = "";
char LogFileDir[_MAX_PATH + 1] = "";
IdeLog *deLog = NULL;
char *LogType = NULL;
char GlobalLogName[120];
int deLogProcessCount = 0;



//=================================================================================
// DllMain()
//
// Dll startup code.
//
// This is the entry point for other processes using the Error and Logging object.
// This function gets called whenever another program does a LoadLibrary() on this
// DLL.  This keeps a reference counter (deLogProcessCount) of the number of processes
// currently connected to this instance of the DLL.  Once the reference count goes to 
// zero, the Log object is destroyed. 
//=================================================================================

BOOL WINAPI IdeLog_DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	lpvReserved = hinstDLL = 0;
	if (fdwReason == DLL_PROCESS_ATTACH)
	{
		deLogProcessCount++;
		
		if (deLogProcessCount == 1)
		{
			if (!ProcessRegistryEntries())
			{
				// error - Create failed
				return FALSE;
			}
			
			if (!CreateLog())
			{
				// error - Create failed
				return FALSE;
			}
		}
	} 
	
	
	if (fdwReason == DLL_PROCESS_DETACH)
	{
		deLogProcessCount--;
		
		if (deLogProcessCount == 0)
		{
			if (!DestroyLog())
			{
				// error - Destroy failed
				return FALSE;
			}
		}
	}
	
	return TRUE; 
}



//=================================================================================
// ProcessRegistryEntries()
//
// Process the Registry entries related to deLog
//=================================================================================

static deBoolean ProcessRegistryEntries(void)
{
#pragma fixme(the ConfigFile stuff here needs to be revamped)
#if 0
   deRegistry Registry;
   deConfigFile *DestinyErrorConfig = NULL;
   deConfigFile *UserErrorConfig = NULL;
   char AppName[120] = "";
   char RegCurrentAppKey[120] = "";
   char DestinyConfigPath[_MAX_PATH + 1] = "";
   char DestinyErrorCfgPath[_MAX_PATH + 1] = "";
   char UserErrorCfgPath[_MAX_PATH + 1] = "";
   int BufferLength = 0;


   if (deLog)
   {
      // Error - Log already exists
      return deFALSE;
   }


   // Get the current running app's name from the registry

   BufferLength = 120;

   if (!Registry.ReadString(RegEngineKey, RegCurrentAppValue, AppName, &BufferLength))
   {
      // error - engine key problem
      return deFALSE;
   }

   if (strlen(AppName) == 0)
   {
      // error - App name not set
      return deFALSE;
   }


   // Get the path from the registry to the current app's Destiny config file

   strcpy(RegCurrentAppKey, RegDestinyKey);
   strcat(RegCurrentAppKey, AppName);

   BufferLength = _MAX_PATH + 1;

   if (!Registry.ReadString(RegCurrentAppKey, RegDestinyConfigPathValue, DestinyConfigPath, &BufferLength))
   {
      // error - Destiny config file path problem
      return deFALSE;
   }


   // Get the path from the registry to the engine's error message config file

   BufferLength = _MAX_PATH + 1;

   if (!Registry.ReadString(RegEngineKey, RegDestinyErrorMsgPathValue, DestinyErrorCfgPath, &BufferLength))
   {
      // error - Engine error message file path not found
      return deFALSE;
   }

   if (strlen(DestinyErrorCfgPath) == 0)
   {
      // error - Engine error message file path not set
      return deFALSE;
   }


   // Get the path from the registry to the current app's user error message config file

   BufferLength = _MAX_PATH + 1;

   if (!Registry.ReadString(RegCurrentAppKey, RegUserErrorMsgPathValue, UserErrorCfgPath, &BufferLength))
   {
      // error - Destiny config file path problem
      return deFALSE;
   }


   // Get the path for the error output file directory

   BufferLength = _MAX_PATH + 1;

   if (!Registry.ReadString(RegCurrentAppKey, RegErrorDirectoryValue, ErrorFileDir, &BufferLength))
   {
      // error - Error file output directory not found
      return deFALSE;
   }


   // Get the path for the log output file directory

   BufferLength = _MAX_PATH + 1;

   if (!Registry.ReadString(RegCurrentAppKey, RegLogDirectoryValue, LogFileDir, &BufferLength))
   {
      // error - Log file output directory not found
      return deFALSE;
   }


   // Create config file objects for the Destiny.cfg and the error message files

   ConfigFile = new deConfigFile(DestinyConfigPath);

   if (!ConfigFile)
   {
      // error - Could not create a ConfigFile object
      return deFALSE;
   }
   
   if (!ConfigFile->GetCreationResult())
   {
      // error - Config file load & parse failed
      delete ConfigFile;
      return deFALSE;
   }

   DestinyErrorConfig = new deConfigFile(DestinyErrorCfgPath);

   if (!DestinyErrorConfig)
   {
      // error - Could not create a ConfigFile object
      return deFALSE;
   }
   
   if (!DestinyErrorConfig->GetCreationResult())
   {
      // error - Config file load & parse failed
      delete ConfigFile;
      delete DestinyErrorConfig;
      return deFALSE;
   }

   UserErrorConfig = new deConfigFile(UserErrorCfgPath);

   if (!UserErrorConfig)
   {
      // error - Could not create a ConfigFile object
      return deFALSE;
   }
   
   if (!UserErrorConfig->GetCreationResult())
   {
      // error - Config file load & parse failed
      delete ConfigFile;
      delete DestinyErrorConfig;
      delete UserErrorConfig;
      return deFALSE;
   }


   // Load the error message arrays

   if (!LoadErrorMessages(DestinyErrors, DestinyErrorConfig))
   {
      // error - Engine error message load failed
      delete ConfigFile;
      delete DestinyErrorConfig;
      delete UserErrorConfig;
      return deFALSE;
   }

   if (!LoadErrorMessages(UserErrors, UserErrorConfig))
   {
      // error - User error message load failed
      delete ConfigFile;
      delete DestinyErrorConfig;
      delete UserErrorConfig;
      return deFALSE;
   }


   delete DestinyErrorConfig;
   delete UserErrorConfig;
   return deTRUE;
#endif
   return deFALSE;
}



//=================================================================================
// LoadErrorMessages()
//
// Load an error message config file into an array object
//=================================================================================

static deBoolean LoadErrorMessages(deTArray<deString*> Array, deConfigFile* /*ConfigFile*/)
{
#pragma fixme(the ConfigFile stuff here needs to be revamped)
#if 0
   deString *ErrorMessage;
   char *KeyName = NULL;
   char *KeyValue = NULL;
   int ErrorSub = 0;
   deBoolean ReturnValue;


   // Create the error messages array object

   Array.Reserve(100);

   ReturnValue = ConfigFile->GetFirstKeyValue(&KeyName, &KeyValue);

   if (ReturnValue == deFALSE)
   {
      // error - Error message config file empty
      return deFALSE;
   }

   for (;;)
   {
      if (ReturnValue == deFALSE)
         break;

      ErrorSub = atoi(KeyName);

      if (ErrorSub > 99999)
         ErrorSub = ErrorSub - 100000;

      ErrorMessage = new deString(KeyValue);

	  if (Array.size() <= ErrorSub)
	  {
		  if (!Array.resize(ErrorSub+1))
		  {
			  //error - Array resize failed
			  return deFALSE;
		  }
	  }
      Array[ErrorSub] = ErrorMessage;

      ReturnValue = ConfigFile->GetNextKeyValue(&KeyName, &KeyValue);
   }


   return deTRUE;
#endif
   return deFALSE;
}



//=================================================================================
// CreateLog()
//
// Initialize the Main Log object.  
//=================================================================================

static deBoolean CreateLog(void)
{
#pragma fixme(the ConfigFile stuff here needs to be revamped)
#if 0
   // Get the Log object type to create

   LogType = ConfigFile->FindKeyValue(ConfigLogType);
   
   if (!LogType)
   {
      // error - Log type key missing
      delete ConfigFile;
      return deFALSE;
   }


   // Create the main Log object based on type specified in config file

   if (strcmp(LogType, DestinyLogType) == 0)
   {
      deLog = new deLogDestiny(NULL);
   }
   else
   {
      // error - Invalid Log type
      delete ConfigFile;
      return deFALSE;
   }

   if (!deLog)
   {
      // error - Log object create failed
      delete ConfigFile;
      return deFALSE;
   }

   if (!deLog->GetCreationResult())
   {
      // error - Log object create failed
      delete deLog;
      delete ConfigFile;
      return deFALSE;
   }

   return deTRUE;
#endif
   return deFALSE;
}



//=================================================================================
// DestroyLog()
//
// Destroy the main Log object and any other dynamic objects.  We be done 
// and Windows is going to trash our DLL home real soon now.
//=================================================================================

static deBoolean DestroyLog(void)
{
#pragma fixme(the ConfigFile stuff here needs to be revamped)
#if 0
   deString *StringVal = NULL;
   unsigned int ArraySize = 0;
   unsigned int looper = 0;


   if (deLog)
      delete deLog;

   if (ConfigFile)
      delete ConfigFile;

   ArraySize = DestinyErrors.size();

   for (looper = 0; looper < ArraySize; looper++)
   {
      StringVal = (deString *)DestinyErrors[looper];
      delete StringVal;
   }

   DestinyErrors.resize(0);

   ArraySize = UserErrors.size();

   for (looper = 0; looper < ArraySize; looper++)
   {
      StringVal = (deString *)UserErrors[looper];
      delete StringVal;
   }

   UserErrors.resize(0);

   return deTRUE;
#endif
   return deFALSE;
}



//=================================================================================
// GetIdeLogInterface()
//
// This is an exported function call in the DLL.  It is the only access point 
// for the outside world.  A call to this function will return an interface pointer
// good for an IdeLog interfaced error and logging object.  If new interfaces 
// are created, leave this alone and create another export function to feed the new 
// interface objects.  That will maintain backward compatibility. 
//=================================================================================

IdeLog *GetIdeLogInterface(char *LogName)
{
   if (LogName == NULL)
   { 
      if (deLog)
      {
         return deLog;
      }
   }
   else
   {
      if (strcmp(LogType, DestinyLogType) == 0)
      {
         return new deLogDestiny(LogName);
      }
      else
      {
         // error - Invalid Log type
         return NULL;
      }
   }

   //Error - Valid log object does not exist
   return NULL;
}






