//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 "uploadqueue.h"
#include "packets.h"
#include "emule.h"
#include "knownfile.h"
#include "listensocket.h"
#include "ini2.h"
#include "math.h"

static uint32 counter, sec,statsave;
static uint32 igraph, istats;
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg,UINT_PTR idEvent,DWORD dwTime);

//TODO rewrite the whole networkcode, use overlapped sockets

CUploadQueue::CUploadQueue(CPreferences* in_prefs){
	app_prefs = in_prefs;
	h_timer = SetTimer(0,141,100,TimerProc);
	if (!h_timer)
		theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_ERR_TIMERCREATEFAILED));
	estadatarate = 2000;
	datarate = 0;
	dataratems = 0;
	datarateave = 0;
	bannedcount = 0;
	counter=0;

	PrefetchStatus=0; //Rectencle
	lasttimechecked = ::GetTickCount() ; //Tarod (Added by Rectencle)

	bDataRateMaxed = false; // Added by Tarod [LoneStar]

	successfullupcount = 0;
	failedupcount = 0;
	totaluploadtime = 0;
	m_nUpDataRateMSOverhead = 0;
	m_nUpDatarateOverhead = 0;
	statsave=0;
	for (int i = 0;i != 400;i++)
		avarage_dr_list.AddHead((uint32)0);

}

void CUploadQueue::AddUpNextClient(CUpDownClient* directadd){
	POSITION toadd = 0;
	uint32	bestscore = 0;
	CUpDownClient* newclient;
	// select next client or use given client
	if (!directadd){
		POSITION pos1, pos2;
		for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;){
			waitinglist.GetNext(pos1);
			CUpDownClient* cur_client =	waitinglist.GetAt(pos2);
			// clear dead clients
			ASSERT ( cur_client->GetLastUpRequest() );
			if ((::GetTickCount() - cur_client->GetLastUpRequest() > MAX_PURGEQUEUETIME) || !theApp.sharedfiles->GetFileByID(cur_client->reqfileid) ){
				RemoveFromWaitingQueue(pos2,true);	
				if (!cur_client->socket)
					cur_client->Disconnected();
			}
			// finished clearing
			else if ( (cur_client->GetScore(true) > bestscore) && (!cur_client->IsBanned()) 
				&& (!cur_client->HasLowID() || (cur_client->socket && cur_client->socket->IsConnected()) ) ){
				bestscore = cur_client->GetScore(true);
				toadd = pos2;
			}
		}
		if (!toadd)
			return;
		newclient = waitinglist.GetAt(toadd);
		RemoveFromWaitingQueue(toadd, true);
		theApp.emuledlg->transferwnd.ShowQueueCount(waitinglist.GetCount());
	}
	else
		newclient = directadd;

	if (IsDownloading(newclient)){
		return;
	}
	// tell the client that we are now ready to upload
	if (!newclient->socket || !newclient->socket->IsConnected()){
		newclient->SetUploadState(US_CONNECTING);
		newclient->TryToConnect(true);
	}
	else{
		Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
		theApp.uploadqueue->AddUpDataRateMSOverhead(packet->size, 160);
		newclient->socket->SendPacket(packet,true);
		newclient->SetUploadState(US_UPLOADING);
	}
	newclient->SetUpStartTime();
/*	if (theApp.glob_prefs->TransferFullChunks())
		newclient->ClearSessionUp(); 	// VQB UL Session Clear*/
	
	newclient->ResetCompressionGain(); // Add show compression

	newclient->ClearSessionUp(); // VQB UL Session Clear
	newclient->ClearPrefetchedAlready(); // Rectencle Connection-Prefetching

	uploadinglist.AddTail(newclient);
	
	// statistic
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)newclient->reqfileid);
	if (reqfile)
		reqfile->statistic.AddAccepted();
	
	theApp.emuledlg->transferwnd.uploadlistctrl.AddClient(newclient);

}

/*void CUploadQueue::Process(){
	avarage_dr_list.RemoveHead();
	avarage_dr_list.AddTail(dataratems);
	datarate = 0;
	for (POSITION pos = avarage_dr_list.GetHeadPosition();pos != 0;avarage_dr_list.GetNext(pos))
		datarate += avarage_dr_list.GetAt(pos);
	datarate /= (avarage_dr_list.GetCount()/10);

	dataratems = 0;
	if (AcceptNewClient() && waitinglist.GetCount()) {
		AddUpNextClient();
		uLastUploadStart = ::GetTickCount(); // Added by Tarod [LoneStar]
	}
	if (!uploadinglist.GetCount())
		return;

	int16 clientsrdy = 0;
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
		CUpDownClient* cur_client = uploadinglist.GetAt(pos);
		if ( (cur_client->socket) && (!cur_client->socket->IsBusy()) && cur_client->HasBlocks())
			clientsrdy++;
	}
	if (!clientsrdy){
		estadatarate -= 200;
		bDataRateMaxed = true; // Added by Tarod [LoneStar]
		if (estadatarate < 100)
			estadatarate = 100;
		clientsrdy++;
	}
	else{
		estadatarate += 200;
		bDataRateMaxed = false; // Added by Tarod [LoneStar]
		if (estadatarate > app_prefs->GetMaxUpload()*102)
			estadatarate = app_prefs->GetMaxUpload()*102;
	}
	uint32 sendperclient = estadatarate/clientsrdy;
	POSITION pos1,pos2;
	for (pos1 = uploadinglist.GetHeadPosition();( pos2 = pos1 ) != NULL; ){
		uploadinglist.GetNext(pos1);
		CUpDownClient* cur_client = uploadinglist.GetAt(pos2);
		dataratems += cur_client->SendBlockData(sendperclient);
	}
};

bool CUploadQueue::AcceptNewClient(){
	// check if we can allow a new client to start downloading form us
	if (uploadinglist.GetCount() < MIN_UP_CLIENTS_ALLOWED)
		return true;
	else if (uploadinglist.GetCount() >= MAX_UP_CLIENTS_ALLOWED)
		return false;

	// Added by Tarod -fills uploads slots before open new one
	//now the final check
	if (!theApp.glob_prefs->IsThrottleUploadEnabled() && theApp.glob_prefs->GetMaxUpload() == UNLIMITED) {
		if ((uint32)uploadinglist.GetCount() < (datarate/UPLOAD_CLIENT_DATARATE))
			return true;
	} else {
		uint16 nMaxSlots = MIN_UP_CLIENTS_ALLOWED;
		if (theApp.glob_prefs->GetMaxUpload() > 10){
			nMaxSlots += (uint16)ceil((((theApp.glob_prefs->GetMaxUpload() - 10)*1024) / UPLOAD_CLIENT_DATARATE)) ;
		}
		if ((uint32)uploadinglist.GetCount() < (datarate/UPLOAD_CHECK_CLIENT_DR) && uploadinglist.GetCount() < nMaxSlots) {
			// Added by Tarod [LoneStar] -modifications for 0.24x code
			if (theApp.glob_prefs->IsThrottleUploadEnabled() && bDataRateMaxed) {
				if ((::GetTickCount() - uLastUploadStart) > UPLOAD_CLIENT_THRESHOLD)
					return true;
			} else {
			return true;
			}
		}
	}
		
	//nope
	return false;
}*/

void CUploadQueue::Process(){
	avarage_dr_list.RemoveHead();
	avarage_dr_list.AddTail(dataratems);
	datarate = 0;
	for (POSITION pos = avarage_dr_list.GetHeadPosition();pos != 0;avarage_dr_list.GetNext(pos))
		datarate += avarage_dr_list.GetAt(pos);
	datarate /= (avarage_dr_list.GetCount()/10);

	dataratems = 0;
	if (AcceptNewClient() && waitinglist.GetCount())
		AddUpNextClient();
	if (!uploadinglist.GetCount())
		return;

	int16 clientsrdy = 0;
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
		CUpDownClient* cur_client = uploadinglist.GetAt(pos);
		if ( (cur_client->socket) && (!cur_client->socket->IsBusy()) && cur_client->HasBlocks())
			clientsrdy++;
	}
	if (!clientsrdy){
		estadatarate -= 200;
		if (estadatarate < 100)
			estadatarate = 100;
		clientsrdy++;
	}
	else{
		estadatarate += 200;
		if (estadatarate > app_prefs->GetMaxUpload()*102)
			estadatarate = app_prefs->GetMaxUpload()*102;
	}
	uint32 sendperclient = estadatarate/clientsrdy;
	POSITION pos1,pos2;
	
	for (pos1 = uploadinglist.GetHeadPosition();( pos2 = pos1 ) != NULL; ){
		uploadinglist.GetNext(pos1);
		CUpDownClient* cur_client = uploadinglist.GetAt(pos2);
		dataratems += cur_client->SendBlockData(sendperclient);
	}

	//Added by Rectencle to find out, if a uploadslot is at Zero Upload
	IsOneClientAtZeroUpload = false;
	for (POSITION pos = uploadinglist.GetHeadPosition() ; pos != (POSITION)NULL; uploadinglist.GetNext(pos)) {
		CUpDownClient* cur_client = uploadinglist.GetAt(pos) ;
		if ((cur_client->GetSessionUp() < 1000) || !(cur_client->GetUploadState() == US_UPLOADING)) {
			IsOneClientAtZeroUpload = true;
		}
	}

	// Added by Tarod [idea by Bis]
	// Check if current clients must be kicked from uploading queue
	for (POSITION pos = uploadinglist.GetHeadPosition() ; pos != (POSITION)NULL; uploadinglist.GetNext(pos)) {
		CUpDownClient* cur_client = uploadinglist.GetAt(pos) ;
		
		
		
		// Check it once per minute (enough)
		// Rectencle: Not this case! Check every 5 seconds
		DWORD actualtime = ::GetTickCount() ;
		if ((actualtime - lasttimechecked) > 5000) { // 5000 = 5 secs.
			lasttimechecked = actualtime ;

		LeavePrefetchSection = false;
// Rectencle Prefetch-Section
			//Rectencle Kick lazy client from Uploading
			if ((cur_client->GetUploadState() == US_UPLOADING) && (cur_client->GetSessionUp() < 1000)) {
				cur_client->ClearPrefetchedAlready();
				cur_client->SetWaitStartTime() ;
				RemoveFromUploadQueue(cur_client) ;
				AddClientToQueue(cur_client, true) ;
				LeavePrefetchSection = true;
			}
			
//			if (CheckForTimeOver(cur_client)) {
			//Rectencle Whole Chunk
			//if (!LeavePrefetchSection && (cur_client->GetSessionUp()>= 500000-PREFETCHSIZE) || ((cur_client->GetFileSize() - cur_client->GetSessionUp()) < PREFETCHSIZE)) { //Rectencle only for testing purposes; in release disabled
			if (!LeavePrefetchSection && (cur_client->GetSessionUp()>= PARTSIZE-PREFETCHSIZE) || ((cur_client->GetFileSize() - cur_client->GetSessionUp()) < PREFETCHSIZE)) { 
				if (!cur_client->PrefetchedAlready()) {
					SetPrefetchStatus();
					cur_client->SetPrefetchedAlready();
					LeavePrefetchSection = true; //to avoid prefetching and removing below at the same time
				}
				//Rectencle: Prefetched but only minimum clients uploading?
				//=> something went wrong; prefetch again and keep old client uploading for further 10 seconds
				if (!LeavePrefetchSection && cur_client->PrefetchedAlready() && (GetUploadQueueLength() <= MIN_UP_CLIENTS_ALLOWED)) {
					SetPrefetchStatus();
					LeavePrefetchSection = true; //to avoid prefetching and removing below at the same time
				}
				//Rectencle: One Prefetched client is still struggling; delay disconnection old client
				//if (!LeavePrefetchSection && IsOneClientAtZeroUpload) {
				//	LeavePrefetchSection = true;  //to avoid prefetching and removing below at the same time
				//}
			}
			//if (!LeavePrefetchSection && !IsOneClientAtZeroUpload && (cur_client->GetSessionUp()>= 500000) && !((cur_client->GetFileSize() - cur_client->GetSessionUp()) < PREFETCHSIZE)) {//Rectencle only for testing purposes; in release disabled
			if (!LeavePrefetchSection && !IsOneClientAtZeroUpload && (cur_client->GetSessionUp()>= PARTSIZE) && !((cur_client->GetFileSize() - cur_client->GetSessionUp()) < PREFETCHSIZE)) {
				// back on the waitqueue
				cur_client->ClearPrefetchedAlready();
				cur_client->SetWaitStartTime() ;
				RemoveFromUploadQueue(cur_client) ;
				AddClientToQueue(cur_client, true) ;
			}
			
//Rectencle
		}
	}
	// End Tarod
};

// Exchanged Process from 0.23a; use old version 0.22c

bool CUploadQueue::AcceptNewClient(){
	// check if we can allow a new client to start downloading form us
	if (uploadinglist.GetCount() < MIN_UP_CLIENTS_ALLOWED)
		return true;
	else if (uploadinglist.GetCount() >= MAX_UP_CLIENTS_ALLOWED)
		return false;

	if ((uint32)uploadinglist.GetCount() < (datarate/UPLOAD_CLIENT_DATARATE))
		return true;

	//Rectencle open additional slot if the uploading three cannot fill the capacitiy
	if ((totaluploadtime > 10) && (GetUploadQueueLength() <= MIN_UP_CLIENTS_ALLOWED) && (datarate < theApp.glob_prefs->GetMaxUpload()*850)) {
		return true;
	}

//Rectencle Connection Prefetching
	if (GetPrefetchStatus()>0) {
		return true;
	}
// Rectencle End
	//nope
	return false;
}

CUploadQueue::~CUploadQueue(){
	KillTimer(0,141);
}

POSITION CUploadQueue::GetWaitingClient(CUpDownClient* client){
	return waitinglist.Find(client); 
}

POSITION CUploadQueue::GetWaitingClientByID(CUpDownClient* client){
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		if (client->Compare(waitinglist.GetAt(pos)))
			return pos;
	}
	return 0;
}

CUpDownClient* CUploadQueue::GetWaitingClientByIP(uint32 dwIP){
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		if (dwIP == waitinglist.GetAt(pos)->GetIP())
			return waitinglist.GetAt(pos);
	}
	return 0;
}

POSITION CUploadQueue::GetDownloadingClient(CUpDownClient* client){
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
		if (client == uploadinglist.GetAt(pos))
			return pos;
	}
	return 0;
}

void CUploadQueue::UpdateBanCount(){
	int count=0;
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		CUpDownClient* cur_client= waitinglist.GetAt(pos);
		if(cur_client->IsBanned())
			count++;
	}
	SetBanCount(count);
}
void CUploadQueue::AddClientToQueue(CUpDownClient* client, bool bIgnoreTimelimit){
	if (theApp.serverconnect->IsConnected() && theApp.serverconnect->IsLowID()
		&& !theApp.serverconnect->IsLocalServer(client->GetServerIP(),client->GetServerPort())
		&& client->GetDownloadState() == DS_NONE && !client->IsFriend()
		&& GetWaitingUserCount() > 50)
		return;
	client->AddAskedCount();
	client->SetLastUpRequest();
	if (!bIgnoreTimelimit){
		if (client->IsBanned()){
			// BAN just for a hour by Tarod
			if (::GetTickCount() - client->GetBanTime() > (18000000)){ //Time longer (Rectencle)
			// End of BAN just for a hour by Tarod
				client->UnBan();
			}
			else
				return;
		}
		client->AddRequestCount(client->reqfileid);
	}
	// check for double
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		CUpDownClient* cur_client= waitinglist.GetAt(pos);
		if (cur_client == client){	//already on queue
			client->SendRankingInfo();
			theApp.emuledlg->transferwnd.queuelistctrl.RefreshClient(client);
			return;			
		}
		else if ( client->Compare(cur_client) || !memcmp(cur_client->GetUserHash(),client->GetUserHash(),16) ) {
			// another client with same ip or hash
			theApp.emuledlg->AddDebugLogLine(false,CString(GetResString(IDS_SAMEUSERHASH)),client->GetUserName(),cur_client->GetUserName(),cur_client->GetUserName() );
			RemoveFromWaitingQueue(pos,true);	
			if (!cur_client->socket)
				cur_client->Disconnected();	
			return;
		}
	}
	// done

	// Add clients server to list.
	if (theApp.glob_prefs->AddServersFromClient()){
		in_addr host;
		host.S_un.S_addr = client->GetServerIP();
		CServer* srv = new CServer(client->GetServerPort(), inet_ntoa(host));
		srv->SetListName(srv->GetAddress());

		if (!theApp.emuledlg->serverwnd.serverlistctrl.AddServer(srv, true))
			delete srv;
		/*else
			theApp.emuledlg->AddLogLine(false,"Added new server: %s:%d", srv->GetFullIP(), srv->GetPort());*/
	}

	// statistic values
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->reqfileid);
		if (reqfile)
			reqfile->statistic.AddRequest();
	// TODO find better ways to cap the list
	if ((uint32)waitinglist.GetCount() > (theApp.glob_prefs->GetQueueSize()-bannedcount)) // Modded by Tarod
		return;
	if (client->IsDownloading()){
		// he's already downloading and wants probably only another file
		Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
		theApp.uploadqueue->AddUpDataRateMSOverhead(packet->size, 160);
		client->socket->SendPacket(packet,true);
		return;
	}
	if (waitinglist.IsEmpty() && AcceptNewClient())
		AddUpNextClient(client);
	else{
		waitinglist.AddTail(client);
		client->SetUploadState(US_ONUPLOADQUEUE);
		client->SendRankingInfo();
		theApp.emuledlg->transferwnd.queuelistctrl.AddClient(client);
		theApp.emuledlg->transferwnd.ShowQueueCount(waitinglist.GetCount());
	}
}

bool CUploadQueue::RemoveFromUploadQueue(CUpDownClient* client, bool updatewindow){
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
		if (client == uploadinglist.GetAt(pos)){
			if (updatewindow)
				theApp.emuledlg->transferwnd.uploadlistctrl.RemoveClient(uploadinglist.GetAt(pos));
			uploadinglist.RemoveAt(pos);
			if( client->GetTransferedUp() ){
				successfullupcount++;
				totaluploadtime += client->GetUpStartTimeDelay()/1000;
			}
			else
				failedupcount++;
			client->SetUploadState(US_NONE);
			client->ClearUploadBlockRequests();

			// Added by Tarod -saves known.met file to avoid loosing it by accident
			theApp.knownfiles->Save();
			// End by Tarod

			return true;
		}
	}
	return false;
}

uint32 CUploadQueue::GetAverageUpTime(){
	if( successfullupcount ){
		return totaluploadtime/successfullupcount;
	}
	return 0;
}

bool CUploadQueue::RemoveFromWaitingQueue(CUpDownClient* client, bool updatewindow){
	POSITION pos = waitinglist.Find(client);
	if (pos){
		RemoveFromWaitingQueue(pos,updatewindow);
		if (updatewindow)
			theApp.emuledlg->transferwnd.ShowQueueCount(waitinglist.GetCount());
		return true;
	}
	else
		return false;
}

void CUploadQueue::RemoveFromWaitingQueue(POSITION pos, bool updatewindow){	
	CUpDownClient* todelete = waitinglist.GetAt(pos);
	waitinglist.RemoveAt(pos);
	if( todelete->IsBanned() )
		todelete->UnBan();
	if (updatewindow)
		theApp.emuledlg->transferwnd.queuelistctrl.RemoveClient(todelete);
	todelete->SetUploadState(US_NONE);
}


bool CUploadQueue::CheckForTimeOver(CUpDownClient* client){
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		if (client->GetScore(true,true) < waitinglist.GetAt(pos)->GetScore(true,false))
			return true;
	}
	return false;
}

void CUploadQueue::DeleteAll(){
	waitinglist.RemoveAll();
	uploadinglist.RemoveAll();
}

uint16 CUploadQueue::GetWaitingPosition(CUpDownClient* client){
	if (!IsOnUploadQueue(client))
		return 0;
	uint16 rank = 1;
	uint32 myscore = client->GetScore(false);
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		if (waitinglist.GetAt(pos)->GetScore(false) > myscore)
			rank++;
	}
	return rank;
}

void CUploadQueue::CompDatarateOverhead(){
	this->m_AvarageUDRO_list.AddTail(m_nUpDataRateMSOverhead);
	if (m_AvarageUDRO_list.GetCount() > 150)
		m_AvarageUDRO_list.RemoveAt(m_AvarageUDRO_list.GetHeadPosition());
	m_nUpDatarateOverhead = 0;
	m_nUpDataRateMSOverhead = 0;
	for (POSITION pos = m_AvarageUDRO_list.GetHeadPosition();pos != 0;m_AvarageUDRO_list.GetNext(pos))
		m_nUpDatarateOverhead += m_AvarageUDRO_list.GetAt(pos);

	if(m_AvarageUDRO_list.GetCount() > 10)
		m_nUpDatarateOverhead /= (m_AvarageUDRO_list.GetCount()/10);
	else
		m_nUpDatarateOverhead = 0;
	return;
}

VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg,UINT_PTR idEvent,DWORD dwTime){

	// Barry - Don't do anything if the app is shutting down - can cause unhandled exceptions
	if (!theApp.emuledlg->IsRunning())
		return;

	theApp.uploadqueue->Process();
	theApp.downloadqueue->Process();
	theApp.clientcredits->Process();
	theApp.uploadqueue->CompDatarateOverhead();
	theApp.downloadqueue->CompDatarateOverhead();
	counter++;

	// one second
	if (counter >= 10){
		counter=0;

		if (theApp.serverconnect->IsConnecting()) theApp.serverconnect->CheckForTimeout();

		// display graphs
		if (theApp.glob_prefs->GetTrafficOMeterInterval()>0) {
			igraph++;

			if (igraph >= (uint32)(theApp.glob_prefs->GetTrafficOMeterInterval()) ) {
				igraph=0;
				theApp.emuledlg->statisticswnd.SetCurrentRate((float)theApp.uploadqueue->GetDatarate()/1024,(float)theApp.downloadqueue->GetDatarate()/1024);
			}
		}
        if (theApp.emuledlg->activewnd == &theApp.emuledlg->statisticswnd) {    
			// display stats
			if (theApp.glob_prefs->GetStatsInterval()>0) {
				istats++;

				if (istats >= (uint32)(theApp.glob_prefs->GetStatsInterval()) ) {
					istats=0;
					theApp.emuledlg->ShowStatistics();
				}
			}
		}
		//save rates every second
		theApp.emuledlg->statisticswnd.RecordRate();

		
		sec++;
		// 5 seconds
		if (sec>=5) {

			#ifdef _DEBUG
				if (!AfxCheckMemory()) AfxDebugBreak();
			#endif

			sec = 0;
			theApp.listensocket->Process();
			theApp.OnlineSig(); // Added By Bouc7 
			theApp.emuledlg->ShowTransferRate();
            if (theApp.emuledlg->activewnd == &theApp.emuledlg->statisticswnd) {
				theApp.emuledlg->ShowStatistics(); 
			}

		}

		statsave++;
		if (statsave>=60) {
			statsave=0;
			CString buffer;
			char* fullpath = new char[strlen(theApp.glob_prefs->GetAppDir())+16];
			sprintf(fullpath,"%spreferences.ini",theApp.glob_prefs->GetAppDir());
			CIni ini( fullpath, "eMule" );
			delete[] fullpath;

			buffer.Format("%I64Lu",theApp.stat_sessionReceivedBytes+theApp.glob_prefs->GetTotalDownloaded());
			ini.WriteString("TotalDownloadedBytes",buffer ,"Statistics");

			buffer.Format("%I64Lu",theApp.stat_sessionSentBytes+theApp.glob_prefs->GetTotalUploaded());
			ini.WriteString("TotalUploadedBytes",buffer ,"Statistics");
		}
	}

}

CUpDownClient* CUploadQueue::GetNextClient(CUpDownClient* lastclient){
	if (waitinglist.IsEmpty())
		return 0;
	if (!lastclient)
		return waitinglist.GetHead();
	POSITION pos = waitinglist.Find(lastclient);
	if (!pos){
		TRACE("Error: CServerList::GetNextClient");
		return waitinglist.GetHead();
	}
	waitinglist.GetNext(pos);
	if (!pos)
		return NULL;
	else
		return waitinglist.GetAt(pos);
}

void CUploadQueue::FindSourcesForFileById(CTypedPtrList<CPtrList, CUpDownClient*>* srclist, uchar* filehash) {
	POSITION pos;
	
	pos = uploadinglist.GetHeadPosition();
	while(pos) {
		CUpDownClient *potential = uploadinglist.GetNext(pos);
		if(memcmp(potential->reqfileid, filehash, 16) == 0)
			srclist->AddTail(potential);
	}

	pos = waitinglist.GetHeadPosition();
	while(pos) {
		CUpDownClient *potential = waitinglist.GetNext(pos);
		if(memcmp(potential->reqfileid, filehash, 16) == 0)
			srclist->AddTail(potential);
	}
}

//Rectencle Connection-Prefetching
uint32 CUploadQueue::GetPrefetchStatus() { //By Recencle for Connection-Prefetching
	if (PrefetchStatus > 0) {
		PrefetchStatus--;
		return PrefetchStatus+1;
	} else {
		PrefetchStatus = 0;
		return 0;
	}
}

void CUploadQueue::SetPrefetchStatus() { //By Recencle for Connection-Prefetching
	PrefetchStatus++;
}
//End Rectencle Connection-Prefetching