//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 "clientcredits.h"
#include "opcodes.h"
#include "emule.h"
#include "safefile.h"
#include <math.h>

CClientCredits::CClientCredits(Credit_Struct* in_credits){
	credits = in_credits;
}

CClientCredits::CClientCredits(uchar* key){
	credits = new Credit_Struct;
	memset(credits,0,sizeof(Credit_Struct));
	memcpy(credits->key,key,16);
}

CClientCredits::~CClientCredits(){
	delete credits;
}

float CClientCredits::GetScoreRatio(){
	if (credits->downloaded < 1000000)
		return 1;
	float result = 0;
	if (!credits->uploaded)
		result = 10;
	else
		result = (float)(credits->downloaded*2)/credits->uploaded;
	float result2 = 0;
	result2 = (float)(credits->downloaded/1048576);
	result2 += 2;
	result2 = (double)sqrt((double)result2);

	if (result > result2)
		result = result2;

	if (result < 1)
		return 1;
	else if (result > 10)
		return 10;
	return result;
}


CClientCreditsList::CClientCreditsList(CPreferences* in_prefs){
	app_prefs = in_prefs;
	lastsaved = ::GetTickCount();
	LoadList();
}

CClientCreditsList::~CClientCreditsList(){
	SaveList();
	CClientCredits* cur_credit;
	CCKey tmpkey(0);
	POSITION pos = client_map.GetStartPosition();
	while (pos){
		client_map.GetNextAssoc(pos,tmpkey,cur_credit);
		delete cur_credit;
	}
	client_map.RemoveAll();
}

void CClientCreditsList::LoadList(){
	CSafeFile file;
	try{
		CString name = app_prefs->GetAppDir() + CString("clients.met");
		if (!file.Open(name,CFile::modeRead)){
			theApp.emuledlg->AddLogLine(false,GetResString(IDS_ERR_LOADCREDITFILE));
			return;
		}
		uint8 version;
		file.Read(&version,1);
		if (version != CREDITFILE_VERSION){
			theApp.emuledlg->AddLogLine(false,GetResString(IDS_ERR_CREDITFILEOLD));
			file.Close();
			return;
		}
		uint32 count;
		file.Read(&count,4);
		client_map.InitHashTable(count+5000);
		for (uint32 i = 0; i != count;i++){
			Credit_Struct* newcstruct = new Credit_Struct;
			memset(newcstruct,0,sizeof(Credit_Struct));
			file.Read(newcstruct,sizeof(Credit_Struct));
			CClientCredits* newcredits = new CClientCredits(newcstruct);
			client_map.SetAt(CCKey(newcredits->GetKey()),newcredits);
		}
		file.Close();
		theApp.emuledlg->AddLogLine(false,GetResString(IDS_CREDITFILELOADED),count);
	}
	catch(CFileException* error){
		OUTPUT_DEBUG_TRACE();
		if (error->m_cause == CFileException::endOfFile)
			theApp.emuledlg->AddLogLine(true,GetResString(IDS_CREDITFILECORRUPT));
		else{
			char buffer[150];
			error->GetErrorMessage(buffer,150);
			theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_CREDITFILEREAD),buffer);
		}
		error->Delete();
	}
}

void CClientCreditsList::SaveList(){
	CString name = app_prefs->GetAppDir() + CString("clients.met");
	CFile diskfile;
	CMemFile file((16 * 1024)); // Modified by Tarod (fix)
	if (!diskfile.Open(name,CFile::modeWrite|CFile::modeCreate)){
		theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_FAILED_CREDITSAVE));
		return;
	}
	uint8 version = CREDITFILE_VERSION;
	file.Write(&version,1);
	uint32 count = client_map.GetCount();
	file.Write(&count,4);
	CClientCredits* cur_credit;
	CCKey tempkey(0);
	POSITION pos = client_map.GetStartPosition();
	count = 0;
	while (pos){
		client_map.GetNextAssoc(pos,tempkey,cur_credit);
		if (cur_credit->GetDataStruct()->uploaded + cur_credit->GetDataStruct()->downloaded > 0){ 
          file.Write(cur_credit->GetDataStruct(),sizeof(Credit_Struct)); 
          count++; 
		}
	}
    file.Seek(1,FILE_BEGIN); 
    file.Write(&count,4); 

	// Modified by Tarod (fix)
	int size = count * sizeof(Credit_Struct) + sizeof(count) + sizeof(version) ;

    BYTE* tmp = file.Detach(); 
    diskfile.Write(tmp,size); 
    free(tmp); 
    diskfile.Close(); 
	lastsaved = ::GetTickCount();
}

CClientCredits* CClientCreditsList::GetCredit(uchar* key){
	CClientCredits* result;
	CCKey tkey(key);
	if (!client_map.Lookup(tkey,result)){
		result = new CClientCredits(key);
		client_map.SetAt(CCKey(result->GetKey()),result);
	}
	result->SetLastSeen();
	return result;
}

void CClientCreditsList::Process(){
	if (::GetTickCount() - lastsaved > 70000)
		SaveList();
}


