/*

	CString csMessage;
	csMessage.Format("%d", );
	AfxMessageBox(csMessage);
 **********************************************************************
 *
 * Original Axis by:
 * Copyright (C) Philip A. Esterle 1998-2002 + (C) parts Adron 2002
 *
 * 55r,56(x) Mods, and Axis2 re-build by:
 * Copyright (C) Benoit Croussette 2004-2006
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 **********************************************************************

*/

// Axis2.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "Axis2.h"
#include "Axis2Dlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CAxis2App * Main;
/////////////////////////////////////////////////////////////////////////////
// CAxis2App

BEGIN_MESSAGE_MAP(CAxis2App, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CAxis2App construction

CAxis2App::CAxis2App()
{
	Main = this;
	EnableHtmlHelp();
	m_pcppAxisLogTab = NULL;
	m_pRConsole = NULL;
	m_iReceiveTimeout = 60000;
}


// The one and only CAxis2App object

CAxis2App theApp;


// CAxis2App initialization

BOOL CAxis2App::InitInstance()
{
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	//CWinApp::InitInstance();

	if (!AfxSocketInit())
	{
		AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
		return FALSE;
	}

	AfxEnableControlContainer();
	AfxInitRichEdit();

	m_pcppAxisLogTab = new CLogTab;
	m_pcppAxisLogTab->m_dcCurrentPage = m_pcppAxisLogTab;
	m_pScripts = new CScriptObjects;
	m_log.Add(0,"Starting %s, built %s", Main->GetVersionTitle(), Main->GetBuildTimestamp());
	m_csCurentProfile = "<None>";
	bMemoryAccess = AdjustPrivileges();

	//*******************************
	// Load the Default settings
	m_log.Add(0,"Loading Default Settings");
	LoadIni();
	m_dwInitiallize = 1;
	m_bkbrush.CreateSolidBrush(RGB(249,249,251));

	//*******************************
	// Load the Registry settings
	HKEY hKey;
	if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_AXIS, 0, KEY_READ, &hKey) == ERROR_SUCCESS )
	{
		m_log.Add(0,"Loading Registry Settings");
		m_dwAllowMultiple = GetRegistryDword("AllowMultipleInstances", m_dwAllowMultiple);
		m_dwAlwaysOnTop = GetRegistryDword("AlwaysOnTop", m_dwAlwaysOnTop);
		m_dwDrawDifs = GetRegistryDword("DrawDifs", m_dwDrawDifs);
		m_dwDrawStatics = GetRegistryDword("DrawStatics", m_dwDrawStatics);
		m_dwLoadDefault = GetRegistryDword("LoadDefault", m_dwLoadDefault);
		m_csPosition = GetRegistryString("Position", m_csPosition);
		m_dwRoomView = GetRegistryDword("RoomView", m_dwRoomView);
		m_dwSameAsClient = GetRegistryDword("SameAsCLient", m_dwSameAsClient);
		m_dwStartTab = GetRegistryDword("StartTab", m_dwStartTab);
		m_dwSysClose = GetRegistryDword("SysClose", m_dwSysClose);
		m_dwInitiallize = GetRegistryDword("Initallize", 1);
		m_dwShowSpawnpoints = GetRegistryDword("ShowSpawnpoints", m_dwShowSpawnpoints);
		m_dwNPCSpawnColor = GetRegistryDword("NPCSpawnColor", m_dwNPCSpawnColor);
		m_dwItemSpawnColor = GetRegistryDword("ItemSpawnColor", m_dwItemSpawnColor);
		m_dwShowItems = GetRegistryDword("ShowItems", m_dwShowItems);
		m_dwShowNPCs = GetRegistryDword("ShowNPCs", m_dwShowNPCs);
		m_dwShowMap = GetRegistryDword("ShowMap", m_dwShowMap);
	}
	RegCloseKey(hKey);

	//*******************************
	// Find the path to the UO client
	m_log.Add(0,"Looking for client installation");
	csUOPath = GetRegistryString("Default Client", "");

	if ( csUOPath == "" )
		csUOPath = GetRegistryString("ExePath", "", HKEY_LOCAL_MACHINE, "SOFTWARE\\Origin Worlds Online\\Ultima Online\\1.0");

	PutRegistryString("Default Client", csUOPath);

	if ( csUOPath == "" )
		m_log.Add(1,"ERROR: No client path specified. Check settings tab to manually set the path");
	else
	{
	//*******************************
	// Check Client info
	m_pClient = new CClientInfo;
	m_pClient->SetClientBuffer();
	m_log.Add(0,"Client version is %s", m_pClient->GetClientVersion());
	m_pClient->DeleteClientBuffer();

	m_log.Add(0,"Client path is %s", csUOPath);
	}

	//*******************************
	// Find the path to the UO Mul files

	csMulPath = GetRegistryString("Default MulPath", "");

	if ((( csMulPath == "" ) || (m_dwSameAsClient))&&( csUOPath != "" ))
	{
		csMulPath = csUOPath;
		csMulPath.SetAt(csUOPath.ReverseFind('\\')+1, 0x00);
	}

	PutRegistryString("Default MulPath", csMulPath);

	if ( csMulPath == "" )
		m_log.Add(1,"ERROR: No mulfile path specified. Check settings tab to manually set the path");
	else
		m_log.Add(0,"Mul path is %s", csMulPath);

	//*******************************
	// Find Default Profile Path

	csProfilePath = GetRegistryString("Default ProfilePath", "");
	if ( csProfilePath == "" )
	{
		CString pathSelected;
		CFolderDialog dlgfolder(&pathSelected, "Select the Default Profile folder");
		if (dlgfolder.DoModal() == IDOK)
			csProfilePath = pathSelected;
		else
			csProfilePath = "C:/Sphere";
		PutRegistryString("Default ProfilePath", csProfilePath);
	}
	m_log.Add(0,"Default profile path is %s", csProfilePath);

	//*******************************
	// Load Mul files

	InitializeMulPaths();

	CFile cfHues;
	CString csHueFile;
	csHueFile = saMulPaths.GetAt(VERFILE_HUES);
	if ( cfHues.Open( csHueFile, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone ) )
	{
		int iBytesRead = 1;
		while ( iBytesRead )
		{
			CHueGroup * pHueGroup = new (CHueGroup);
			iBytesRead = cfHues.Read( pHueGroup, sizeof(CHueGroup) );
			if ( iBytesRead )
			{
				m_aHueGroups.Add( pHueGroup );
			}
			else
				delete pHueGroup;

		}
		cfHues.Close();
	}
	else
		m_log.Add(1,"ERROR: Unable to open %s", csHueFile);

	//*******************************
	// Check for multiple instances
	m_log.Add(0,"Checking multiple instances");
	if (!m_dwAllowMultiple)
	{
		if (FindInstance())
		{
			return FALSE;
		}
	}

	CString csTitle;
	csTitle.Format( "%s - Press F1 for help", Main->GetVersionTitle() );
	CAxis2Dlg dlg(csTitle);
	dlg.m_psh.dwFlags = PSH_HASHELP | PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE;
	dlg.EnableStackedTabs( false );

	//*******************************
	// Create Tabs
	m_log.Add(0,"Creating Tabs");

	m_pcppGeneralTab = new CGeneralTab;
	m_pcppSettingsTab = new CSettingsTab;
	m_pcppProfileTab = new CProfileTab;
	m_pcppItemTab = new CItemTab;
	m_pcppItemTweakTab = new CItemTweakTab;
	m_pcppLauncherTab = new CLauncherTab;
	m_pcppSpawnTab = new CSpawnTab;
	m_pcppPlayerTweakTab = new CPlayerTweakTab;
	m_pcppTravelTab = new CTravelTab;
	m_pcppCommandsTab = new CCommandsTab;
	m_pcppAccountTab = new CAccountTab;

	//Settings Pages
	m_pcppSetGeneral = new CSettingsGeneral;
	m_pcppSetPaths = new CSettingsPaths;
	m_pcppSetItem = new CSettingsItem;
	m_pcppSetTravel = new CSettingsTravel;
	m_pcppSetSpawn = new CSettingsSpawn;

	dlg.AddPage(m_pcppGeneralTab);
	dlg.AddPage(m_pcppTravelTab);
	dlg.AddPage(m_pcppSpawnTab);
	dlg.AddPage(m_pcppPlayerTweakTab);
	dlg.AddPage(m_pcppItemTab);
	dlg.AddPage(m_pcppItemTweakTab);
	dlg.AddPage(m_pcppAccountTab);
	dlg.AddPage(m_pcppLauncherTab);
	dlg.AddPage(m_pcppProfileTab);
	//dlg.AddPage(m_pcppSettingsTab);
	dlg.AddPage(m_pcppCommandsTab);
	dlg.AddPage(m_pcppAxisLogTab);

	m_pMainWnd = &dlg;

	//*******************************
	//Check what tab we start with

	if (m_dwStartTab != -1)
	{
		switch(m_dwStartTab)
		{
		case 0:
			dlg.SetActivePage(m_pcppGeneralTab);
			break;
		case 1:
			dlg.SetActivePage(m_pcppTravelTab);
			break;
		case 2:
			dlg.SetActivePage(m_pcppSpawnTab);
			break;
		case 3:
			dlg.SetActivePage(m_pcppPlayerTweakTab);
			break;
		case 4:
			dlg.SetActivePage(m_pcppItemTab);
			break;
		case 5:
			dlg.SetActivePage(m_pcppItemTweakTab);
			break;
		case 6:
			dlg.SetActivePage(m_pcppAccountTab);
			break;
		case 7:
			dlg.SetActivePage(m_pcppLauncherTab);
			break;
		case 8:
			dlg.SetActivePage(m_pcppProfileTab);
			break;
		case 9:
			dlg.SetActivePage(m_pcppSettingsTab);
			break;
		case 10:
			dlg.SetActivePage(m_pcppCommandsTab);
			break;
		case 11:
			dlg.SetActivePage(m_pcppAxisLogTab);
			break;
		default:
			dlg.SetActivePage(m_pcppSettingsTab);
			break;
		}
	}

	//*******************************
	// Check to see if it the first time we run Axis
	if ( m_dwInitiallize == 1 )
	{
		dlg.SetActivePage(m_pcppSettingsTab);
		PutRegistryDword("Initallize", 0);
		PutRegistryString("Default Profile", "<Axis Profile>");
	}


	//*******************************
	// Loading default profile
	if (m_dwLoadDefault)
		CWinThread* m_pThreads=AfxBeginThread(LoadProfileThread,(LPVOID)1);

	m_log.Add(0,"Finished loading Axis");
	m_pcppAxisLogTab->SetVisible(true);
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
	}
	else if (nResponse == IDCANCEL)
	{
	}

	return TRUE;
}

CAxis2App::~CAxis2App()
{
	if ( m_pScripts )
		delete m_pScripts;

	if ( m_pClient )
		delete m_pClient;

	delete m_pcppGeneralTab;
	delete m_pcppTravelTab;
	delete m_pcppSpawnTab;
	delete m_pcppPlayerTweakTab;
	delete m_pcppItemTab;
	delete m_pcppItemTweakTab;
	delete m_pcppLauncherTab;
	delete m_pcppProfileTab;
	delete m_pcppSettingsTab;
	delete m_pcppCommandsTab;
	delete m_pcppAccountTab;
	delete m_pcppAxisLogTab;

	if (m_dlgWorldMap)
		delete m_dlgWorldMap;
	if (m_dlgDoorWiz)
		delete m_dlgDoorWiz;
	if (m_dlgLightWiz)
		delete m_dlgLightWiz;

	delete m_pcppSetGeneral;
	delete m_pcppSetPaths;
	delete m_pcppSetItem;
	delete m_pcppSetTravel;
	delete m_pcppSetSpawn;


	m_pcppAxisLogTab = NULL;

	//Clearing Log Array
	if (!m_olLog.IsEmpty())
	{
		POSITION Pos = m_olLog.GetHeadPosition();
		while (Pos != NULL)
		{
			CLogArray * pLog = (CLogArray *) m_olLog.GetNext(Pos);
			delete (pLog);
		}
	}
	m_olLog.RemoveAll();

	//Clearing Hues
	for ( int i = 0; i < m_aHueGroups.GetSize(); i++ )
	{
		CHueGroup * pHueGroup = (CHueGroup *) m_aHueGroups.GetAt(i);
		delete pHueGroup;
	}
	m_aHueGroups.RemoveAll();
}

//////////////////////////////////////////////////////////////////////////

BOOL CAxis2App::PreTranslateMessage(MSG* pMsg) 
{
	if ((pMsg->message == 256) && (pMsg->wParam == 27))
	{
		// this is the escape key
		return (TRUE);
	}
	return CWinApp::PreTranslateMessage(pMsg);
}

bool CAxis2App::FindInstance()
{
	// try to determine if there is already an instance of this application running.
	EnumWindows(EnumInstanceProc, 0);
	if (hwndHoGInstance)
	{
		// Found the client window
		CWnd * pWnd = CWnd::FromHandle(hwndHoGInstance);
		pWnd->ShowWindow(SW_SHOWNORMAL);
		pWnd->SetForegroundWindow();
		return true;
	}
	else
		return false;

}

//////////////////////////////////////////////////////////////////////////

DWORD CAxis2App::GetRegistryDword(CString csValue, DWORD dwDefault, HKEY hMainKey, CString csSubKey)
{
	HKEY hKey;
	if ( RegOpenKeyEx(hMainKey, csSubKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS )
		return dwDefault;
	DWORD dwType, dwSize, dwValue;
	dwSize = sizeof(DWORD);
	LONG lStatus = RegQueryValueEx(hKey, LPCTSTR(csValue), 0, &dwType, (BYTE *) &dwValue, &dwSize);
	if ( lStatus != ERROR_SUCCESS )
	{
		if ( lStatus == ERROR_FILE_NOT_FOUND )
		{
			//m_log.Add(0,"Unable to find value %s in the registry.  Using default values", csValue);
		}
		else
		{
			char szBuffer[MAX_BUFFER];
			strerror_s(szBuffer,MAX_BUFFER,GetLastError());
			m_log.Add(1,"Error reading value %s from registry.  Last error was %s", csValue, szBuffer );
		}
		RegCloseKey(hKey);
		return dwDefault;
	}
	if ( dwType != REG_DWORD )
	{
		m_log.Add(1,"Registry value of wrong type for %s.  Type was %ld, expected %ld", csValue, dwType, REG_DWORD);
		RegCloseKey(hKey);
		return dwDefault;
	}
	RegCloseKey(hKey);
	return dwValue;
}

CString CAxis2App::GetRegistryString(CString csValue, CString csDefault, HKEY hMainKey, CString csSubKey)
{
	HKEY hKey;
	if ( RegOpenKeyEx(hMainKey, csSubKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS )
		return csDefault;
	DWORD dwType, dwSize;
	char szBuffer[MAX_BUFFER];
	memset(&szBuffer[0], 0x00, sizeof(szBuffer));
	dwSize = sizeof(szBuffer);
	LONG lStatus = RegQueryValueEx(hKey, LPCTSTR(csValue), 0, &dwType, (BYTE *) &szBuffer[0], &dwSize);
	if ( lStatus != ERROR_SUCCESS )
	{
		if ( lStatus == ERROR_FILE_NOT_FOUND )
		{
			// m_log.Add(1,"Unable to find value %s in the registry.  Using default values", csValue);
		}
		else
		{
			char szBuffer[MAX_BUFFER];
			strerror_s(szBuffer,MAX_BUFFER,GetLastError());
			m_log.Add(1,"Error reading value %s from registry.  Last error was %s", csValue, szBuffer );
		}
		RegCloseKey(hKey);
		return csDefault;
	}
	if ( dwType != REG_SZ )
	{
		m_log.Add(1,"Registry value of wrong type for %s.  Type was %ld, expected %ld", csValue, dwType, REG_SZ);
		RegCloseKey(hKey);
		return csDefault;
	}
	RegCloseKey(hKey);
	return _T(szBuffer);
}

void CAxis2App::GetRegistryMultiSz(CString csValue, CStringArray * pStrings, HKEY hMainKey, CString csSubKey)
{
	// Make sure the input array is empty
	pStrings->RemoveAll();

	HKEY hKey;
	if ( RegOpenKeyEx(hMainKey, csSubKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS )
		return;
	DWORD dwType, dwSize;
	// Need to find out how big the buffer is
	dwSize = 0;
	LONG lStatus = RegQueryValueEx(hKey, LPCTSTR(csValue), 0, &dwType, NULL, &dwSize);

	if ( dwSize == 0 )
	{
		RegCloseKey(hKey);
		return;
	}

	char * pszBuffer = new char [dwSize];
	memset(pszBuffer, 0x00, dwSize);
	lStatus = RegQueryValueEx(hKey, LPCTSTR(csValue), 0, &dwType, (BYTE*) pszBuffer, &dwSize);
	char * pDataPtr = pszBuffer;

	if ( lStatus != ERROR_SUCCESS )
	{
		if ( lStatus == ERROR_FILE_NOT_FOUND )
		{
			// m_log.Add(1,"Unable to find value %s in the registry.", csValue);
		}
		else
		{
			char szBuffer[MAX_BUFFER];
			strerror_s(szBuffer,MAX_BUFFER,GetLastError());
			m_log.Add(1,"Error reading value %s from registry.  Last error was %s", csValue, szBuffer );
		}
	}
	else
	{
		// parse the registry value
		DWORD dwOffset = 0;
		while ( dwOffset < dwSize )
		{
			CString csValue = _T(pDataPtr);
			pStrings->Add(csValue);
			pDataPtr += csValue.GetLength() + 1;
			dwOffset += csValue.GetLength() + 1;
		}
		
	}
	if ( dwType != REG_MULTI_SZ )
		m_log.Add(1,"Registry value of wrong type for %s.  Type was %ld, expected %ld", csValue, dwType, REG_MULTI_SZ);
	RegCloseKey(hKey);
	delete [] pszBuffer;
}

//////////////////////////////////////////////////////////////////////////

void CAxis2App::PutRegistryDword(CString csValue, DWORD dwValue, HKEY hMainKey, CString csSubKey)
{
	HKEY hKey;
	DWORD dwDisp;
	LONG lStatus = RegCreateKeyEx(hMainKey, csSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp);

	if ( lStatus != ERROR_SUCCESS )
	{
		char szBuffer[MAX_BUFFER];
		strerror_s(szBuffer,MAX_BUFFER,lStatus);
		m_log.Add(1,"Unable to open registry key %s for writing.  Last error was %s", csSubKey, szBuffer );
		return;
	}
	lStatus = RegSetValueEx(hKey, csValue, 0, REG_DWORD, ((BYTE *) &dwValue), sizeof(DWORD) );
	if ( lStatus != ERROR_SUCCESS )
	{
		char szBuffer[MAX_BUFFER];
		strerror_s(szBuffer,MAX_BUFFER,lStatus);
		m_log.Add(1,"Error writing value %s to the registry.  Last error was %s", csValue, szBuffer );
	}
	RegCloseKey(hKey);
}

void CAxis2App::PutRegistryString(CString csValue, CString csString, HKEY hMainKey, CString csSubKey)
{
	HKEY hKey;
	DWORD dwDisp;

	LONG lStatus = RegCreateKeyEx(hMainKey, csSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp);

	if ( lStatus != ERROR_SUCCESS )
	{
		char szBuffer[MAX_BUFFER];
		strerror_s(szBuffer,MAX_BUFFER,lStatus);
		m_log.Add(1,"Unable to open registry key %s for writing.  Last error was %s", csSubKey, szBuffer );
		return;
	}
	lStatus = RegSetValueEx(hKey, csValue, 0, REG_SZ, ((BYTE *) csString.GetBuffer(csString.GetLength()) ), csString.GetLength() );
	if ( lStatus != ERROR_SUCCESS )
	{
		char szBuffer[MAX_BUFFER];
		strerror_s(szBuffer,MAX_BUFFER,lStatus);
		m_log.Add(1,"Error writing value %s to the registry.  Last error was %s", csValue, szBuffer );
	}
	RegCloseKey(hKey);
}

void CAxis2App::PutRegistryMultiSz(CString csValue, CStringArray * pStrings, HKEY hMainKey, CString csSubKey)
{
	HKEY hKey;
	DWORD dwDisp;
	LONG lStatus = RegCreateKeyEx(hMainKey, csSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp);

	// Find out how much space we need to allocate for the string buffer
	int i = 0;
	int iLength = 0;
	for ( i = 0; i <= pStrings->GetUpperBound(); i++ )
		iLength += ( pStrings->GetAt(i).GetLength() + 1);

	char * pszStrings = new char [iLength + 1];
	
	memset(pszStrings, 0x00, iLength + 1);
	char * ptr = pszStrings;
	for ( i = 0; i <= pStrings->GetUpperBound(); i++ )
	{
		memcpy(ptr, LPCTSTR(pStrings->GetAt(i)), pStrings->GetAt(i).GetLength());
		ptr += pStrings->GetAt(i).GetLength() + 1;
	}

	if ( lStatus != ERROR_SUCCESS )
	{
		char szBuffer[MAX_BUFFER];
		strerror_s(szBuffer,MAX_BUFFER,lStatus);
		m_log.Add(1,"Unable to open registry key %s for writing.  Last error was %s", csSubKey, szBuffer );
		return;
	}
	lStatus = RegSetValueEx(hKey, csValue, 0, REG_MULTI_SZ, ((BYTE *) pszStrings), iLength );
	if ( lStatus != ERROR_SUCCESS )
	{
		char szBuffer[MAX_BUFFER];
		strerror_s(szBuffer,MAX_BUFFER,lStatus);
		m_log.Add(1,"Error writing value %s to the registry.  Last error was %s", csValue, szBuffer );
	}
	RegCloseKey(hKey);

	delete [] pszStrings;
}

//////////////////////////////////////////////////////////////////////////

void CAxis2App::DeleteRegistryKey(CString csKeyName, HKEY hRootKey)
{
	HKEY hKey;
	if ( RegOpenKeyEx(hRootKey, csKeyName, 0, KEY_READ, &hKey) == ERROR_FILE_NOT_FOUND )
		return;
	RegCloseKey(hKey);
	LONG lStatus = RegDeleteKey(hRootKey, csKeyName);
	if ( lStatus != ERROR_SUCCESS )
	{
		char szBuffer[MAX_BUFFER];
		strerror_s(szBuffer,MAX_BUFFER,lStatus);
		m_log.Add(1,"Error deleting registry key %s.  Last error was %s", csKeyName, szBuffer);
	}
	return;
}

void CAxis2App::DeleteRegistryValue(CString csValueName, CString csSubKey, HKEY hRootKey)
{
	HKEY hKey;
	LONG lStatus = RegOpenKey(hRootKey, csSubKey, &hKey);
	if ( lStatus == ERROR_SUCCESS )
	{
		lStatus = RegDeleteValue(hKey, csValueName);
		if ( lStatus == ERROR_FILE_NOT_FOUND)
			return;
		if ( lStatus != ERROR_SUCCESS )
		{
			char szBuffer[MAX_BUFFER];
			strerror_s(szBuffer,MAX_BUFFER,lStatus);
			m_log.Add(1,"Error deleting registry value %s.  Last error was %s", csValueName, szBuffer);
		}
		RegCloseKey(hKey);
	}
	else
	{
		char szBuffer[MAX_BUFFER];
		strerror_s(szBuffer,MAX_BUFFER,lStatus);
		m_log.Add(1,"Couldn't open registry key %s.  Last error was %s", csSubKey, szBuffer);
	}
	return;
}

//////////////////////////////////////////////////////////////////////////

CString CAxis2App::GetVersionTitle()
{
	// Get the version info from the exe itself
	CString csExe = AfxGetAppName();
	csExe += ".exe";
	char * pszExe = new char [csExe.GetLength() + 1];
	sprintf_s(pszExe,csExe.GetLength()+1, csExe);
	DWORD dwHandle = 0;
	DWORD dwSize = GetFileVersionInfoSize(pszExe, &dwHandle);
	char * pBuffer = new char [dwSize];
	GetFileVersionInfo(pszExe, dwHandle, dwSize, (LPVOID) pBuffer);
	CString csVersionInfo;
	unsigned int iDataSize = 80;
	LPVOID pData;
	VerQueryValue(pBuffer, _T("\\StringFileInfo\\040904b0\\ProductVersion"), &pData, &iDataSize);
	csVersionInfo.Format("%s", pData);

	delete [] pszExe;
	delete [] pBuffer;
	
	csVersionInfo.Replace(",", ".");
	csVersionInfo.Replace(" ", "");

	CString csVersionTitle;
	csVersionTitle.Format("Axis2 version %s", csVersionInfo);

	return csVersionTitle;
}


CString CAxis2App::GetBuildTimestamp()
{
	CString csTimestamp;
	csTimestamp.Format("%s %s", __DATE__, __TIME__);
	return csTimestamp;
}

//*************************************

void CAxis2App::InitializeMulPaths()
{
	saMulPaths.SetSize(VERFILE_ENDOFTABLE);

	CString csPath;
	//Map files
	csPath.Format(_T("%smap0.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAP0, csPath);

	csPath.Format(_T("%smap1.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAP1, csPath);

	csPath.Format(_T("%smap2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAP2, csPath);

	csPath.Format(_T("%smap3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAP3, csPath);

	csPath.Format(_T("%smap4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAP4, csPath);

	//Map DIF files
	csPath.Format(_T("%smapdif0.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIF0, csPath);

	csPath.Format(_T("%smapdif1.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIF1, csPath);

	csPath.Format(_T("%smapdif2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIF2, csPath);

	csPath.Format(_T("%smapdif3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIF3, csPath);
	
	csPath.Format(_T("%smapdif4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIF4, csPath);

	//Map DIFL files
	csPath.Format(_T("%smapdifl0.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIFL0, csPath);

	csPath.Format(_T("%smapdifl1.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIFL1, csPath);

	csPath.Format(_T("%smapdifl2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIFL2, csPath);

	csPath.Format(_T("%smapdifl3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIFL3, csPath);

	csPath.Format(_T("%smapdifl4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_MAPDIFL4, csPath);

	//Static Files
	csPath.Format(_T("%sstatics0.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STATICS0, csPath);

	csPath.Format(_T("%sstatics1.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STATICS1, csPath);

	csPath.Format(_T("%sstatics2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STATICS2, csPath);

	csPath.Format(_T("%sstatics3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STATICS3, csPath);

	csPath.Format(_T("%sstatics4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STATICS4, csPath);

	//Static IDX files
	csPath.Format(_T("%sstaidx0.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STAIDX0, csPath);

	csPath.Format(_T("%sstaidx1.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STAIDX1, csPath);

	csPath.Format(_T("%sstaidx2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STAIDX2, csPath);

	csPath.Format(_T("%sstaidx3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STAIDX3, csPath);

	csPath.Format(_T("%sstaidx4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STAIDX4, csPath);

	//Static DIF files
	csPath.Format(_T("%sstadif0.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIF0, csPath);

	csPath.Format(_T("%sstadif1.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIF1, csPath);

	csPath.Format(_T("%sstadif2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIF2, csPath);

	csPath.Format(_T("%sstadif3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIF3, csPath);

	csPath.Format(_T("%sstadif4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIF4, csPath);

	//Static DIFI files
	csPath.Format(_T("%sstadifi0.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFI0, csPath);

	csPath.Format(_T("%sstadifi1.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFI1, csPath);

	csPath.Format(_T("%sstadifi2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFI2, csPath);

	csPath.Format(_T("%sstadifi3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFI3, csPath);

	csPath.Format(_T("%sstadifi4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFI4, csPath);

	//Static DIFL files
	csPath.Format(_T("%sstadifl0.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFL0, csPath);

	csPath.Format(_T("%sstadifl1.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFL1, csPath);

	csPath.Format(_T("%sstadifl2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFL2, csPath);

	csPath.Format(_T("%sstadifl3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFL3, csPath);

	csPath.Format(_T("%sstadifl4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_STADIFL4, csPath);

	//Art
	csPath.Format(_T("%sartidx.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_ARTIDX, csPath);

	csPath.Format(_T("%sart.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_ART, csPath);

	//Anim
	csPath.Format(_T("%sanim.idx"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIMIDX, csPath);

	csPath.Format(_T("%sanim.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIM, csPath);

	csPath.Format(_T("%sanim2.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIM2, csPath);

	csPath.Format(_T("%sanim2.idx"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIMIDX2, csPath);

	csPath.Format(_T("%sanim3.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIM3, csPath);

	csPath.Format(_T("%sanim3.idx"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIMIDX3, csPath);

	csPath.Format(_T("%sanim4.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIM4, csPath);

	csPath.Format(_T("%sanim4.idx"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIMIDX4, csPath);

	csPath.Format(_T("%sanim5.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIM5, csPath);

	csPath.Format(_T("%sanim5.idx"), csMulPath);
	saMulPaths.SetAt(VERFILE_ANIMIDX5, csPath);

	//Misc
	csPath.Format(_T("%slightidx.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_LIGHTIDX, csPath);

	csPath.Format(_T("%slight.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_LIGHT, csPath);

	csPath.Format(_T("%stiledata.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_TILEDATA, csPath);

	csPath.Format(_T("%shues.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_HUES, csPath);

	csPath.Format(_T("%sradarcol.mul"), csMulPath);
	saMulPaths.SetAt(VERFILE_RADARCOL, csPath);

	//Def Files
	csPath.Format(_T("%sbodyconv.def"), csMulPath);
	saMulPaths.SetAt(VERFILE_BODYCONVDEF, csPath);

	csPath.Format(_T("%sbody.def"), csMulPath);
	saMulPaths.SetAt(VERFILE_BODYDEF, csPath);

}

BOOL CAxis2App::SetCustomMulPath(short sFileIndex, LPCTSTR pszFilePath)
{
	if ( sFileIndex < 0 || sFileIndex > saMulPaths.GetUpperBound() )
		return FALSE;	// Invalid index!
	if ( _tcslen(pszFilePath) == 0 )
		return FALSE;	// Invalid filename!
	saMulPaths.SetAt(sFileIndex, pszFilePath);
	return TRUE;
}

CString CAxis2App::GetCustomMulPath(short sFileIndex)
{
	CString strResult;
	if ( sFileIndex < 0 || sFileIndex > saMulPaths.GetUpperBound() )
	{
		// Do nothing...we never set these
	}
	else
		strResult = saMulPaths.GetAt(sFileIndex);
	return strResult;
}

enum INI_TYPE
{
	INI_SETTINGS,
	INI_NPCTAG,
	INI_ITEMTAG,
	INI_QTY,			// Don't care
};

const char * pIniBlocks[INI_QTY] =
{
	"SETTINGS",
	"NPCTAG",
	"ITEMTAG",
};

bool CAxis2App::LoadIni(int iLoadPart)
{
	try
	{
				//Load Axis.ini
		CString csFile;
		csFile.Format("%sAxis2.ini",GetRegistryString("RootPath", ""));
		CStdioFile pFile;
		if ( !pFile.Open(csFile, CFile::modeRead | CFile::shareDenyNone) )
		{
			Main->m_log.Add(1,"ERROR: Unable to open file %s", csFile);
			return false;
		}

		BOOL bStatus = TRUE;
		while ( bStatus )
		{
			CString csLine;
			bStatus = pFile.ReadString(csLine);

			if ( !bStatus )
				break;

			if ( csLine.Find("[") == 0 )
			{
				while ( bStatus )
				{
					if ( !bStatus )
						break;
					if ( csLine.Find("[") == 0 )
					{
						CString csKey = csLine.Mid(1);
						csKey = csKey.SpanExcluding("]");
						CString csIndex;
						if ( csKey.Find(" ") != -1 )
							csIndex = csKey.Mid(csKey.Find(" ") + 1);
						CString csType = csKey.SpanExcluding(" ");
						int resource = FindTable(csType, pIniBlocks, INI_QTY);		

						if ((iLoadPart > -1) && (resource != iLoadPart))
							break;

						switch (resource)
						{
						case INI_SETTINGS:
							{
								while ( bStatus )
								{
									bStatus = pFile.ReadString(csLine);
									if ( !bStatus )
										break;
									if ( csLine.Find("[") == 0 )
									{
										break;
									}
									csLine = csLine.SpanExcluding("//");
									csLine.Trim(); 
									if ( csLine != "" )
									{
										CString csSetting, csValue;
										csSetting = csLine.SpanExcluding(" \t=");
										csSetting.Trim();
										csValue = csLine.Mid(csSetting.GetLength() + 1);
										csValue.Trim();
										if( csValue.Find(" \t="))
											csValue = csValue.Mid(csValue.Find(" \t=") + 1);
										csValue.Trim();

										if (csSetting == "AllowMultiple")
											m_dwAllowMultiple = atoi(csValue);
										if (csSetting == "AlwaysOnTop")
											m_dwAlwaysOnTop = atoi(csValue);
										if (csSetting == "DrawDifs")
											m_dwDrawDifs = atoi(csValue);
										if (csSetting == "DrawStatics")
											m_dwDrawStatics = atoi(csValue);
										if (csSetting == "LoadDefault")
											m_dwLoadDefault = atoi(csValue);
										if (csSetting == "Position")
											m_csPosition = csValue;
										if (csSetting == "RoomView")
											m_dwRoomView = atoi(csValue);
										if (csSetting == "SameAsClient")
											m_dwSameAsClient = atoi(csValue);
										if (csSetting == "StartTab")
											m_dwStartTab = atoi(csValue);
										if (csSetting == "SysClose")
											m_dwSysClose = atoi(csValue);
										if (csSetting == "ShowSpawnpoints")
											m_dwShowSpawnpoints = atoi(csValue);
										if (csSetting == "NPCSpawnColor")
											m_dwNPCSpawnColor = atoi(csValue);
										if (csSetting == "ItemSpawnColor")
											m_dwItemSpawnColor = atoi(csValue);
										if (csSetting == "ShowItems")
											m_dwShowItems = atoi(csValue);
										if (csSetting == "ShowNPCs")
											m_dwShowNPCs = atoi(csValue);
										if (csSetting == "ShowMap")
											m_dwShowMap = atoi(csValue);
									}
								}
							}
							break;
						case INI_NPCTAG:
							{
								CStringArray * csaList;
								if (csIndex == "Stats")
									csaList = &Main->m_pScripts->m_asaNPCStats;
								else if (csIndex == "Resistences")
									csaList = &Main->m_pScripts->m_asaNPCResistences;
								else if (csIndex == "Misc")
									csaList = &Main->m_pScripts->m_asaNPCMisc;
								else if (csIndex == "Tags")
									csaList = &Main->m_pScripts->m_asaNPCTags;
								while ( bStatus )
								{
									bStatus = pFile.ReadString(csLine);
									if ( !bStatus )
										break;
									if ( csLine.Find("[") == 0 )
									{
										break;
									}
									csLine = csLine.SpanExcluding("//");
									csLine.Trim();
									if ( csLine != "" )
									{
										csaList->Add(csLine);
									}
								}
							}
							break;
						case INI_ITEMTAG:
							{
								CStringArray * csaList;
								if (csIndex == "Props")
									csaList = &Main->m_pScripts->m_asaITEMProps;
								else if (csIndex == "Tags")
									csaList = &Main->m_pScripts->m_asaITEMTags;
								while ( bStatus )
								{
									bStatus = pFile.ReadString(csLine);
									if ( !bStatus )
										break;
									if ( csLine.Find("[") == 0 )
									{
										break;
									}
									csLine = csLine.SpanExcluding("//");
									csLine.Trim();
									if ( csLine != "" )
									{
										csaList->Add(csLine);
									}
								}

							}
							break;
						default:
							Main->m_log.Add(1,"ERROR: Unknown section %s in file %s", csLine, csFile);
							bStatus = pFile.ReadString(csLine);
							break;
						}
					}
					else
					{
						bStatus = pFile.ReadString(csLine);
					}
				}
			}
		}
	}
	catch (CFileException *e)
	{
		Main->m_log.Add(1,"ERROR: Caught an exception while reading the file %s.  Cause code = %ld", e->m_strFileName, e->m_cause);
		e->Delete();
	}
	return true;
}