//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//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.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#include "StdAfx.h"
#include "preferences.h"
#include <time.h>
#include "opcodes.h"
#include "otherfunctions.h"
#include "ini2.h"
#include "stdlib.h"
#include "stdio.h"
#include <locale.h>
#include "resource.h"
#include "emule.h"
#include <io.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CPreferences::CPreferences(){
	srand((uint32)time(0)); // we need random numbers sometimes

	prefs = new Preferences_Struct;
	memset(prefs,0,sizeof(Preferences_Struct));
	prefsExt=new Preferences_Ext_Struct;
	memset(prefsExt,0,sizeof(Preferences_Ext_Struct));

	//get application start directory
	char buffer[490];
	::GetModuleFileName(0, buffer, 490);
	LPTSTR pszFileName = _tcsrchr(buffer, '\\') + 1;
	*pszFileName = '\0';

	appdir = CString(buffer);
	configdir = CString(buffer);
	configdir.Append("config\\");

	::CreateDirectory(GetConfigDir(),0);

	// lets move config-files in the appdir to the configdir (for upgraders <0.29a to >=0.29a )
	if ( PathFileExists(appdir+"preferences.ini")) MoveFile(appdir+"preferences.ini",configdir+"preferences.ini");
	if ( PathFileExists(appdir+"preferences.dat")) MoveFile(appdir+"preferences.dat",configdir+"preferences.dat");
	if ( PathFileExists(appdir+"adresses.dat")) MoveFile(appdir+"adresses.dat",configdir+"adresses.dat");
	if ( PathFileExists(appdir+"Category.ini")) MoveFile(appdir+"Category.ini",configdir+"Category.ini");
	if ( PathFileExists(appdir+"clients.met")) MoveFile(appdir+"clients.met",configdir+"clients.met");
	if ( PathFileExists(appdir+"emfriends.met")) MoveFile(appdir+"emfriends.met",configdir+"emfriends.met");
	if ( PathFileExists(appdir+"fileinfo.ini")) MoveFile(appdir+"fileinfo.ini",configdir+"fileinfo.ini");
	if ( PathFileExists(appdir+"ipfilter.dat")) MoveFile(appdir+"ipfilter.dat",configdir+"ipfilter.dat");
	if ( PathFileExists(appdir+"known.met")) MoveFile(appdir+"known.met",configdir+"known.met");
	if ( PathFileExists(appdir+"server.met")) MoveFile(appdir+"server.met",configdir+"server.met");
	if ( PathFileExists(appdir+"shareddir.dat")) MoveFile(appdir+"shareddir.dat",configdir+"shareddir.dat");
	if ( PathFileExists(appdir+"staticservers.dat")) MoveFile(appdir+"staticservers.dat",configdir+"staticservers.dat");
	if ( PathFileExists(appdir+"webservices.dat")) MoveFile(appdir+"webservices.dat",configdir+"webservices.dat");

	CreateUserHash();
	md4cpy(&prefs->userhash,&userhash);

	// load preferences.dat or set standart values
	char* fullpath = new char[strlen(configdir)+16];
	sprintf(fullpath,"%spreferences.dat",configdir);
	FILE* preffile = fopen(fullpath,"rb");
	delete[] fullpath;

	LoadPreferences();

	if (!preffile){
		SetStandartValues();
		//if (Ask4RegFix(true)) Ask4RegFix(false);
	}
	else{
		fread(prefsExt,sizeof(Preferences_Ext_Struct),1,preffile);
		if (ferror(preffile))
			SetStandartValues();

		// import old pref-files
		if (prefsExt->version<20) {


			if (prefsExt->version>17) {// v0.20b+
				prefsImport20b=new Preferences_Import20b_Struct;
				memset(prefsImport20b,0,sizeof(Preferences_Import20b_Struct));
				fseek(preffile,0,0);
				fread(prefsImport20b,sizeof(Preferences_Import20b_Struct),1,preffile);

				md4cpy(&prefs->userhash,&prefsImport20b->userhash);
				memcpy(&prefs->incomingdir,&prefsImport20b->incomingdir,510);
				memcpy(&prefs->tempdir,&prefsImport20b->tempdir,510);
				sprintf(prefs->nick,prefsImport20b->nick);

				prefs->totalDownloadedBytes=prefsImport20b->totalDownloadedBytes;
				prefs->totalUploadedBytes=prefsImport20b->totalUploadedBytes;

			} else if (prefsExt->version>7) { // v0.20a
				prefsImport20a=new Preferences_Import20a_Struct;
				memset(prefsImport20a,0,sizeof(Preferences_Import20a_Struct));
				fseek(preffile,0,0);
				fread(prefsImport20a,sizeof(Preferences_Import20a_Struct),1,preffile);

				md4cpy(&prefs->userhash,&prefsImport20a->userhash);
				memcpy(&prefs->incomingdir,&prefsImport20a->incomingdir,510);
				memcpy(&prefs->tempdir,&prefsImport20a->tempdir,510);
				sprintf(prefs->nick,prefsImport20a->nick);

				prefs->totalDownloadedBytes=prefsImport20a->totalDownloaded;
				prefs->totalUploadedBytes=prefsImport20a->totalUploaded;

			} else {	//v0.19c-
				prefsImport19c=new Preferences_Import19c_Struct;
				memset(prefsImport19c,0,sizeof(Preferences_Import19c_Struct));

				fseek(preffile,0,0);
				fread(prefsImport19c,sizeof(Preferences_Import19c_Struct),1,preffile);

				if (prefsExt->version<3) {
					CreateUserHash();
					md4cpy(&prefs->userhash,&userhash);
				} else {md4cpy(&prefs->userhash,&prefsImport19c->userhash);}
				memcpy(&prefs->incomingdir,&prefsImport19c->incomingdir,510);memcpy(&prefs->tempdir,&prefsImport19c->tempdir,510);
				sprintf(prefs->nick,prefsImport19c->nick);
			}
 		} else {
			md4cpy(&prefs->userhash,&prefsExt->userhash);
			prefs->EmuleWindowPlacement=prefsExt->EmuleWindowPlacement;
		}
		fclose(preffile);
		md4cpy(&userhash,&prefs->userhash);
		prefs->smartidstate=0;
	}

	// shared directories
	fullpath = new char[strlen(configdir)+MAX_PATH]; // i_a
	sprintf(fullpath,"%sshareddir.dat",configdir);
	CStdioFile* sdirfile = new CStdioFile();
	if (sdirfile->Open(fullpath,CFile::modeRead)){
		CString toadd;
		while (sdirfile->ReadString(toadd)){
			if (toadd.Right(1)!='\\') toadd.Append("\\");
			if ( /*(!toadd.MakeLower().CompareNoCase(appdir)) || */ (!toadd.MakeLower().CompareNoCase(configdir)) ) continue;
			if (_taccess(toadd, 0) == 0) // only add directories which still exist
				shareddir_list.AddHead(toadd);
		}
		sdirfile->Close();
	}
	delete sdirfile;
	delete[] fullpath;
	
	//serverlist adresses
	fullpath = new char[strlen(configdir)+20];
	sprintf(fullpath,"%sadresses.dat",configdir);
	sdirfile = new CStdioFile();
	if (sdirfile->Open(fullpath,CFile::modeRead)){
		CString toadd;
		while (sdirfile->ReadString(toadd))
			adresses_list.AddHead(toadd);
		sdirfile->Close();
	}
	delete sdirfile;
	delete[] fullpath;	
	fullpath=NULL;

	userhash[5] = 14;
	userhash[14] = 111;

	// deadlake PROXYSUPPORT
	m_UseProxyListenPort = false;
	ListenPort = 0;

	// Explicitly inform the user about errors with incoming/temp folders!
	if (!PathFileExists(GetIncomingDir()) && !::CreateDirectory(GetIncomingDir(),0)) {
		CString strError;
		strError.Format(_T("Failed to create incoming directory \"%s\" - %s"), GetIncomingDir(), GetErrorMessage(GetLastError()));
		AfxMessageBox(strError, MB_ICONERROR);
		sprintf(prefs->incomingdir,"%sincoming",appdir);
		if (!PathFileExists(GetIncomingDir()) && !::CreateDirectory(GetIncomingDir(),0)){
			strError.Format(_T("Failed to create incoming directory \"%s\" - %s"), GetIncomingDir(), GetErrorMessage(GetLastError()));
			AfxMessageBox(strError, MB_ICONERROR);
		}
	}
	if (!PathFileExists(GetTempDir()) && !::CreateDirectory(GetTempDir(),0)) {
		CString strError;
		strError.Format(_T("Failed to create temporary directory \"%s\" - %s"), GetTempDir(), GetErrorMessage(GetLastError()));
		AfxMessageBox(strError, MB_ICONERROR);
		sprintf(prefs->tempdir,"%stemp",appdir);
		if (!PathFileExists(GetTempDir()) && !::CreateDirectory(GetTempDir(),0)){
			strError.Format(_T("Failed to create temporary directory \"%s\" - %s"), GetTempDir(), GetErrorMessage(GetLastError()));
			AfxMessageBox(strError, MB_ICONERROR);
		}
	}
	if (((int*)prefs->userhash[0]) == 0 && ((int*)prefs->userhash[1]) == 0 && ((int*)prefs->userhash[2]) == 0 && ((int*)prefs->userhash[3]) == 0)
		CreateUserHash();
}

void CPreferences::SetStandartValues(){
	CreateUserHash();
	md4cpy(&prefs->userhash,&userhash);

	WINDOWPLACEMENT defaultWPM;
	defaultWPM.length = sizeof(WINDOWPLACEMENT);
	defaultWPM.rcNormalPosition.left=10;defaultWPM.rcNormalPosition.top=10;
	defaultWPM.rcNormalPosition.right=700;defaultWPM.rcNormalPosition.bottom=500;
	defaultWPM.showCmd=0;
	prefs->EmuleWindowPlacement=defaultWPM;
	prefs->versioncheckLastAutomatic=0;

//	Save();
}

uint16 CPreferences::GetMaxDownload(){
	//dont be a Lam3r :)
	//if( GetMaxUpload() < 4 )
	//	return (( (GetMaxUpload() < 10) && (GetMaxUpload()*3 < prefs->maxdownload) )? GetMaxUpload()*3 : prefs->maxdownload);
	//return (( (GetMaxUpload() < 10) && (GetMaxUpload()*4 < prefs->maxdownload) )? GetMaxUpload()*4 : prefs->maxdownload);
	return prefs->maxdownload;
}

// -khaos--+++> A whole bunch of methods!  Keep going until you reach the end tag.
void CPreferences::SaveStats(int bBackUp){
	// This function saves all of the new statistics in my addon.  It is also used to
	// save backups for the Reset Stats function, and the Restore Stats function (Which is actually LoadStats)
	// bBackUp = 0: DEFAULT; save to preferences.ini
	// bBackUp = 1: Save to statbkup.ini, which is used to restore after a reset
	// bBackUp = 2: Save to statbkuptmp.ini, which is temporarily created during a restore and then renamed to statbkup.ini

	CString buffer;
	char* fullpath = new char[strlen(configdir)+MAX_PATH]; // i_a
	if (bBackUp == 1) sprintf(fullpath,"%sstatbkup.ini",configdir);
	else if (bBackUp == 2) sprintf(fullpath,"%sstatbkuptmp.ini",configdir);
	else sprintf(fullpath,"%spreferences.ini",configdir);
	
	CIni ini(fullpath, "Statistics");

	delete[] fullpath;

	// Save cumulative statistics to preferences.ini, going in order as they appear in CStatisticsDlg::ShowStatistics.
	// We do NOT SET the values in prefs struct here.

    // Save Cum Down Data
	buffer.Format("%I64u",theApp.stat_sessionReceivedBytes+GetTotalDownloaded());
	ini.WriteString("TotalDownloadedBytes", buffer );
    // Save Complete Downloads - This is saved and incremented in partfile.cpp.
	// Save Successful Download Sessions
	ini.WriteInt("DownSuccessfulSessions", prefs->cumDownSuccessfulSessions);
	// Save Failed Download Sessions
	ini.WriteInt("DownFailedSessions", prefs->cumDownFailedSessions);
	ini.WriteInt("DownAvgTime", (GetDownC_AvgTime() + GetDownS_AvgTime()) / 2 );

	// Cumulative statistics for saved due to compression/lost due to corruption
	buffer.Format("%I64u",prefs->cumLostFromCorruption);
	ini.WriteString("LostFromCorruption", buffer );
	buffer.Format("%I64u",prefs->cumSavedFromCompression);
	ini.WriteString("SavedFromCompression", buffer );
	ini.WriteInt("PartsSavedByICH", prefs->cumPartsSavedByICH+prefs->sesPartsSavedByICH);

	// Save cumulative client breakdown stats for received bytes...
	buffer.Format("%I64u", GetCumDownData_EDONKEY() );
	ini.WriteString("DownData_EDONKEY", buffer );
	buffer.Format("%I64u", GetCumDownData_EDONKEYHYBRID() );
	ini.WriteString("DownData_EDONKEYHYBRID", buffer );
	buffer.Format("%I64u", GetCumDownData_EMULE() );
	ini.WriteString("DownData_EMULE", buffer );
	buffer.Format("%I64u", GetCumDownData_MLDONKEY() );
	ini.WriteString("DownData_MLDONKEY", buffer );
	buffer.Format("%I64u", GetCumDownData_LMULE() );
	ini.WriteString("DownData_LMULE", buffer );
	buffer.Format("%I64u", GetCumDownData_CDONKEY() );
	ini.WriteString("DownData_CDONKEY", buffer );

	// Save cumulative port breakdown stats for received bytes
	buffer.Format("%I64u", GetCumDownDataPort_4662() );
	ini.WriteString("DownDataPort_4662", buffer );
	buffer.Format("%I64u", GetCumDownDataPort_OTHER() );
	ini.WriteString("DownDataPort_OTHER", buffer );

	// Save Cumulative Downline Overhead Statistics
	buffer.Format("%I64u",(uint64)theApp.downloadqueue->GetDownDataOverheadFileRequest()+theApp.downloadqueue->GetDownDataOverheadSourceExchange()+theApp.downloadqueue->GetDownDataOverheadServer()+theApp.downloadqueue->GetDownDataOverheadOther()+GetDownOverheadTotal());
	ini.WriteString("DownOverheadTotal", buffer );
	buffer.Format("%I64u",theApp.downloadqueue->GetDownDataOverheadFileRequest() + GetDownOverheadFileReq());
	ini.WriteString("DownOverheadFileReq", buffer );
	buffer.Format("%I64u",theApp.downloadqueue->GetDownDataOverheadSourceExchange() + GetDownOverheadSrcEx());
	ini.WriteString("DownOverheadSrcEx", buffer );
	buffer.Format("%I64u",(uint64) theApp.downloadqueue->GetDownDataOverheadServer()+GetDownOverheadServer());
	ini.WriteString("DownOverheadServer", buffer );
	buffer.Format("%I64u",theApp.downloadqueue->GetDownDataOverheadFileRequestPackets() + theApp.downloadqueue->GetDownDataOverheadSourceExchangePackets() + theApp.downloadqueue->GetDownDataOverheadServerPackets() + theApp.downloadqueue->GetDownDataOverheadOtherPackets() + GetDownOverheadTotalPackets());
	ini.WriteString("DownOverheadTotalPackets", buffer );
	buffer.Format("%I64u",theApp.downloadqueue->GetDownDataOverheadFileRequestPackets() + GetDownOverheadFileReqPackets());
	ini.WriteString("DownOverheadFileReqPackets", buffer );
	buffer.Format("%I64u",theApp.downloadqueue->GetDownDataOverheadSourceExchangePackets() + GetDownOverheadSrcExPackets());
	ini.WriteString("DownOverheadSrcExPackets", buffer );
	buffer.Format("%I64u",theApp.downloadqueue->GetDownDataOverheadServerPackets() + GetDownOverheadServerPackets());
	ini.WriteString("DownOverheadServerPackets", buffer );

	// Save Cumulative Upline Statistics
	buffer.Format("%I64u",theApp.stat_sessionSentBytes+GetTotalUploaded());
	ini.WriteString("TotalUploadedBytes", buffer );
	ini.WriteInt("UpSuccessfulSessions", theApp.uploadqueue->GetSuccessfullUpCount()+GetUpSuccessfulSessions());
	ini.WriteInt("UpFailedSessions", theApp.uploadqueue->GetFailedUpCount()+GetUpFailedSessions());
	ini.WriteInt("UpAvgTime", (theApp.uploadqueue->GetAverageUpTime()+GetUpAvgTime())/2);

	// Save Cumulative Client Breakdown Stats For Sent Bytes
	buffer.Format("%I64u", GetCumUpData_EDONKEY() );
	ini.WriteString("UpData_EDONKEY", buffer );
	buffer.Format("%I64u", GetCumUpData_EDONKEYHYBRID() );
	ini.WriteString("UpData_EDONKEYHYBRID", buffer );
	buffer.Format("%I64u", GetCumUpData_EMULE() );
	ini.WriteString("UpData_EMULE", buffer );
	buffer.Format("%I64u", GetCumUpData_MLDONKEY() );
	ini.WriteString("UpData_MLDONKEY", buffer );
	buffer.Format("%I64u", GetCumUpData_LMULE() );
	ini.WriteString("UpData_LMULE", buffer );
	buffer.Format("%I64u", GetCumUpData_CDONKEY() );
	ini.WriteString("UpData_CDONKEY", buffer );

	// Save cumulative port breakdown stats for sent bytes
	buffer.Format("%I64u", GetCumUpDataPort_4662() );
	ini.WriteString("UpDataPort_4662", buffer );
	buffer.Format("%I64u", GetCumUpDataPort_OTHER() );
	ini.WriteString("UpDataPort_OTHER", buffer );

	// Save cumulative source breakdown stats for sent bytes
	buffer.Format("%I64u", GetCumUpData_File() );
	ini.WriteString("UpData_File", buffer );
	buffer.Format("%I64u", GetCumUpData_Partfile() );
	ini.WriteString("UpData_Partfile", buffer );

	// Save Cumulative Upline Overhead Statistics
	buffer.Format("%I64u",theApp.uploadqueue->GetUpDataOverheadFileRequest() + theApp.uploadqueue->GetUpDataOverheadSourceExchange() + theApp.uploadqueue->GetUpDataOverheadServer() + theApp.uploadqueue->GetUpDataOverheadOther() + GetUpOverheadTotal());
	ini.WriteString("UpOverheadTotal", buffer);
	buffer.Format("%I64u",theApp.uploadqueue->GetUpDataOverheadFileRequest() + GetUpOverheadFileReq());
	ini.WriteString("UpOverheadFileReq", buffer );
	buffer.Format("%I64u",theApp.uploadqueue->GetUpDataOverheadSourceExchange() + GetUpOverheadSrcEx());
	ini.WriteString("UpOverheadSrcEx", buffer );
	buffer.Format("%I64u",theApp.uploadqueue->GetUpDataOverheadServer() + GetUpOverheadServer());
	ini.WriteString("UpOverheadServer", buffer );
	buffer.Format("%I64u",theApp.uploadqueue->GetUpDataOverheadFileRequestPackets() + theApp.uploadqueue->GetUpDataOverheadSourceExchangePackets() + theApp.uploadqueue->GetUpDataOverheadServerPackets() + theApp.uploadqueue->GetUpDataOverheadOtherPackets() + GetUpOverheadTotalPackets());
	ini.WriteString("UpOverheadTotalPackets", buffer );
	buffer.Format("%I64u",theApp.uploadqueue->GetUpDataOverheadFileRequestPackets() + GetUpOverheadFileReqPackets());
	ini.WriteString("UpOverheadFileReqPackets", buffer );
	buffer.Format("%I64u",theApp.uploadqueue->GetUpDataOverheadSourceExchangePackets() + GetUpOverheadSrcExPackets());
	ini.WriteString("UpOverheadSrcExPackets", buffer );
	buffer.Format("%I64u",theApp.uploadqueue->GetUpDataOverheadServerPackets() + GetUpOverheadServerPackets());
	ini.WriteString("UpOverheadServerPackets", buffer );

	// Save Cumulative Connection Statistics
	float tempRate = 0;
	// Download Rate Average
	tempRate = theApp.emuledlg->statisticswnd.GetAvgDownloadRate(2);
	ini.WriteFloat("ConnAvgDownRate", tempRate);
	// Max Download Rate Average
	if (tempRate>GetConnMaxAvgDownRate()) Add2ConnMaxAvgDownRate(tempRate);
	ini.WriteFloat("ConnMaxAvgDownRate", GetConnMaxAvgDownRate());
	// Max Download Rate
	tempRate = (float) theApp.downloadqueue->GetDatarate() / 1024;
	if (tempRate>GetConnMaxDownRate()) Add2ConnMaxDownRate(tempRate);
	ini.WriteFloat("ConnMaxDownRate", GetConnMaxDownRate());
	// Upload Rate Average
	tempRate = theApp.emuledlg->statisticswnd.GetAvgUploadRate(2);
	ini.WriteFloat("ConnAvgUpRate", tempRate);
	// Max Upload Rate Average
	if (tempRate>GetConnMaxAvgUpRate()) Add2ConnMaxAvgUpRate(tempRate);
	ini.WriteFloat("ConnMaxAvgUpRate", GetConnMaxAvgUpRate());
	// Max Upload Rate
	tempRate = (float) theApp.uploadqueue->GetDatarate() / 1024;
	if (tempRate>GetConnMaxUpRate()) Add2ConnMaxUpRate(tempRate);
	ini.WriteFloat("ConnMaxUpRate", GetConnMaxUpRate());
	// Overall Run Time
	uint32 timeseconds = (GetTickCount()-theApp.stat_starttime)/1000;
	timeseconds+=GetConnRunTime();
	ini.WriteInt("ConnRunTime",timeseconds );
	// Number of Reconnects
	if (theApp.stat_reconnects>0) buffer.Format("%u",theApp.stat_reconnects - 1 + GetConnNumReconnects());
	else buffer.Format("%u",GetConnNumReconnects());
	ini.WriteString("ConnNumReconnects", buffer);
	// Average Connections
	if (theApp.serverconnect->IsConnected()){
		buffer.Format("%u",(uint32)(theApp.emuledlg->statisticswnd.GetAverageConnections()+prefs->cumConnAvgConnections)/2);
		ini.WriteString("ConnAvgConnections", buffer);
	}
	// Peak Connections
	if (theApp.emuledlg->statisticswnd.GetPeakConnections()>prefs->cumConnPeakConnections)
		prefs->cumConnPeakConnections = theApp.emuledlg->statisticswnd.GetPeakConnections();
	ini.WriteInt("ConnPeakConnections", prefs->cumConnPeakConnections);
	// Max Connection Limit Reached
	buffer.Format("%u",theApp.listensocket->GetMaxConnectionReached()+prefs->cumConnMaxConnLimitReached);
	if (atoi(buffer)>prefs->cumConnMaxConnLimitReached) ini.WriteString("ConnMaxConnLimitReached", buffer);
	// Time Stuff...
	ini.WriteInt("ConnTransferTime", GetConnTransferTime() + theApp.emuledlg->statisticswnd.GetTransferTime());
	ini.WriteInt("ConnUploadTime", GetConnUploadTime() + theApp.emuledlg->statisticswnd.GetUploadTime());
	ini.WriteInt("ConnDownloadTime", GetConnDownloadTime() + theApp.emuledlg->statisticswnd.GetDownloadTime());
	ini.WriteInt("ConnServerDuration", GetConnServerDuration() + theApp.emuledlg->statisticswnd.GetServerDuration());
	
	// Compare and Save Server Records
	uint32 servtotal, servfail, servuser, servfile, servtuser, servtfile; float servocc;
	theApp.serverlist->GetStatus( servtotal, servfail, servuser, servfile, servtuser, servtfile, servocc );
	
	if ((servtotal-servfail)>prefs->cumSrvrsMostWorkingServers)	prefs->cumSrvrsMostWorkingServers = servtotal-servfail;
	ini.WriteInt("SrvrsMostWorkingServers", prefs->cumSrvrsMostWorkingServers);
	if (servtuser>prefs->cumSrvrsMostUsersOnline) prefs->cumSrvrsMostUsersOnline = servtuser;
	ini.WriteInt("SrvrsMostUsersOnline", prefs->cumSrvrsMostUsersOnline);
	if (servtfile>prefs->cumSrvrsMostFilesAvail) prefs->cumSrvrsMostFilesAvail = servtfile;
	ini.WriteInt("SrvrsMostFilesAvail", prefs->cumSrvrsMostFilesAvail);

	// Compare and Save Shared File Records
	if (theApp.sharedfiles->GetCount()>prefs->cumSharedMostFilesShared)	prefs->cumSharedMostFilesShared = theApp.sharedfiles->GetCount();
	ini.WriteInt("SharedMostFilesShared", prefs->cumSharedMostFilesShared);
	uint64 bytesLargestFile = 0;
	uint64 allsize=theApp.sharedfiles->GetDatasize(bytesLargestFile);
	if (allsize>prefs->cumSharedLargestShareSize) prefs->cumSharedLargestShareSize = allsize;
	buffer.Format("%I64u", prefs->cumSharedLargestShareSize);
	ini.WriteString("SharedLargestShareSize", buffer);
	if (bytesLargestFile>prefs->cumSharedLargestFileSize) prefs->cumSharedLargestFileSize = bytesLargestFile;
	buffer.Format("%I64u", prefs->cumSharedLargestFileSize);
	ini.WriteString("SharedLargestFileSize", buffer);
	if (theApp.sharedfiles->GetCount() != 0) {
		uint64 tempint = allsize/theApp.sharedfiles->GetCount();
		if (tempint>prefs->cumSharedLargestAvgFileSize)	prefs->cumSharedLargestAvgFileSize = tempint;
	}
	buffer.Format("%I64u",prefs->cumSharedLargestAvgFileSize);
	ini.WriteString("SharedLargestAvgFileSize", buffer);

	buffer.Format("%I64u",prefs->stat_datetimeLastReset);
	ini.WriteString("statsDateTimeLastReset", buffer);

	// If we are saving a back-up or a temporary back-up, return now.
	if (bBackUp != 0) return;

	// These aren't really statistics, but they're a part of my add-on, so we'll save them here and load them in LoadStats
	ini.WriteInt("statsConnectionsGraphRatio", prefs->statsConnectionsGraphRatio, "Statistics");
	ini.WriteString("statsExpandedTreeItems", prefs->statsExpandedTreeItems, "Statistics");

	// End SaveStats
}

void CPreferences::SetRecordStructMembers() {

	// The purpose of this function is to be called from CStatisticsDlg::ShowStatistics()
	// This was easier than making a bunch of functions to interface with the record
	// members of the prefs struct from ShowStatistics.

	// This function is going to compare current values with previously saved records, and if
	// the current values are greater, the corresponding member of prefs will be updated.
	// We will not write to INI here, because this code is going to be called a lot more often
	// than SaveStats()  - Khaos

	CString buffer;

	// Servers
	uint32 servtotal, servfail, servuser, servfile, servtuser, servtfile; float servocc;
	theApp.serverlist->GetStatus( servtotal, servfail, servuser, servfile, servtuser, servtfile, servocc );
	if ((servtotal-servfail)>prefs->cumSrvrsMostWorkingServers) prefs->cumSrvrsMostWorkingServers = (servtotal-servfail);
	if (servtuser>prefs->cumSrvrsMostUsersOnline) prefs->cumSrvrsMostUsersOnline = servtuser;
	if (servtfile>prefs->cumSrvrsMostFilesAvail) prefs->cumSrvrsMostFilesAvail = servtfile;

	// Shared Files
	if (theApp.sharedfiles->GetCount()>prefs->cumSharedMostFilesShared) prefs->cumSharedMostFilesShared = theApp.sharedfiles->GetCount();
	uint64 bytesLargestFile = 0;
	uint64 allsize=theApp.sharedfiles->GetDatasize(bytesLargestFile);
	if (allsize>prefs->cumSharedLargestShareSize) prefs->cumSharedLargestShareSize = allsize;
	if (bytesLargestFile>prefs->cumSharedLargestFileSize) prefs->cumSharedLargestFileSize = bytesLargestFile;
	if (theApp.sharedfiles->GetCount() != 0) {
		uint64 tempint = allsize/theApp.sharedfiles->GetCount();
		if (tempint>prefs->cumSharedLargestAvgFileSize) prefs->cumSharedLargestAvgFileSize = tempint;
	}
} // SetRecordStructMembers()

void CPreferences::SaveCompletedDownloadsStat(){

	// This function saves the values for the completed
	// download members to INI.  It is called from
	// CPartfile::PerformFileComplete ...   - Khaos

	char* fullpath = new char[strlen(configdir)+MAX_PATH]; // i_a
	sprintf(fullpath,"%spreferences.ini",configdir);
	
	CIni ini( fullpath, "eMule" );

	delete[] fullpath;

	ini.WriteInt("DownCompletedFiles",			GetDownCompletedFiles(),		"Statistics");
	ini.WriteInt("DownSessionCompletedFiles",	GetDownSessionCompletedFiles(),	"Statistics");
} // SaveCompletedDownloadsStat()

void CPreferences::Add2SessionTransferData(uint8 uClientID, uint16 uClientPort, BOOL bFromPF, BOOL bUpDown, uint32 bytes, bool sentToFriend = false){

	//	This function adds the transferred bytes to the appropriate variables,
	//	as well as to the totals for all clients. - Khaos
	//	PARAMETERS:
	//	uClientID - The identifier for which client software sent or received this data, eg SO_EMULE
	//	uClientPort - The remote port of the client that sent or received this data, eg 4662
	//	bFromPF - Applies only to uploads.  True is from partfile, False is from non-partfile.
	//	bUpDown - True is Up, False is Down
	//	bytes - Number of bytes sent by the client.  Subtract header before calling.

	switch (bUpDown){
		case true:
			//	Upline Data
			
			switch (uClientID){
				// Update session client breakdown stats for sent bytes...
				case SO_EDONKEY:		prefs->sesUpData_EDONKEY+=bytes;		break;
				case SO_EDONKEYHYBRID:	prefs->sesUpData_EDONKEYHYBRID+=bytes;	break;
				case SO_OLDEMULE:
				case SO_EMULE:			prefs->sesUpData_EMULE+=bytes;			break;
				case SO_MLDONKEY:		prefs->sesUpData_MLDONKEY+=bytes;		break;
				case SO_CDONKEY:		prefs->sesUpData_CDONKEY+=bytes;		break;
				case SO_LMULE:			prefs->sesUpData_LMULE+=bytes;			break;
				case SO_SHAREAZA:		prefs->sesUpData_SHAREAZA+=bytes;		break;
			}

			switch (uClientPort){
				// Update session port breakdown stats for sent bytes...
				case 4662:				prefs->sesUpDataPort_4662+=bytes;		break;
				default:				prefs->sesUpDataPort_OTHER+=bytes;		break;
			}

			if (bFromPF)				prefs->sesUpData_Partfile+=bytes;
			else						prefs->sesUpData_File+=bytes;

			//	Add to our total for sent bytes...
			theApp.UpdateSentBytes(bytes, sentToFriend);

			break;

		case false:
			// Downline Data

			switch (uClientID){
                // Update session client breakdown stats for received bytes...
				case SO_EDONKEY:		prefs->sesDownData_EDONKEY+=bytes;		break;
				case SO_EDONKEYHYBRID:	prefs->sesDownData_EDONKEYHYBRID+=bytes;break;
				case SO_OLDEMULE:
				case SO_EMULE:			prefs->sesDownData_EMULE+=bytes;		break;
				case SO_MLDONKEY:		prefs->sesDownData_MLDONKEY+=bytes;		break;
				case SO_CDONKEY:		prefs->sesDownData_CDONKEY+=bytes;		break;
				case SO_LMULE:			prefs->sesDownData_LMULE+=bytes;		break;
				case SO_SHAREAZA:		prefs->sesDownData_SHAREAZA+=bytes;		break;
			}

			switch (uClientPort){
				// Update session port breakdown stats for received bytes...
				// For now we are only going to break it down by default and non-default.
				// A statistical analysis of all data sent from every single port/domain is
				// beyond the scope of this add-on.
				case 4662:				prefs->sesDownDataPort_4662+=bytes;		break;
				default:				prefs->sesDownDataPort_OTHER+=bytes;	break;
			}

			//	Add to our total for received bytes...
			theApp.UpdateReceivedBytes(bytes);

	}

}

// Reset Statistics by Khaos

void CPreferences::ResetCumulativeStatistics(){

	// Save a backup so that we can undo this action
	SaveStats(1);

	// SET ALL CUMULATIVE STAT VALUES TO 0  :'-(

	prefs->totalDownloadedBytes=0;
	prefs->totalUploadedBytes=0;
	prefs->cumDownOverheadTotal=0;
	prefs->cumDownOverheadFileReq=0;
	prefs->cumDownOverheadSrcEx=0;
	prefs->cumDownOverheadServer=0;
	prefs->cumDownOverheadTotalPackets=0;
	prefs->cumDownOverheadFileReqPackets=0;
	prefs->cumDownOverheadSrcExPackets=0;
	prefs->cumDownOverheadServerPackets=0;
	prefs->cumUpOverheadTotal=0;
	prefs->cumUpOverheadFileReq=0;
	prefs->cumUpOverheadSrcEx=0;
	prefs->cumUpOverheadServer=0;
	prefs->cumUpOverheadTotalPackets=0;
	prefs->cumUpOverheadFileReqPackets=0;
	prefs->cumUpOverheadSrcExPackets=0;
	prefs->cumUpOverheadServerPackets=0;
	prefs->cumUpSuccessfulSessions=0;
	prefs->cumUpFailedSessions=0;
	prefs->cumUpAvgTime=0;
	prefs->cumUpData_EDONKEY=0;
	prefs->cumUpData_EDONKEYHYBRID=0;
	prefs->cumUpData_EMULE=0;
	prefs->cumUpData_MLDONKEY=0;
	prefs->cumUpData_CDONKEY=0;
	prefs->cumUpData_LMULE=0;
	prefs->cumUpData_SHAREAZA=0;
	prefs->cumUpDataPort_4662=0;
	prefs->cumUpDataPort_OTHER=0;
	prefs->cumDownCompletedFiles=0;
	prefs->cumDownSuccessfulSessions=0;
	prefs->cumDownFailedSessions=0;
	prefs->cumDownAvgTime=0;
	prefs->cumLostFromCorruption=0;
	prefs->cumSavedFromCompression=0;
	prefs->cumPartsSavedByICH=0;
	prefs->cumDownData_EDONKEY=0;
	prefs->cumDownData_EDONKEYHYBRID=0;
	prefs->cumDownData_EMULE=0;
	prefs->cumDownData_MLDONKEY=0;
	prefs->cumDownData_CDONKEY=0;
	prefs->cumDownData_LMULE=0;
	prefs->cumDownData_SHAREAZA=0;
	prefs->cumDownDataPort_4662=0;
	prefs->cumDownDataPort_OTHER=0;
	prefs->cumConnAvgDownRate=0;
	prefs->cumConnMaxAvgDownRate=0;
	prefs->cumConnMaxDownRate=0;
	prefs->cumConnAvgUpRate=0;
	prefs->cumConnRunTime=0;
	prefs->cumConnNumReconnects=0;
	prefs->cumConnAvgConnections=0;
	prefs->cumConnMaxConnLimitReached=0;
	prefs->cumConnPeakConnections=0;
	prefs->cumConnDownloadTime=0;
	prefs->cumConnUploadTime=0;
	prefs->cumConnTransferTime=0;
	prefs->cumConnServerDuration=0;
	prefs->cumConnMaxAvgUpRate=0;
	prefs->cumConnMaxUpRate=0;
	prefs->cumSrvrsMostWorkingServers=0;
	prefs->cumSrvrsMostUsersOnline=0;
	prefs->cumSrvrsMostFilesAvail=0;
    prefs->cumSharedMostFilesShared=0;
	prefs->cumSharedLargestShareSize=0;
	prefs->cumSharedLargestAvgFileSize=0;

	// Set the time of last reset...
	time_t	timeNow;time(&timeNow);prefs->stat_datetimeLastReset = (__int64) timeNow;

	// Save the reset stats
	SaveStats();

	// End Reset Statistics

}


// Load Statistics
// This used to be integrated in LoadPreferences, but it has been altered
// so that it can be used to load the backup created when the stats are reset.
// Last Modified: 2-22-03 by Khaos

bool CPreferences::LoadStats(int loadBackUp){
	// loadBackUp is 0 by default
	// loadBackUp = 0: Load the stats normally like we used to do in LoadPreferences
	// loadBackUp = 1: Load the stats from statbkup.ini and create a backup of the current stats.  Also, do not initialize session variables.
	// loadBackUp = 2: Load the stats from preferences.ini.old because the version has changed.
	char buffer[200];
	CString sINI;
	//uint64 temp64; moved
	CFileFind findBackUp;

	switch (loadBackUp) {
		case 0:
			sINI.Format("%spreferences.ini", configdir);
			break;
		case 1:
			sINI.Format("%sstatbkup.ini", configdir);
			if (!findBackUp.FindFile(sINI))
				return false;

			SaveStats(2); // Save our temp backup of current values to statbkuptmp.ini, we will be renaming it at the end of this function.
			break;
		case 2:
			sINI.Format("%spreferences.ini.old",configdir);
			break;
	}

	bool fileex=PathFileExists(sINI);
	CIni ini(sINI, "Statistics");

	sprintf(buffer , ini.GetString(			"TotalDownloadedBytes"			, 0 ) );
	prefs->totalDownloadedBytes=			_atoi64( buffer );

	sprintf(buffer , ini.GetString(			"TotalUploadedBytes"			, 0 ) );
	prefs->totalUploadedBytes=				_atoi64( buffer );

	// Load stats for cumulative downline overhead
	sprintf(buffer,ini.GetString(			"DownOverheadTotal"				, 0	) );
	prefs->cumDownOverheadTotal=			_atoi64( buffer );
	sprintf(buffer,ini.GetString(			"DownOverheadFileReq"			, 0	) );
	prefs->cumDownOverheadFileReq=			_atoi64( buffer );
	sprintf(buffer,ini.GetString(			"DownOverheadSrcEx"				, 0	) );
	prefs->cumDownOverheadSrcEx=			_atoi64( buffer );
	sprintf(buffer,ini.GetString(			"DownOverheadServer"			, 0	) );
	prefs->cumDownOverheadServer=			_atoi64( buffer );
	sprintf(buffer,ini.GetString(			"DownOverheadTotalPackets"		, 0 ) );
	prefs->cumDownOverheadTotalPackets=		_atoi64( buffer );
	sprintf(buffer,ini.GetString(			"DownOverheadFileReqPackets"	, 0 ) );
	prefs->cumDownOverheadFileReqPackets=	_atoi64( buffer );
	sprintf(buffer,ini.GetString(			"DownOverheadSrcExPackets"		, 0 ) );
	prefs->cumDownOverheadSrcExPackets=		_atoi64( buffer );
	sprintf(buffer,ini.GetString(			"DownOverheadServerPackets"		, 0 ) );
	prefs->cumDownOverheadServerPackets=	_atoi64( buffer );

	// Load stats for cumulative upline overhead
	sprintf(buffer , ini.GetString(			"UpOverHeadTotal"				, 0 ) );
	prefs->cumUpOverheadTotal=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpOverheadFileReq"				, 0 ) );
	prefs->cumUpOverheadFileReq=			_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpOverheadSrcEx"				, 0 ) );
	prefs->cumUpOverheadSrcEx=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpOverheadServer"				, 0 ) );
	prefs->cumUpOverheadServer=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpOverHeadTotalPackets"		, 0 ) );
	prefs->cumUpOverheadTotalPackets=		_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpOverheadFileReqPackets"		, 0 ) );
	prefs->cumUpOverheadFileReqPackets=		_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpOverheadSrcExPackets"		, 0 ) );
	prefs->cumUpOverheadSrcExPackets=		_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpOverheadServerPackets"		, 0 ) );
	prefs->cumUpOverheadServerPackets=		_atoi64( buffer );

	// Load stats for cumulative upline data
	prefs->cumUpSuccessfulSessions =	ini.GetInt("UpSuccessfulSessions"	, 0 );
	prefs->cumUpFailedSessions =		ini.GetInt("UpFailedSessions"		, 0 );
	prefs->cumUpAvgTime =				ini.GetInt("UpAvgTime"				, 0 );

	// Load cumulative client breakdown stats for sent bytes
	sprintf(buffer , ini.GetString(			"UpData_EDONKEY"				, 0 ) );
	prefs->cumUpData_EDONKEY=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpData_EDONKEYHYBRID"			, 0 ) );
	prefs->cumUpData_EDONKEYHYBRID=			_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpData_EMULE"					, 0 ) );
	prefs->cumUpData_EMULE=					_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpData_MLDONKEY"				, 0 ) );
	prefs->cumUpData_MLDONKEY=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpData_LMULE"					, 0 ) );
	prefs->cumUpData_LMULE=					_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpData_CDONKEY"				, 0 ) );
	prefs->cumUpData_CDONKEY=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpData_SHAREAZA"				, 0 ) );
	prefs->cumUpData_SHAREAZA=				_atoi64( buffer );

	// Load cumulative port breakdown stats for sent bytes
	sprintf(buffer , ini.GetString(			"UpDataPort_4662"				, 0 ) );
	prefs->cumUpDataPort_4662=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpDataPort_OTHER"				, 0 ) );
	prefs->cumUpDataPort_OTHER=				_atoi64( buffer );

	// Load cumulative source breakdown stats for sent bytes
	sprintf(buffer , ini.GetString(			"UpData_File"					, 0 ) );
	prefs->cumUpData_File=					_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"UpData_Partfile"				, 0 ) );
	prefs->cumUpData_Partfile=				_atoi64( buffer );

	// Load stats for cumulative downline data
	prefs->cumDownCompletedFiles =		ini.GetInt("DownCompletedFiles"		, 0 );
	prefs->cumDownSuccessfulSessions=	ini.GetInt("DownSuccessfulSessions"	, 0 );
	prefs->cumDownFailedSessions=		ini.GetInt("DownFailedSessions"		, 0 );
	prefs->cumDownAvgTime=				ini.GetInt("DownAvgTime"			, 0 );

	// Cumulative statistics for saved due to compression/lost due to corruption
	sprintf(buffer , ini.GetString(			"LostFromCorruption"			, 0 ) );
	prefs->cumLostFromCorruption=			_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"SavedFromCompression"			, 0 ) );
	prefs->cumSavedFromCompression=			_atoi64( buffer );
	prefs->cumPartsSavedByICH=			ini.GetInt("PartsSavedByICH"		, 0 );

	// Load cumulative client breakdown stats for received bytes
	sprintf(buffer , ini.GetString(			"DownData_EDONKEY"				, 0 ) );
	prefs->cumDownData_EDONKEY=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"DownData_EDONKEYHYBRID"		, 0 ) );
	prefs->cumDownData_EDONKEYHYBRID=		_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"DownData_EMULE"				, 0 ) );
	prefs->cumDownData_EMULE=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"DownData_MLDONKEY"				, 0 ) );
	prefs->cumDownData_MLDONKEY=			_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"DownData_LMULE"				, 0 ) );
	prefs->cumDownData_LMULE=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"DownData_CDONKEY"				, 0 ) );
	prefs->cumDownData_CDONKEY=				_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"DownData_SHAREAZA"				, 0 ) );
	prefs->cumDownData_SHAREAZA=				_atoi64( buffer );

	// Load cumulative port breakdown stats for received bytes
	sprintf(buffer , ini.GetString(			"DownDataPort_4662"				, 0 ) );
	prefs->cumDownDataPort_4662=			_atoi64( buffer );
	sprintf(buffer , ini.GetString(			"DownDataPort_OTHER"			, 0 ) );
	prefs->cumDownDataPort_OTHER=			_atoi64( buffer );

	// Load stats for cumulative connection data
	prefs->cumConnAvgDownRate =		ini.GetFloat(	"ConnAvgDownRate"		, 0 );
	prefs->cumConnMaxAvgDownRate =	ini.GetFloat(	"ConnMaxAvgDownRate"	, 0 );
	prefs->cumConnMaxDownRate =		ini.GetFloat(	"ConnMaxDownRate"		, 0 );
	prefs->cumConnAvgUpRate =		ini.GetFloat(	"ConnAvgUpRate"			, 0 );
	prefs->cumConnMaxAvgUpRate =	ini.GetFloat(	"ConnMaxAvgUpRate"		, 0 );
	prefs->cumConnMaxUpRate =		ini.GetFloat(	"ConnMaxUpRate"			, 0 );

	sprintf(buffer , ini.GetString(			"ConnRunTime"					, 0 ) );
	prefs->cumConnRunTime=					_atoi64(buffer);

	prefs->cumConnTransferTime=			ini.GetInt(	"ConnTransferTime"			, 0 );
	prefs->cumConnDownloadTime=			ini.GetInt(	"ConnDownloadTime"			, 0 );
	prefs->cumConnUploadTime=			ini.GetInt(	"ConnUploadTime"			, 0 );
	prefs->cumConnServerDuration=		ini.GetInt( "ConnServerDuration"		, 0 );
	prefs->cumConnNumReconnects =		ini.GetInt(	"ConnNumReconnects"			, 0 );
	prefs->cumConnAvgConnections =		ini.GetInt(	"ConnAvgConnections"		, 0 );
	prefs->cumConnMaxConnLimitReached=	ini.GetInt(	"ConnMaxConnLimitReached"	, 0 );
	prefs->cumConnPeakConnections =		ini.GetInt(	"ConnPeakConnections"		, 0 );

	// Load date/time of last reset
	sprintf(buffer , ini.GetString(			"statsDateTimeLastReset"		, 0 ) );
	prefs->stat_datetimeLastReset=			_atoi64( buffer );

	// Smart Load For Restores - Don't overwrite records that are greater than the backed up ones
	if (loadBackUp == 1) {
		uint64 temp64;
		// Load records for servers / network
		if (ini.GetInt("SrvrsMostWorkingServers", 0) > prefs->cumSrvrsMostWorkingServers)
			prefs->cumSrvrsMostWorkingServers = ini.GetInt(		"SrvrsMostWorkingServers"	, 0 );
		if (ini.GetInt("SrvrsMostUsersOnline", 0) > (int)prefs->cumSrvrsMostUsersOnline)
			prefs->cumSrvrsMostUsersOnline =	ini.GetInt(		"SrvrsMostUsersOnline"		, 0 );
		if (ini.GetInt("SrvrsMostFilesAvail", 0) > (int)prefs->cumSrvrsMostFilesAvail)
			prefs->cumSrvrsMostFilesAvail =		ini.GetInt(		"SrvrsMostFilesAvail"		, 0 );

		// Load records for shared files
		if (ini.GetInt("SharedMostFilesShared ", 0, "Statistics") > prefs->cumSharedMostFilesShared)
			prefs->cumSharedMostFilesShared =	ini.GetInt(		"SharedMostFilesShared"		, 0 );

		sprintf(buffer , ini.GetString(	"SharedLargestShareSize" , 0 ) );
		temp64 = _atoi64( buffer );
		if (temp64 > prefs->cumSharedLargestShareSize) prefs->cumSharedLargestShareSize = temp64;
		sprintf(buffer , ini.GetString( "SharedLargestAvgFileSize" , 0 ) );
		temp64 = _atoi64( buffer );
		if (temp64 > prefs->cumSharedLargestAvgFileSize) prefs->cumSharedLargestAvgFileSize = temp64;
		sprintf(buffer , ini.GetString( "SharedLargestFileSize" , 0 ) );
		temp64 = _atoi64( buffer );
		if (temp64 > prefs->cumSharedLargestFileSize) prefs->cumSharedLargestFileSize = temp64;

		// Check to make sure the backup of the values we just overwrote exists.  If so, rename it to the backup file.
		// This allows us to undo a restore, so to speak, just in case we don't like the restored values...
		CString sINIBackUp;
		sINIBackUp.Format("%sstatbkuptmp.ini", configdir);
		if (findBackUp.FindFile(sINIBackUp)) {		
			CFile::Remove(sINI); // Remove the backup that we just restored from
			CFile::Rename(sINIBackUp, sINI); // Rename our temporary backup to the normal statbkup.ini filename.
		}

		// Since we know this is a restore, now we should call ShowStatistics to update the data items to the new ones we just loaded.
		// Otherwise user is left waiting around for the tick counter to reach the next automatic update (Depending on setting in prefs)
		theApp.emuledlg->statisticswnd.ShowStatistics();
		
	}
	// Stupid Load -> Just load the values.
	else {
		// Load records for servers / network
		prefs->cumSrvrsMostWorkingServers = ini.GetInt(		"SrvrsMostWorkingServers"	, 0 );
		prefs->cumSrvrsMostUsersOnline =	ini.GetInt(		"SrvrsMostUsersOnline"		, 0 );
		prefs->cumSrvrsMostFilesAvail =		ini.GetInt(		"SrvrsMostFilesAvail"		, 0 );

		// Load records for shared files
		prefs->cumSharedMostFilesShared =	ini.GetInt(		"SharedMostFilesShared"		, 0 );

		sprintf(buffer , ini.GetString(		"SharedLargestShareSize"					, 0 ) );
		prefs->cumSharedLargestShareSize=	_atoi64( buffer );
		sprintf(buffer , ini.GetString(		"SharedLargestAvgFileSize"					, 0 ) );
		prefs->cumSharedLargestAvgFileSize=	_atoi64( buffer );
		sprintf(buffer , ini.GetString(		"SharedLargestFileSize"						, 0 ) );
		prefs->cumSharedLargestFileSize =	_atoi64( buffer );

		// These are not stats, but they're part of my mod, so we will load them here anyway.
		prefs->statsConnectionsGraphRatio =		ini.GetInt("statsConnectionsGraphRatio"	, 3	, "Statistics");
		sprintf(prefs->statsExpandedTreeItems,"%s",ini.GetString("statsExpandedTreeItems","111000000100000110000010000011110000010010","Statistics"));

		// Initialize new session statistic variables...
		prefs->sesDownCompletedFiles =		0;
		prefs->sesUpData_EDONKEY =			0;
		prefs->sesUpData_EDONKEYHYBRID =	0;
		prefs->sesUpData_EMULE =			0;
		prefs->sesUpData_MLDONKEY =			0;
		prefs->sesUpData_CDONKEY =			0;
		prefs->sesUpDataPort_4662 =			0;
		prefs->sesUpDataPort_OTHER =		0;
		prefs->sesDownData_EDONKEY =		0;
		prefs->sesDownData_EDONKEYHYBRID =	0;
		prefs->sesDownData_EMULE =			0;
		prefs->sesDownData_MLDONKEY =		0;
		prefs->sesDownData_CDONKEY =		0;
		prefs->sesDownData_SHAREAZA =		0;
		prefs->sesDownDataPort_4662 =		0;
		prefs->sesDownDataPort_OTHER =		0;
		prefs->sesDownSuccessfulSessions=	0;
		prefs->sesDownFailedSessions=		0;
		prefs->sesPartsSavedByICH=			0;
	}

	if (!fileex) {time_t	timeNow;time(&timeNow);prefs->stat_datetimeLastReset = (__int64) timeNow;}
	
	return true;

	// End Load Stats
}

// This formats the UCT long value that is saved for stat_datetimeLastReset
// If this value is 0 (Never reset), then it returns Unknown.
CString CPreferences::GetStatsLastResetStr(bool formatLong)
{
	// formatLong dictates the format of the string returned.
	// For example...
	// true: DateTime format from the .ini
	// false: DateTime format from the .ini for the log
	CString	returnStr;
	if (GetStatsLastResetLng()) {
		tm		*statsReset;
		char	strDateReset[128];
		time_t	lastResetDateTime = (time_t) GetStatsLastResetLng();
		statsReset = localtime(&lastResetDateTime);
		strftime(strDateReset, 128, formatLong?GetDateTimeFormat():GetDateTimeFormat4Log(), statsReset);
		returnStr.Format("%s", strDateReset);
	}
	else returnStr = GetResString(IDS_UNKNOWN);
	return returnStr;
}

// <-----khaos-

bool CPreferences::Save(){

	bool error = false;
	char* fullpath = new char[strlen(configdir)+MAX_PATH]; // i_a
	sprintf(fullpath,"%spreferences.dat",configdir);

	FILE* preffile = fopen(fullpath,"wb");
	prefsExt->version = PREFFILE_VERSION;

	// -khaos--+++> Don't save stats if preferences.ini doesn't exist yet (Results in unhandled exception).
	sprintf(fullpath,"%spreferences.ini",configdir);
	bool bSaveStats = true;
	if (!PathFileExists(fullpath))
		bSaveStats = false;
	// <-----khaos-

	delete[] fullpath;
	if (preffile){
		prefsExt->version=PREFFILE_VERSION;
		prefsExt->EmuleWindowPlacement=prefs->EmuleWindowPlacement;
		md4cpy(&prefsExt->userhash,&prefs->userhash);

		error = fwrite(prefsExt,sizeof(Preferences_Ext_Struct),1,preffile);
		fclose(preffile);
	}
	else
		error = true;

	SavePreferences();
	// -khaos--+++> SaveStats is now called here instead of from SavePreferences...
	if (bSaveStats)
		SaveStats();
	// <-----khaos-

	fullpath = new char[strlen(configdir)+14];
	sprintf(fullpath,"%sshareddir.dat",configdir);
	CStdioFile sdirfile;
	if (sdirfile.Open(fullpath,CFile::modeCreate|CFile::modeWrite)){

		for (POSITION pos = shareddir_list.GetHeadPosition();pos != 0;shareddir_list.GetNext(pos)){
			sdirfile.WriteString(shareddir_list.GetAt(pos).GetBuffer());
			sdirfile.Write("\n",1);
		}
		sdirfile.Close();
	}
	else
		error = true;
	delete[] fullpath;
	fullpath=NULL;
	::CreateDirectory(GetIncomingDir(),0);
	::CreateDirectory(GetTempDir(),0);
	return error;
}

void CPreferences::CreateUserHash(){
	for (int i = 0;i != 8; i++){ 
		uint16	random = rand();
		memcpy(&userhash[i*2],&random,2);
	}
	// mark as emule client. that will be need in later version
	userhash[5] = 14;
	userhash[14] = 111;
}

int CPreferences::GetColumnWidth(Table t, int index) const {
	switch(t) {
	case tableDownload:
		return prefs->downloadColumnWidths[index];
	case tableUpload:
		return prefs->uploadColumnWidths[index];
	case tableQueue:
		return prefs->queueColumnWidths[index];
	case tableSearch:
		return prefs->searchColumnWidths[index];
	case tableShared:
		return prefs->sharedColumnWidths[index];
	case tableServer:
		return prefs->serverColumnWidths[index];
	case tableClientList:
		return prefs->clientListColumnWidths[index];
	}
	return 0;
}

void CPreferences::SetColumnWidth(Table t, int index, int width) {
	switch(t) {
	case tableDownload:
		prefs->downloadColumnWidths[index] = width;
		break;
	case tableUpload:
		prefs->uploadColumnWidths[index] = width;
		break;
	case tableQueue:
		prefs->queueColumnWidths[index] = width;
		break;
	case tableSearch:
		prefs->searchColumnWidths[index] = width;
		break;
	case tableShared:
		prefs->sharedColumnWidths[index] = width;
		break;
	case tableServer:
		prefs->serverColumnWidths[index] = width;
		break;
	case tableClientList:
		prefs->clientListColumnWidths[index] = width;
		break;
	}
}

BOOL CPreferences::GetColumnHidden(Table t, int index) const {
	switch(t) {
	case tableDownload:
		return prefs->downloadColumnHidden[index];
	case tableUpload:
		return prefs->uploadColumnHidden[index];
	case tableQueue:
		return prefs->queueColumnHidden[index];
	case tableSearch:
		return prefs->searchColumnHidden[index];
	case tableShared:
		return prefs->sharedColumnHidden[index];
	case tableServer:
		return prefs->serverColumnHidden[index];
	case tableClientList:
		return prefs->clientListColumnHidden[index];
	}
	return FALSE;
}

void CPreferences::SetColumnHidden(Table t, int index, BOOL bHidden) {
	switch(t) {
	case tableDownload:
		prefs->downloadColumnHidden[index] = bHidden;
		break;
	case tableUpload:
		prefs->uploadColumnHidden[index] = bHidden;
		break;
	case tableQueue:
		prefs->queueColumnHidden[index] = bHidden;
		break;
	case tableSearch:
		prefs->searchColumnHidden[index] = bHidden;
		break;
	case tableShared:
		prefs->sharedColumnHidden[index] = bHidden;
		break;
	case tableServer:
		prefs->serverColumnHidden[index] = bHidden;
		break;
	case tableClientList:
		prefs->clientListColumnHidden[index] = bHidden;
		break;
	}
}

int CPreferences::GetColumnOrder(Table t, int index) const {
	switch(t) {
	case tableDownload:
		return prefs->downloadColumnOrder[index];
	case tableUpload:
		return prefs->uploadColumnOrder[index];
	case tableQueue:
		return prefs->queueColumnOrder[index];
	case tableSearch:
		return prefs->searchColumnOrder[index];
	case tableShared:
		return prefs->sharedColumnOrder[index];
	case tableServer:
		return prefs->serverColumnOrder[index];
	case tableClientList:
		return prefs->clientListColumnOrder[index];
	}
	return 0;
}

void CPreferences::SetColumnOrder(Table t, INT *piOrder) {
	switch(t) {
	case tableDownload:
		memcpy(prefs->downloadColumnOrder, piOrder, sizeof(prefs->downloadColumnOrder));
		break;
	case tableUpload:
		memcpy(prefs->uploadColumnOrder, piOrder, sizeof(prefs->uploadColumnOrder));
		break;
	case tableQueue:
		memcpy(prefs->queueColumnOrder, piOrder, sizeof(prefs->queueColumnOrder));
		break;
	case tableSearch:
		memcpy(prefs->searchColumnOrder, piOrder, sizeof(prefs->searchColumnOrder));
		break;
	case tableShared:
		memcpy(prefs->sharedColumnOrder, piOrder, sizeof(prefs->sharedColumnOrder));
		break;
	case tableServer:
		memcpy(prefs->serverColumnOrder, piOrder, sizeof(prefs->serverColumnOrder));
		break;
	case tableClientList:
		memcpy(prefs->clientListColumnOrder, piOrder, sizeof(prefs->clientListColumnOrder));
		break;
	}
}

CPreferences::~CPreferences(){

	Category_Struct* delcat;
	while (!catMap.IsEmpty()) {
		delcat=catMap.GetAt(0); 
		catMap.RemoveAt(0); 
		delete delcat;
	}

//	delete[] appdir;
//	delete[] configdir;
	delete prefs;
	delete prefsExt;
}

int CPreferences::GetRecommendedMaxConnections() {
	int iRealMax = ::GetMaxConnections();
	if(iRealMax == -1 || iRealMax > 520)
		return 500;

	if(iRealMax < 20)
		return iRealMax;

	if(iRealMax <= 256)
		return iRealMax - 10;

	return iRealMax - 20;
}

void CPreferences::SavePreferences(){
	CString buffer;
	char* fullpath = new char[strlen(configdir)+MAX_PATH]; // i_a
	sprintf(fullpath,"%spreferences.ini",configdir);
	
	CIni ini( fullpath, "eMule" );
	delete[] fullpath;
	fullpath=NULL;
	//---
	ini.WriteString("AppVersion", CURRENT_VERSION_LONG);
	//---

	buffer.Format("%s",prefs->nick);
	ini.WriteString("Nick",buffer);

	buffer.Format("%s",prefs->incomingdir);
	ini.WriteString("IncomingDir",buffer );

	buffer.Format("%s",prefs->tempdir);
	ini.WriteString("TempDir",buffer );

	ini.WriteInt("MaxUpload",prefs->maxupload);
	ini.WriteInt("MaxDownload",prefs->maxdownload);
	ini.WriteInt("MaxConnections",prefs->maxconnections);
	ini.WriteInt("RemoveDeadServer",prefs->deadserver);
	ini.WriteInt("Port",prefs->port);
	ini.WriteInt("UDPPort",prefs->udpport);
	ini.WriteInt("MaxSourcesPerFile",prefs->maxsourceperfile );
	ini.WriteWORD("Language",prefs->languageID);
	ini.WriteInt("SeeShare",prefs->m_iSeeShares);
	ini.WriteInt("ToolTipDelay",prefs->m_iToolDelayTime);
	ini.WriteInt("StatGraphsInterval",prefs->trafficOMeterInterval);
	ini.WriteInt("StatsInterval",prefs->statsInterval);
	ini.WriteInt("DownloadCapacity",prefs->maxGraphDownloadRate);
	ini.WriteInt("UploadCapacity",prefs->maxGraphUploadRate);
	ini.WriteInt("DeadServerRetry",prefs->deadserverretries);
	ini.WriteInt("SplitterbarPosition",prefs->splitterbarPosition+2);
	ini.WriteInt("VariousStatisticsMaxValue",prefs->statsMax);
	ini.WriteInt("StatsAverageMinutes",prefs->statsAverageMinutes);
	ini.WriteInt("MaxConnectionsPerFiveSeconds",prefs->MaxConperFive);
	ini.WriteInt("Check4NewVersionDelay",prefs->versioncheckdays);

	ini.WriteBool("Reconnect",prefs->reconnect);
	ini.WriteBool("Scoresystem",prefs->scorsystem);
	ini.WriteBool("ICH",prefs->ICH);
	ini.WriteBool("Serverlist",prefs->autoserverlist);
	ini.WriteBool("UpdateNotify",prefs->updatenotify);
	ini.WriteBool("MinToTray",prefs->mintotray);
	ini.WriteBool("AddServersFromServer",prefs->addserversfromserver);
	ini.WriteBool("AddServersFromClient",prefs->addserversfromclient);
	ini.WriteBool("Splashscreen",prefs->splashscreen);
	ini.WriteBool("BringToFront",prefs->bringtoforeground);
	ini.WriteBool("TransferDoubleClick",prefs->transferDoubleclick);
	ini.WriteBool("BeepOnError",prefs->beepOnError);
	ini.WriteBool("ConfirmExit",prefs->confirmExit);
	ini.WriteBool("FilterBadIPs",prefs->filterBadIP);
    ini.WriteBool("Autoconnect",prefs->autoconnect);
	ini.WriteBool("OnlineSignature",prefs->onlineSig);
	ini.WriteBool("StartupMinimized",prefs->startMinimized);
	ini.WriteBool("SafeServerConnect",prefs->safeServerConnect);
	ini.WriteBool("ShowRatesOnTitle",prefs->showRatesInTitle);
	ini.WriteBool("IndicateRatings",prefs->indicateratings);
	ini.WriteBool("WatchClipboard4ED2kFilelinks",prefs->watchclipboard);

	// Barry - New properties...
    ini.WriteBool("AutoConnectStaticOnly", prefs->autoconnectstaticonly);  
	ini.WriteBool("AutoTakeED2KLinks", prefs->autotakeed2klinks);  
    ini.WriteBool("AddNewFilesPaused", prefs->addnewfilespaused);  
    ini.WriteInt ("3DDepth", prefs->depth3D);  

	ini.WriteBool("NotifyOnDownload",prefs->useDownloadNotifier); // Added by enkeyDEV
	ini.WriteBool("NotifyOnChat",prefs->useChatNotifier);		  
	ini.WriteBool("NotifyOnLog",prefs->useLogNotifier);
	ini.WriteBool("NotifierUseSound",prefs->useSoundInNotifier);
	ini.WriteBool("NotifierPopEveryChatMessage",prefs->notifierPopsEveryChatMsg);
	ini.WriteBool("NotifierPopNewVersion",prefs->notifierNewVersion);

	buffer.Format("%s",prefs->notifierSoundFilePath);
	ini.WriteString("NotifierSoundPath",buffer);
	buffer.Format("%s",prefs->notifierConfiguration);		      // Added by enkeyDEV
	ini.WriteString("NotifierConfiguration",buffer);			  // Added by enkeyDEV
	ini.WriteString("TxtEditor",prefs->TxtEditor);
	ini.WriteString("VideoPlayer",prefs->VideoPlayer);
	ini.WriteString("MessageFilter",prefs->messageFilter);
	ini.WriteString("CommentFilter",prefs->commentFilter);
	ini.WriteString("DateTimeFormat",GetDateTimeFormat());
	ini.WriteString("DateTimeFormat4Log",GetDateTimeFormat4Log());
	ini.WriteString("WebTemplateFile",prefs->m_sTemplateFile);
	ini.WriteString("FilenameCleanups",prefs->filenameCleanups);

	ini.WriteString("DefaultIRCServer",prefs->m_sircserver);
	ini.WriteString("IRCNick",prefs->m_sircnick);
	ini.WriteBool("IRCAddTimestamp", prefs->m_bircaddtimestamp);
	ini.WriteString("IRCFilterName", prefs->m_sircchannamefilter);
	ini.WriteInt("IRCFilterUser", prefs->m_iircchanneluserfilter);
	ini.WriteBool("IRCUseFilter", prefs->m_bircusechanfilter);
	ini.WriteString("IRCPerformString", prefs->m_sircperformstring);
	ini.WriteBool("IRCUsePerform", prefs->m_bircuseperform);
	ini.WriteBool("IRCListOnConnect", prefs->m_birclistonconnect);
	ini.WriteBool("IRCAcceptLinks", prefs->m_bircacceptlinks);
	ini.WriteBool("IRCIgnoreInfoMessage", prefs->m_bircignoreinfomessage);
	ini.WriteBool("IRCIgnoreEmuleProtoInfoMessage", prefs->m_bircignoreemuleprotoinfomessage);
	ini.WriteBool("NotifyOnImportantError", prefs->notifierImportantError);
	ini.WriteBool("SmartIdCheck", prefs->smartidcheck);
	ini.WriteBool("Verbose", prefs->m_bVerbose);
	ini.WriteBool("DebugSourceExchange", prefs->m_bDebugSourceExchange);
	ini.WriteBool("PreviewPrio", prefs->m_bpreviewprio);
	ini.WriteBool("UpdateQueueListPref", prefs->m_bupdatequeuelist);
	ini.WriteBool("ManualHighPrio", prefs->m_bmanualhighprio);
	ini.WriteBool("FullChunkTransfers", prefs->m_btransferfullchunks);
	ini.WriteBool("StartNextFile", prefs->m_bstartnextfile);
	ini.WriteBool("ShowOverhead", prefs->m_bshowoverhead);
	ini.WriteBool("VideoPreviewBackupped", prefs->moviePreviewBackup);
	ini.WriteInt("FileBufferSizePref", prefs->m_iFileBufferSize);
	ini.WriteInt("QueueSizePref", prefs->m_iQueueSize);
	ini.WriteBool("DAPPref", prefs->m_bDAP);
	ini.WriteBool("UAPPref", prefs->m_bUAP);
	ini.WriteInt("AllcatType", prefs->allcatType);
	ini.WriteBool("FilterServersByIP",prefs->filterserverbyip);
	ini.WriteBool("DisableKnownClientList",prefs->m_bDisableKnownClientList);
	ini.WriteBool("DisableQueueList",prefs->m_bDisableQueueList);
	ini.WriteBool("UseCreditSystem",prefs->m_bCreditSystem);
	ini.WriteBool("SaveLogToDisk",prefs->log2disk);
	ini.WriteBool("SaveDebugToDisk",prefs->debug2disk);
	ini.WriteBool("EnableScheduler",prefs->scheduler);
	ini.WriteBool("MessagesFromFriendsOnly",prefs->msgonlyfriends);
	ini.WriteBool("MessageFromValidSourcesOnly",prefs->msgsecure);
	ini.WriteBool("ShowInfoOnCatTabs",prefs->showCatTabInfos);
	ini.WriteBool("ResumeNextFromSameCat",prefs->resumeSameCat);
	ini.WriteBool("DontRecreateStatGraphsOnResize",prefs->dontRecreateGraphs);
	ini.WriteBool("AutoFilenameCleanup",prefs->autofilenamecleanup);

	ini.WriteInt("VersionCheckLastAutomatic", prefs->versioncheckLastAutomatic);
	ini.WriteInt("FilterLevel",prefs->filterlevel);


	ini.SerGet(false, prefs->downloadColumnWidths,
		ELEMENT_COUNT(prefs->downloadColumnWidths), "DownloadColumnWidths");
	ini.SerGet(false, prefs->downloadColumnHidden,
		ELEMENT_COUNT(prefs->downloadColumnHidden), "DownloadColumnHidden");
	ini.SerGet(false, prefs->downloadColumnOrder,
		ELEMENT_COUNT(prefs->downloadColumnOrder), "DownloadColumnOrder");
	ini.SerGet(false, prefs->uploadColumnWidths,
		ELEMENT_COUNT(prefs->uploadColumnWidths), "UploadColumnWidths");
	ini.SerGet(false, prefs->uploadColumnHidden,
		ELEMENT_COUNT(prefs->uploadColumnHidden), "UploadColumnHidden");
	ini.SerGet(false, prefs->uploadColumnOrder,
		ELEMENT_COUNT(prefs->uploadColumnOrder), "UploadColumnOrder");
	ini.SerGet(false, prefs->queueColumnWidths,
		ELEMENT_COUNT(prefs->queueColumnWidths), "QueueColumnWidths");
	ini.SerGet(false, prefs->queueColumnHidden,
		ELEMENT_COUNT(prefs->queueColumnHidden), "QueueColumnHidden");
	ini.SerGet(false, prefs->queueColumnOrder,
		ELEMENT_COUNT(prefs->queueColumnOrder), "QueueColumnOrder");
	ini.SerGet(false, prefs->searchColumnWidths,
		ELEMENT_COUNT(prefs->searchColumnWidths), "SearchColumnWidths");
	ini.SerGet(false, prefs->searchColumnHidden,
		ELEMENT_COUNT(prefs->searchColumnHidden), "SearchColumnHidden");
	ini.SerGet(false, prefs->searchColumnOrder,
		ELEMENT_COUNT(prefs->searchColumnOrder), "SearchColumnOrder");
	ini.SerGet(false, prefs->sharedColumnWidths,
		ELEMENT_COUNT(prefs->sharedColumnWidths), "SharedColumnWidths");
	ini.SerGet(false, prefs->sharedColumnHidden,
		ELEMENT_COUNT(prefs->sharedColumnHidden), "SharedColumnHidden");
	ini.SerGet(false, prefs->sharedColumnOrder,
		ELEMENT_COUNT(prefs->sharedColumnOrder), "SharedColumnOrder");
	ini.SerGet(false, prefs->serverColumnWidths,
		ELEMENT_COUNT(prefs->serverColumnWidths), "ServerColumnWidths");
	ini.SerGet(false, prefs->serverColumnHidden,
		ELEMENT_COUNT(prefs->serverColumnHidden), "ServerColumnHidden");
	ini.SerGet(false, prefs->serverColumnOrder,
		ELEMENT_COUNT(prefs->serverColumnOrder), "ServerColumnOrder");
	ini.SerGet(false, prefs->clientListColumnWidths,
		ELEMENT_COUNT(prefs->clientListColumnWidths), "ClientListColumnWidths");
	ini.SerGet(false, prefs->clientListColumnHidden,
		ELEMENT_COUNT(prefs->clientListColumnHidden), "ClientListColumnHidden");
	ini.SerGet(false, prefs->clientListColumnOrder,
		ELEMENT_COUNT(prefs->clientListColumnOrder), "ClientListColumnOrder");

	// Barry - Provide a mechanism for all tables to store/retrieve sort order
	ini.WriteInt("TableSortItemDownload", prefs->tableSortItemDownload);
	ini.WriteInt("TableSortItemUpload", prefs->tableSortItemUpload);
	ini.WriteInt("TableSortItemQueue", prefs->tableSortItemQueue);
	ini.WriteInt("TableSortItemSearch", prefs->tableSortItemSearch);
	ini.WriteInt("TableSortItemShared", prefs->tableSortItemShared);
	ini.WriteInt("TableSortItemServer", prefs->tableSortItemServer);
	ini.WriteInt("TableSortItemClientList", prefs->tableSortItemClientList);
	ini.WriteBool("TableSortAscendingDownload", prefs->tableSortAscendingDownload);
	ini.WriteBool("TableSortAscendingUpload", prefs->tableSortAscendingUpload);
	ini.WriteBool("TableSortAscendingQueue", prefs->tableSortAscendingQueue);
	ini.WriteBool("TableSortAscendingSearch", prefs->tableSortAscendingSearch);
	ini.WriteBool("TableSortAscendingShared", prefs->tableSortAscendingShared);
	ini.WriteBool("TableSortAscendingServer", prefs->tableSortAscendingServer);
	ini.WriteBool("TableSortAscendingClientList", prefs->tableSortAscendingClientList);

	// deadlake PROXYSUPPORT
	ini.WriteBool("ProxyEnablePassword",prefs->proxy.EnablePassword,"Proxy");
	ini.WriteBool("ProxyEnableProxy",prefs->proxy.UseProxy,"Proxy");
	ini.WriteString("ProxyName",prefs->proxy.name,"Proxy");
	ini.WriteString("ProxyPassword",prefs->proxy.password,"Proxy");
	ini.WriteString("ProxyUser",prefs->proxy.user,"Proxy");
	ini.WriteInt("ProxyPort",prefs->proxy.port,"Proxy");
	ini.WriteInt("ProxyType",prefs->proxy.type,"Proxy");
	ini.WriteBool("ConnectWithoutProxy",prefs->m_bIsASCWOP,"Proxy");
	ini.WriteBool("ShowErrors",prefs->m_bShowProxyErrors,"Proxy");

	CString buffer2;
	for (int i=0;i<15;i++) {
		buffer.Format("%I64u",GetStatsColor(i));
		buffer2.Format("StatColor%i",i);
		ini.WriteString(buffer2,buffer,"Statistics");
	}

	// -khaos--+++>
	/* Original stat saves from base code now obsolete (KHAOS)
	buffer.Format("%I64u",prefs->totalDownloadedBytes);
	ini.WriteString("TotalDownloadedBytes",buffer ,"Statistics");

	buffer.Format("%I64u",prefs->totalUploadedBytes);
	ini.WriteString("TotalUploadedBytes",buffer ,"Statistics");
	// End original stat saves from base code. */
	// <-----khaos--

	// Web Server
	ini.WriteString("Password", GetWSPass(), "WebServer");
	ini.WriteString("PasswordLow", GetWSLowPass());
	ini.WriteInt("Port", prefs->m_nWebPort);
	ini.WriteBool("Enabled", prefs->m_bWebEnabled);
	ini.WriteBool("UseGzip", prefs->m_bWebUseGzip);
	ini.WriteInt("PageRefreshTime", prefs->m_nWebPageRefresh);
	ini.WriteBool("UseLowRightsUser", prefs->m_bWebLowEnabled);
}

void CPreferences::SaveCats(){

	// Cats
	CString catinif,ixStr,buffer;
	catinif.Format("%sCategory.ini",configdir);
	remove(catinif);

	if (GetCatCount()>1) {
		CIni catini( catinif, "Category" );
		catini.WriteInt("Count",catMap.GetCount()-1,"General");
		for (int ix=1;ix<catMap.GetCount();ix++){
			ixStr.Format("Cat#%i",ix);
			catini.WriteString("Title",catMap.GetAt(ix)->title,ixStr);
			catini.WriteString("Incoming",catMap.GetAt(ix)->incomingpath,ixStr);
			catini.WriteString("Comment",catMap.GetAt(ix)->comment,ixStr);
			buffer.Format("%lu",catMap.GetAt(ix)->color,ixStr);
			catini.WriteString("Color",buffer,ixStr);
			catini.WriteInt("Priority",catMap.GetAt(ix)->prio,ixStr);
		}
	}
}

void CPreferences::ResetStatsColor(int index){
	switch(index) {
		case 0 : prefs->statcolors[0]=RGB(0,0,64);break;
		case 1 : prefs->statcolors[1]=RGB(192,192,255);break;
		case 2 : prefs->statcolors[2]=RGB(128, 255, 128);break;
		case 3 : prefs->statcolors[3]=RGB(0, 210, 0);break;
		case 4 : prefs->statcolors[4]=RGB(0, 128, 0);break;
		case 5 : prefs->statcolors[5]=RGB(255, 128, 128);break;
		case 6 : prefs->statcolors[6]=RGB(200, 0, 0);break;
		case 7 : prefs->statcolors[7]=RGB(140, 0, 0);break;
		case 8 : prefs->statcolors[8]=RGB(150, 150, 255);break;
		case 9 : prefs->statcolors[9]=RGB(255, 255, 128);break;
		case 10 : prefs->statcolors[10]=RGB(255, 255, 128);break;
		case 11 : prefs->statcolors[11]=RGB(192,   0, 192);break;
		case 12 : prefs->statcolors[12]=RGB(255, 255, 255);break;
		case 13 : prefs->statcolors[13]=RGB(0, 0, 255);break;

		default:break;
	}
}

void CPreferences::LoadPreferences(){
	char buffer[200];
	// -khaos--+++> Fix to stats being lost when version changes!
	int loadstatsFromOld = 0;
	// <-----khaos-

	//--- Quick hack to add version tag to preferences.ini-file and solve the issue with the FlatStatusBar tag...
	CString strFileName;
	strFileName.Format("%spreferences.ini", configdir);
	CIni* pIni = new CIni(strFileName, "eMule");

	CString strCurrVersion, strPrefsVersion;

	strCurrVersion = CURRENT_VERSION_LONG;
	strPrefsVersion = pIni->GetString("AppVersion");
	delete pIni;
	prefs->m_bFirstStart = false;

	CFileFind findFileName;

	if (strCurrVersion != strPrefsVersion){
		prefs->m_bFirstStart = true;
		if(findFileName.FindFile(strFileName)){
			CFile file;
			CFileFind findNewName;
			CString strNewName;
			strNewName.Format("%spreferences.ini.old", configdir);
	
			if (findNewName.FindFile(strNewName))
				file.Remove(strNewName);
	
			file.Rename(strFileName, strNewName);
			strFileName = strNewName;
			// -khaos--+++> Set this to 2 so that LoadStats will load 'em from ini.old
			loadstatsFromOld = 2;
			// <-----khaos-
		}
	}
	CIni ini(strFileName, "eMule");
	//--- end Ozon :)

	sprintf(prefs->nick,"%s",ini.GetString("Nick","http://emule-project.net"));
	
	sprintf(buffer,"%sIncoming",appdir);
	sprintf(prefs->incomingdir,"%s",ini.GetString("IncomingDir",buffer ));
	MakeFoldername(prefs->incomingdir);

	sprintf(buffer,"%sTemp",appdir);
	sprintf(prefs->tempdir,"%s",ini.GetString("TempDir",buffer));
	MakeFoldername(prefs->tempdir);

	prefs->maxupload=ini.GetInt("MaxUpload",UNLIMITED);
	prefs->maxdownload=ini.GetInt("MaxDownload",UNLIMITED);
	prefs->maxconnections=ini.GetInt("MaxConnections",GetRecommendedMaxConnections());
	prefs->deadserver=ini.GetInt("RemoveDeadServer",2);
	prefs->port=ini.GetInt("Port",4662);
	prefs->udpport=ini.GetInt("UDPPort",prefs->port+10);
	prefs->maxsourceperfile=ini.GetInt("MaxSourcesPerFile",400 );
	prefs->languageID=ini.GetWORD("Language",0);
	prefs->m_iSeeShares=ini.GetInt("SeeShare",2);
	prefs->m_iToolDelayTime=ini.GetInt("ToolTipDelay",1);
	prefs->trafficOMeterInterval=ini.GetInt("StatGraphsInterval",3);
	prefs->statsInterval=ini.GetInt("statsInterval",5);
	prefs->maxGraphDownloadRate=ini.GetInt("DownloadCapacity",96);
	prefs->maxGraphUploadRate=ini.GetInt("UploadCapacity",16);
	prefs->deadserverretries=ini.GetInt("DeadServerRetry",1);
	prefs->splitterbarPosition=ini.GetInt("SplitterbarPosition",75);
	prefs->statsMax=ini.GetInt("VariousStatisticsMaxValue",100);
	prefs->statsAverageMinutes=ini.GetInt("StatsAverageMinutes",5);
	prefs->MaxConperFive=ini.GetInt("MaxConnectionsPerFiveSeconds",GetDefaultMaxConperFive());

	prefs->reconnect=ini.GetBool("Reconnect",true);
	prefs->scorsystem=ini.GetBool("Scoresystem",true);
	prefs->ICH=ini.GetBool("ICH",true);
	prefs->autoserverlist=ini.GetBool("Serverlist",false);

	prefs->updatenotify=ini.GetBool("UpdateNotify",false);
	prefs->mintotray=ini.GetBool("MinToTray",false);
	prefs->addserversfromserver=ini.GetBool("AddServersFromServer",true);
	prefs->addserversfromclient=ini.GetBool("AddServersFromClient",true);
	prefs->splashscreen=ini.GetBool("Splashscreen",true);
	prefs->bringtoforeground=ini.GetBool("BringToFront",true);
	prefs->transferDoubleclick=ini.GetBool("TransferDoubleClick",true);
	prefs->beepOnError=ini.GetBool("BeepOnError",true);
	prefs->confirmExit=ini.GetBool("ConfirmExit",false);
	prefs->filterBadIP=ini.GetBool("FilterBadIPs",true);
	prefs->autoconnect=ini.GetBool("Autoconnect",false);
	prefs->showRatesInTitle=ini.GetBool("ShowRatesOnTitle",false);

	prefs->onlineSig=ini.GetBool("OnlineSignature",false);
	prefs->startMinimized=ini.GetBool("StartupMinimized",false);
	prefs->safeServerConnect =ini.GetBool("SafeServerConnect",false);

	prefs->filterserverbyip=ini.GetBool("FilterServersByIP",false);
	prefs->filterlevel=ini.GetInt("FilterLevel",127);

	// Barry - New properties...
	prefs->autoconnectstaticonly = ini.GetBool("AutoConnectStaticOnly",false); 
	prefs->autotakeed2klinks = ini.GetBool("AutoTakeED2KLinks",true); 
	prefs->addnewfilespaused = ini.GetBool("AddNewFilesPaused",false); 
	prefs->depth3D = ini.GetInt("3DDepth", 0);

	// as temporarial converter for previous versions
	if (strPrefsVersion < "0.25a") // before 0.25a
		if (ini.GetBool("FlatStatusBar",false))
			prefs->depth3D = 0;
		else 
			prefs->depth3D = 5;

    prefs->useDownloadNotifier=ini.GetBool("NotifyOnDownload",false);	// Added by enkeyDEV
    prefs->useChatNotifier=ini.GetBool("NotifyOnChat",false);
    prefs->useLogNotifier=ini.GetBool("NotifyOnLog",false);
    prefs->useSoundInNotifier=ini.GetBool("NotifierUseSound",false);
	prefs->notifierPopsEveryChatMsg=ini.GetBool("NotifierPopEveryChatMessage",false);
	prefs->notifierImportantError=ini.GetBool("NotifyOnImportantError",false);
	prefs->notifierNewVersion=ini.GetBool("NotifierPopNewVersion",false);
	sprintf(prefs->notifierSoundFilePath,"%s",ini.GetString("NotifierSoundPath",""));
	sprintf(prefs->notifierConfiguration,"%s",ini.GetString("NotifierConfiguration","")); // Added by enkeyDEV
	sprintf(prefs->datetimeformat,"%s",ini.GetString("DateTimeFormat","%A, %x, %X"));
	sprintf(prefs->datetimeformat4log,"%s",ini.GetString("DateTimeFormat4Log","%c"));

	sprintf(prefs->m_sircserver,"%s",ini.GetString("DefaultIRCServer","irc.emule-project.net"));
	sprintf(prefs->m_sircnick,"%s",ini.GetString("IRCNick","eMule"));
	prefs->m_bircaddtimestamp=ini.GetBool("IRCAddTimestamp",true);
	sprintf(prefs->m_sircchannamefilter,"%s",ini.GetString("IRCFilterName", "" ));
	prefs->m_bircusechanfilter=ini.GetBool("IRCUseFilter", false);
	prefs->m_iircchanneluserfilter=ini.GetInt("IRCFilterUser", 0);
	sprintf(prefs->m_sircperformstring,"%s",ini.GetString("IRCPerformString", "/join #emule" ));
	prefs->m_bircuseperform=ini.GetBool("IRCUsePerform", false);
	prefs->m_birclistonconnect=ini.GetBool("IRCListOnConnect", true);
	prefs->m_bircacceptlinks=ini.GetBool("IRCAcceptLinks", false);
	prefs->m_bircignoreinfomessage=ini.GetBool("IRCIgnoreInfoMessage", false);
	prefs->m_bircignoreemuleprotoinfomessage=ini.GetBool("IRCIgnoreEmuleProtoInfoMessage", true);
	prefs->smartidcheck=ini.GetBool("SmartIdCheck",true);
	prefs->m_bVerbose=ini.GetBool("Verbose",false);
	prefs->m_bDebugSourceExchange=ini.GetBool("DebugSourceExchange",false);
	prefs->m_bpreviewprio=ini.GetBool("PreviewPrio",false);
	prefs->m_bupdatequeuelist=ini.GetBool("UpdateQueueListPref",false);
	prefs->m_bmanualhighprio=ini.GetBool("ManualHighPrio",false);
	prefs->m_btransferfullchunks=ini.GetBool("FullChunkTransfers",true);
	prefs->m_bstartnextfile=ini.GetBool("StartNextFile",false);
	prefs->m_bshowoverhead=ini.GetBool("ShowOverhead",false);
	prefs->moviePreviewBackup=ini.GetBool("VideoPreviewBackupped",true);
	prefs->m_iFileBufferSize=ini.GetInt("FileBufferSizePref",16);
	prefs->m_iQueueSize=ini.GetInt("QueueSizePref",50);
	prefs->versioncheckdays=ini.GetInt("Check4NewVersionDelay",5);
	prefs->m_bDAP=ini.GetBool("DAPPref",true);
	prefs->m_bUAP=ini.GetBool("UAPPref",true);
	prefs->indicateratings=ini.GetBool("IndicateRatings",true);
	prefs->allcatType=ini.GetInt("AllcatType",0);
	prefs->watchclipboard=ini.GetBool("WatchClipboard4ED2kFilelinks",false);
	prefs->log2disk=ini.GetBool("SaveLogToDisk",false);
	prefs->debug2disk=ini.GetBool("SaveDebugToDisk",false);
	prefs->iMaxLogMessages = ini.GetInt("MaxLogMessages",1000);
	prefs->showCatTabInfos=ini.GetBool("ShowInfoOnCatTabs",false);
	prefs->resumeSameCat=ini.GetBool("ResumeNextFromSameCat",false);
	prefs->dontRecreateGraphs =ini.GetBool("DontRecreateStatGraphsOnResize",false);

	prefs->versioncheckLastAutomatic=ini.GetInt("VersionCheckLastAutomatic",0);
	prefs->m_bDisableKnownClientList=ini.GetInt("DisableKnownClientList",false);
	prefs->m_bDisableQueueList=ini.GetInt("DisableQueueList",false);
	prefs->m_bCreditSystem=ini.GetInt("UseCreditSystem",true);
	prefs->scheduler=ini.GetBool("EnableScheduler",false);
	prefs->msgonlyfriends=ini.GetBool("MessagesFromFriendsOnly",false);
	prefs->msgsecure=ini.GetBool("MessageFromValidSourcesOnly",true);
	prefs->autofilenamecleanup=ini.GetBool("AutoFilenameCleanup",false);

	prefs->maxmsgsessions=ini.GetInt("MaxMessageSessions",50);

	sprintf(prefs->TxtEditor,"%s",ini.GetString("TxtEditor","notepad.exe"));
	sprintf(prefs->VideoPlayer,"%s",ini.GetString("VideoPlayer",""));
	
	sprintf(prefs->m_sTemplateFile,"%s",ini.GetString("WebTemplateFile","eMule.tmpl"));

	sprintf(prefs->messageFilter,"%s",ini.GetString("MessageFilter","Your client has an infinite queue"));
	sprintf(prefs->commentFilter,"%s",ini.GetString("CommentFilter","http://|www."));
	sprintf(prefs->filenameCleanups,"%s",ini.GetString("FilenameCleanups","http|www.|.com|shared|powered|sponsored|sharelive|filedonkey|saugstube|eselfilme|eseldownloads|emulemovies|spanishare|eselpsychos.de|saughilfe.de|goldesel.6x.to|freedivx.org|elitedivx|deviance|-ftv|ftv|-flt|flt"));
	
	//if (prefs->maxGraphDownloadRate<prefs->maxdownload) prefs->maxdownload=UNLIMITED;
	//if (prefs->maxGraphUploadRate<prefs->maxupload) prefs->maxupload=UNLIMITED;

	ini.SerGet(true, prefs->downloadColumnWidths,
		ELEMENT_COUNT(prefs->downloadColumnWidths), "DownloadColumnWidths");
	ini.SerGet(true, prefs->downloadColumnHidden,
		ELEMENT_COUNT(prefs->downloadColumnHidden), "DownloadColumnHidden");
	ini.SerGet(true, prefs->downloadColumnOrder,
		ELEMENT_COUNT(prefs->downloadColumnOrder), "DownloadColumnOrder");
	ini.SerGet(true, prefs->uploadColumnWidths,
		ELEMENT_COUNT(prefs->uploadColumnWidths), "UploadColumnWidths");
	ini.SerGet(true, prefs->uploadColumnHidden,
		ELEMENT_COUNT(prefs->uploadColumnHidden), "UploadColumnHidden");
	ini.SerGet(true, prefs->uploadColumnOrder,
		ELEMENT_COUNT(prefs->uploadColumnOrder), "UploadColumnOrder");
	ini.SerGet(true, prefs->queueColumnWidths,
		ELEMENT_COUNT(prefs->queueColumnWidths), "QueueColumnWidths");
	ini.SerGet(true, prefs->queueColumnHidden,
		ELEMENT_COUNT(prefs->queueColumnHidden), "QueueColumnHidden");
	ini.SerGet(true, prefs->queueColumnOrder,
		ELEMENT_COUNT(prefs->queueColumnOrder), "QueueColumnOrder");
	ini.SerGet(true, prefs->searchColumnWidths,
		ELEMENT_COUNT(prefs->searchColumnWidths), "SearchColumnWidths");
	ini.SerGet(true, prefs->searchColumnHidden,
		ELEMENT_COUNT(prefs->searchColumnHidden), "SearchColumnHidden");
	ini.SerGet(true, prefs->searchColumnOrder,
		ELEMENT_COUNT(prefs->searchColumnOrder), "SearchColumnOrder");
	ini.SerGet(true, prefs->sharedColumnWidths,
		ELEMENT_COUNT(prefs->sharedColumnWidths), "SharedColumnWidths");
	ini.SerGet(true, prefs->sharedColumnHidden,
		ELEMENT_COUNT(prefs->sharedColumnHidden), "SharedColumnHidden");
	ini.SerGet(true, prefs->sharedColumnOrder,
		ELEMENT_COUNT(prefs->sharedColumnOrder), "SharedColumnOrder");
	ini.SerGet(true, prefs->serverColumnWidths,
		ELEMENT_COUNT(prefs->serverColumnWidths), "ServerColumnWidths");
	ini.SerGet(true, prefs->serverColumnHidden,
		ELEMENT_COUNT(prefs->serverColumnHidden), "ServerColumnHidden");
	ini.SerGet(true, prefs->serverColumnOrder,
		ELEMENT_COUNT(prefs->serverColumnOrder), "ServerColumnOrder");
	ini.SerGet(true, prefs->clientListColumnWidths,
		ELEMENT_COUNT(prefs->clientListColumnWidths), "ClientListColumnWidths");
	ini.SerGet(true, prefs->clientListColumnHidden,
		ELEMENT_COUNT(prefs->clientListColumnHidden), "ClientListColumnHidden");
	ini.SerGet(true, prefs->clientListColumnOrder,
		ELEMENT_COUNT(prefs->clientListColumnOrder), "ClientListColumnOrder");

	// Barry - Provide a mechanism for all tables to store/retrieve sort order
	prefs->tableSortItemDownload = ini.GetInt("TableSortItemDownload", 0);
	prefs->tableSortItemUpload = ini.GetInt("TableSortItemUpload", 0);
	prefs->tableSortItemQueue = ini.GetInt("TableSortItemQueue", 0);
	prefs->tableSortItemSearch = ini.GetInt("TableSortItemSearch", 0);
	prefs->tableSortItemShared = ini.GetInt("TableSortItemShared", 0);
	prefs->tableSortItemServer = ini.GetInt("TableSortItemServer", 0);
	prefs->tableSortItemClientList = ini.GetInt("TableSortItemClientList", 0);
	prefs->tableSortAscendingDownload = ini.GetBool("TableSortAscendingDownload", true);
	prefs->tableSortAscendingUpload = ini.GetBool("TableSortAscendingUpload", true);
	prefs->tableSortAscendingQueue = ini.GetBool("TableSortAscendingQueue", true);
	prefs->tableSortAscendingSearch = ini.GetBool("TableSortAscendingSearch", true);
	prefs->tableSortAscendingShared = ini.GetBool("TableSortAscendingShared", true);
	prefs->tableSortAscendingServer = ini.GetBool("TableSortAscendingServer", true);
	prefs->tableSortAscendingClientList = ini.GetBool("TableSortAscendingClientList", true);

	if (prefs->statsAverageMinutes<1) prefs->statsAverageMinutes=5;

	// deadlake PROXYSUPPORT
	prefs->proxy.EnablePassword = ini.GetBool("ProxyEnablePassword",false,"Proxy");
	prefs->proxy.UseProxy = ini.GetBool("ProxyEnableProxy",false,"Proxy");
	sprintf(buffer,"");
	sprintf(prefs->proxy.name,"%s",ini.GetString("ProxyName",buffer,"Proxy"));
	sprintf(prefs->proxy.password,"%s",ini.GetString("ProxyPassword",buffer,"Proxy"));
	sprintf(prefs->proxy.user,"%s",ini.GetString("ProxyUser",buffer,"Proxy"));
	prefs->proxy.port = ini.GetInt("ProxyPort",1080,"Proxy");
	prefs->proxy.type = ini.GetInt("ProxyType",PROXYTYPE_NOPROXY,"Proxy");
	prefs->m_bIsASCWOP = ini.GetBool("ConnectWithoutProxy",false,"Proxy");
	prefs->m_bShowProxyErrors = ini.GetBool("ShowErrors",false,"Proxy");

	CString buffer2;
	for (int i=0;i<15;i++) {
		buffer2.Format("StatColor%i",i);
		sprintf(buffer,ini.GetString(buffer2,"0","Statistics"));
		prefs->statcolors[i]=_atoi64(buffer);
		if (prefs->statcolors[i]==0) ResetStatsColor(i);
	}

	// -khaos--+++> Load Stats
	// I changed this to a seperate function because it is now also used
	// to load the stats backup and to load stats from preferences.ini.old.
	LoadStats(loadstatsFromOld);

	/*Original stat loads from base code, now obsolete.  -khaos-
	sprintf(buffer,ini.GetString("TotalDownloadedBytes",0,"Statistics"));
	prefs->totalDownloadedBytes=_atoi64(buffer);

	sprintf(buffer,ini.GetString("TotalUploadedBytes",0,"Statistics"));
	prefs->totalUploadedBytes=_atoi64(buffer);*/

	// <-----khaos-

	// Web Server
	sprintf(prefs->m_sWebPassword,"%s",ini.GetString("Password", "","WebServer"));
	sprintf(prefs->m_sWebLowPassword,"%s",ini.GetString("PasswordLow", ""));
	prefs->m_nWebPort=ini.GetInt("Port", 4711);
	prefs->m_bWebEnabled=ini.GetBool("Enabled", false);
	prefs->m_bWebUseGzip=ini.GetBool("UseGzip", true);
	prefs->m_bWebLowEnabled=ini.GetBool("UseLowRightsUser", false);
	prefs->m_nWebPageRefresh=ini.GetInt("PageRefreshTime", 120);

	prefs->dontcompressavi=ini.GetBool("DontCompressAvi",false);

	LoadCats();
	if (GetCatCount()==1) SetAllcatType(0);

	SetLanguage();
}

void CPreferences::LoadCats() {
	CString ixStr,catinif,cat_a,cat_b,cat_c;
	char buffer[100];

	catinif.Format("%sCategory.ini",configdir);

	// default cat
	Category_Struct* newcat=new Category_Struct;
	sprintf(newcat->title,"");
	sprintf(newcat->incomingpath,"");
	sprintf(newcat->comment,"");
	newcat->prio=0;
	newcat->color=0;
	AddCat(newcat);

	if (!PathFileExists(catinif)) return;

	CIni catini( catinif, "Category" );
	int max=catini.GetInt("Count",0,"General");

	for (int ix=1;ix<=max;ix++){
		ixStr.Format("Cat#%i",ix);

		Category_Struct* newcat=new Category_Struct;
		sprintf(newcat->title,catini.GetString("Title","",ixStr));
		sprintf(newcat->incomingpath,catini.GetString("Incoming","",ixStr));
		MakeFoldername(newcat->incomingpath);
		sprintf(newcat->comment,catini.GetString("Comment","",ixStr));
		newcat->prio =catini.GetInt("Priority",0,ixStr);
		sprintf(buffer,catini.GetString("Color","0",ixStr));
		newcat->color=_atoi64(buffer);

		AddCat(newcat);
		if (!PathFileExists(newcat->incomingpath)) ::CreateDirectory(newcat->incomingpath,0);
	}
}

WORD CPreferences::GetWindowsVersion(){
	static bWinVerAlreadyDetected = false;
	if(!bWinVerAlreadyDetected)
	{	
		bWinVerAlreadyDetected = true;
		m_wWinVer = DetectWinVersion();	
	}	
	return m_wWinVer;
}

uint16 CPreferences::GetDefaultMaxConperFive(){
	switch (GetWindowsVersion()){
		case _WINVER_98_:
			return 5;
		case _WINVER_95_:	
		case _WINVER_ME_:
			return MAXCON5WIN9X;
		case _WINVER_2K_:
		case _WINVER_XP_:
			return MAXCONPER5SEC;
		default:
			return MAXCONPER5SEC;
	}
}

// Barry - Provide a mechanism for all tables to store/retrieve sort order
int CPreferences::GetColumnSortItem(Table t) const
{
	switch(t) 
	{
		case tableDownload:
			return prefs->tableSortItemDownload;
		case tableUpload:
			return prefs->tableSortItemUpload;
		case tableQueue:
			return prefs->tableSortItemQueue;
		case tableSearch:
			return prefs->tableSortItemSearch;
		case tableShared:
			return prefs->tableSortItemShared;
		case tableServer:
			return prefs->tableSortItemServer;
		case tableClientList:
			return prefs->tableSortItemClientList;
	}
	return 0;
}

// Barry - Provide a mechanism for all tables to store/retrieve sort order
bool CPreferences::GetColumnSortAscending(Table t) const
{
	switch(t) 
	{
		case tableDownload:
			return prefs->tableSortAscendingDownload;
		case tableUpload:
			return prefs->tableSortAscendingUpload;
		case tableQueue:
			return prefs->tableSortAscendingQueue;
		case tableSearch:
			return prefs->tableSortAscendingSearch;
		case tableShared:
			return prefs->tableSortAscendingShared;
		case tableServer:
			return prefs->tableSortAscendingServer;
		case tableClientList:
			return prefs->tableSortAscendingClientList;
	}
	return true;
}

// Barry - Provide a mechanism for all tables to store/retrieve sort order
void CPreferences::SetColumnSortItem(Table t, int sortItem)
{
	switch(t) 
	{
		case tableDownload:
			prefs->tableSortItemDownload = sortItem;
			break;
		case tableUpload:
			prefs->tableSortItemUpload = sortItem;
			break;
		case tableQueue:
			prefs->tableSortItemQueue = sortItem;
			break;
		case tableSearch:
			prefs->tableSortItemSearch = sortItem;
			break;
		case tableShared:
			prefs->tableSortItemShared = sortItem;
			break;
		case tableServer:
			prefs->tableSortItemServer = sortItem;
			break;
		case tableClientList:
			prefs->tableSortItemClientList = sortItem;
			break;
	}
}

// Barry - Provide a mechanism for all tables to store/retrieve sort order
void CPreferences::SetColumnSortAscending(Table t, bool sortAscending)
{
	switch(t) 
	{
		case tableDownload:
			prefs->tableSortAscendingDownload = sortAscending;
			break;
		case tableUpload:
			prefs->tableSortAscendingUpload = sortAscending;
			break;
		case tableQueue:
			prefs->tableSortAscendingQueue = sortAscending;
			break;
		case tableSearch:
			prefs->tableSortAscendingSearch = sortAscending;
			break;
		case tableShared:
			prefs->tableSortAscendingShared = sortAscending;
			break;
		case tableServer:
			prefs->tableSortAscendingServer = sortAscending;
			break;
		case tableClientList:
			prefs->tableSortAscendingClientList = sortAscending;
			break;
	}
}

void CPreferences::SetLanguage() {
	switch(prefs->languageID) {
		// read from ini and supported by the program?
		case MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT):setlocale( LC_ALL, "english");break;
		case MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT):setlocale( LC_ALL, "german");break;
		case MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT):setlocale( LC_ALL, "french");break;
		case MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT):setlocale( LC_ALL, "danish");break;
		case MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH):setlocale( LC_ALL, "spanish");break;
		case MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT):setlocale( LC_ALL, "dutch");break;
		case MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT):setlocale( LC_ALL, "russian");break;
		case MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT):setlocale( LC_ALL, "");break;
		case MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED):setlocale( LC_ALL, "chs");break;
		case MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_TRADITIONAL):setlocale( LC_ALL, "cht");break;
		case MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT):setlocale( LC_ALL, "");break;
		case MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT):setlocale( LC_ALL, "polish");break;
		case MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT):setlocale( LC_ALL, "korean");break;
		case MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN):setlocale( LC_ALL, "ptb");break;
		case MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE):setlocale( LC_ALL, "ptg");break;
		case MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT):setlocale( LC_ALL, "swedish");break;
		case MAKELANGID(LANG_NORWEGIAN,SUBLANG_NORWEGIAN_BOKMAL):setlocale( LC_ALL, "norwegian");break;
		case MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT):setlocale( LC_ALL, "finnish");break;
		case MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT):setlocale( LC_ALL, "italian");break;
		case MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT):setlocale( LC_ALL, "hun");break;
		case MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT):setlocale( LC_ALL, "");break;
		case MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT):setlocale( LC_ALL, "greek");break;
		case MAKELANGID(LANG_LATVIAN ,SUBLANG_DEFAULT):setlocale( LC_ALL, "");break;
		case MAKELANGID(LANG_TURKISH ,SUBLANG_DEFAULT):setlocale( LC_ALL, "turkish");break;
		case MAKELANGID(LANG_HUNGARIAN ,SUBLANG_DEFAULT):setlocale( LC_ALL, "hungarian");break;
		case MAKELANGID(LANG_ESTONIAN ,SUBLANG_DEFAULT):setlocale( LC_ALL, "");break;
		case MAKELANGID(LANG_ARABIC ,SUBLANG_ARABIC_UAE):setlocale( LC_ALL, "");break;
		case MAKELANGID(LANG_GALICIAN ,SUBLANG_DEFAULT):setlocale( LC_ALL, "");break;
		default:{	// no preset language available - get system language and check if its supported (cases).
			uint8 nLocalLang = ::GetThreadLocale();
			uint8 langp=PRIMARYLANGID(::GetThreadLocale());
			uint8 langs=SUBLANGID(::GetThreadLocale());

            CString strLng1 = GetResString(IDS_MB_LANGUAGEINFO,MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT));
			CString strLng2 = "";
			switch(nLocalLang) {
				case	LANG_GREEK:
				case 	LANG_GERMAN:
				case 	LANG_FRENCH:
				case 	LANG_DANISH:
				case 	LANG_SPANISH:
				case 	LANG_DUTCH:
				case 	LANG_RUSSIAN:
				case 	LANG_SLOVENIAN:
				case 	LANG_CHINESE:
				case 	LANG_LITHUANIAN:
				case 	LANG_NORWEGIAN:
				case 	LANG_POLISH:
				case 	LANG_KOREAN:
				case 	LANG_PORTUGUESE:
				case 	LANG_SWEDISH:
				case	LANG_FINNISH:
				case	LANG_ITALIAN:
				case	LANG_BULGARIAN:
				case	LANG_CATALAN:
				case	LANG_LATVIAN:
				case	LANG_TURKISH:
				case	LANG_HUNGARIAN:
				case	LANG_ESTONIAN:
				case	LANG_ARABIC:
				case	LANG_GALICIAN:
				{
					prefs->languageID =  MAKELANGID(langp,langs);
					SetThreadLocale(prefs->languageID);
					if (nLocalLang != LANG_ENGLISH) strLng2=GetResString(IDS_MB_LANGUAGEINFO,prefs->languageID);
					break;
				}
				default:	// not supported language -> use english
					prefs->languageID = MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT);
					SetThreadLocale(prefs->languageID);
			}

			CString strMessage = strLng2 + CString("\n\n") + strLng1;
			AfxMessageBox(strMessage,MB_ICONASTERISK);
		}
	}
	SetThreadLocale(prefs->languageID);

	// if loading a string fails, set language to English
	if (GetResString(IDS_MB_LANGUAGEINFO,prefs->languageID).GetLength()==0) {
		prefs->languageID = MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT);
		SetThreadLocale(prefs->languageID);
	}
}

void CPreferences::RemoveCat(int index)	{
	if (index>=0 && index<catMap.GetCount()) { 
		Category_Struct* delcat;
		delcat=catMap.GetAt(index); 
		catMap.RemoveAt(index); 
		delete delcat;
	}
}

bool CPreferences::MoveCat(UINT from, UINT to){
	if (from>=(UINT)catMap.GetCount() || to >=(UINT)catMap.GetCount()+1 || from==to) return false;

	Category_Struct* tomove;

	tomove=catMap.GetAt(from);

	if (from < to) {
		catMap.RemoveAt(from);
		catMap.InsertAt(to-1,tomove);
	} else {
		catMap.InsertAt(to,tomove);
		catMap.RemoveAt(from+1);
	}
	
	SaveCats();

	return true;
}
