//this file is part of eMule
//Copyright (C)2002-2008 Merkur ( strEmail.Format("%s@%s", "devteam", "emule-project.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 "emule.h"
#include "UploadQueue.h"
#include "Packets.h"
#include "KnownFile.h"
#include "ListenSocket.h"
#include "Exceptions.h"
#include "PerfLog.h"
#include "UploadBandwidthThrottler.h"
#include "ClientList.h"
#include "LastCommonRouteFinder.h"
#include "DownloadQueue.h"
#include "FriendList.h"
#include "Statistics.h"
#include "MMServer.h"
#include "OtherFunctions.h"
#include "UpDownClient.h"
#include "SharedFileList.h"
#include "KnownFileList.h"
#include "Sockets.h"
#include "ClientCredits.h"
#include "Server.h"
#include "ServerList.h"
#include "emuledlg.h"
#include "ServerWnd.h"
#include "TransferDlg.h"
#include "SearchDlg.h"
#include "StatisticsDlg.h"
#include "Kademlia/Kademlia/Kademlia.h"
#include "Kademlia/Kademlia/Prefs.h"
#include "Log.h"
//#include "collection.h" //>>> WiZaRd::Small File Slot
#ifdef CLIENTANALYZER
#include "./AntiLeech/ClientAnalyzer.h" //>>> WiZaRd::ClientAnalyzer
#endif
//>>> WiZaRd::PNCheck
#include "./EMF/eMuleFuture.h" 
//<<< WiZaRd::PNCheck
#include "PartFile.h"

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

//>>> Add2Up Timer
#define UPLOAD_RETALIATIONTIME		SEC2MS(15)		//was: 10
#define MIN_NEXTSLOT_WAITTIME		SEC2MS(5)		//was:  3
#define MIN_NEXTSLOT_WAITTIME_LOW	SEC2MS(5)		//was:  1 
//<<< Add2Up Timer
//>>> WiZaRd::Automatic Firewalled Retries
static	uint8	m_iFirewalledRetries = 0;
static	DWORD	m_dwFirewalledTimer = NULL;
//<<< WiZaRd::Automatic Firewalled Retries

static uint32 counter, sec, statsave;
static UINT s_uSaveStatistics = 0;
static uint32 igraph, istats, i2Secs;

#define HIGHSPEED_UPLOADRATE_START 500*1024
#define HIGHSPEED_UPLOADRATE_END   300*1024


CUploadQueue::CUploadQueue()
{
	m_uiPaybackCount = 0; //>>> WiZaRd::Payback First
	m_dwFirewalledTimer = ::GetTickCount(); //>>> WiZaRd::Automatic Firewalled Retries
#ifdef MOD_FUNCTIONS
//>>> WiZaRd::PNCheck/EMF
	VERIFY( (h_PNTimer = SetTimer(0,0,MIN2MS(15),PNTimer)) != NULL ); 
	if (thePrefs.GetVerbose() && !h_PNTimer)
		AddDebugLogLine(true,_T("Failed to create 'private message' timer - %s"),GetErrorMessage(GetLastError()));
//<<< WiZaRd::PNCheck/EMF
#endif
	h_timer = NULL;
//	VERIFY( (h_timer = SetTimer(0,0,100,UploadTimer)) != NULL );
//	if (thePrefs.GetVerbose() && !h_timer)
//		AddDebugLogLine(true,_T("Failed to create 'upload queue' timer - %s"),GetErrorMessage(GetLastError()));
	m_uiFellBelowSlotsNeeded = 0; //>>> Add2Up Timer
	datarate = 0;
	counter=0;
	successfullupcount = 0;
	failedupcount = 0;
	totaluploadtime = 0;
	m_nLastStartUpload = 0;
	statsave=0;
	i2Secs=0;
	m_dwRemovedClientByScore = ::GetTickCount();
    m_iHighestNumberOfFullyActivatedSlotsSinceLastCall = 0;
    m_MaxActiveClients = 0;
    m_MaxActiveClientsShortTime = 0;

    m_lastCalculatedDataRateTick = 0;
    m_avarage_dr_sum = 0;
    friendDatarate = 0;

    m_dwLastResortedUploadSlots = 0;
	m_hHighSpeedUploadTimer = NULL;
	m_bStatisticsWaitingListDirty = true;
}

void	CUploadQueue::StartTimer()
{
	if(h_timer == NULL)
	{
		VERIFY( (h_timer = SetTimer(0,0,100,UploadTimer)) != NULL );
		if (thePrefs.GetVerbose() && !h_timer)
			AddDebugLogLine(true, L"Failed to create 'upload queue' timer - %s", GetErrorMessage(GetLastError()));
	}
	else
		ASSERT(0);
}

CUploadQueue::~CUploadQueue(){
#ifdef MOD_FUNCTIONS
//>>> WiZaRd::PNCheck/EMF
	if(h_PNTimer)
		KillTimer(0, h_PNTimer);
//<<< WiZaRd::PNCheck/EMF
#endif
	if (h_timer)
		KillTimer(0,h_timer);
	if (m_hHighSpeedUploadTimer)
		UseHighSpeedUploadTimer(false);
}

//>>> WiZaRd::Payback First
INT64	GetUpDownDiff(const CUpDownClient* client)
{
	if(client->Credits() == NULL)
		return _I64_MIN;
	return  client->Credits()->GetDownloadedTotal()-client->Credits()->GetUploadedTotal();
}

BOOL IsPayback(const CUpDownClient* client)
{	
	return (!client->GetRequestFile() || client->GetDownloadState() > DS_ONQUEUE)
		&& GetUpDownDiff(client) > (SESSIONMAXTRANS/2);
}

BOOL SecondIsBetterClient(const bool bPaybackCheck, const CUpDownClient* first, const CUpDownClient* second, const UINT firstscore, const UINT secondscore)
{
	if(second == NULL)
		return FALSE;
	if(first == NULL)
		return TRUE;

	if(bPaybackCheck)
	{
		const BOOL bPay1 = IsPayback(first);
		const BOOL bPay2 = IsPayback(second);
		if(bPay1 && !bPay2)
			return FALSE;	//first is better
		if(!bPay1 && bPay2)
			return TRUE;	//second is better
		else if(bPay1 && bPay2) 
			return GetUpDownDiff(second) > GetUpDownDiff(first); //second or first?
		//flow over
	}

	return (secondscore > firstscore);
}
//<<< WiZaRd::Payback First

/**
 * Find the highest ranking client in the waiting queue, and return it.
 *
 * Low id client are ranked as lowest possible, unless they are currently connected.
 * A low id client that is not connected, but would have been ranked highest if it
 * had been connected, gets a flag set. This flag means that the client should be
 * allowed to get an upload slot immediately once it connects.
 *
 * @return address of the highest ranking client.
 */
CUpDownClient* CUploadQueue::FindBestClientInQueue()
{
//>>> WiZaRd::PowerShare
	CUpDownClient* toadd = NULL;
	CUpDownClient* toaddlow = NULL;
	UINT	bestscore = 0;
	UINT  bestlowscore = 0;

	CUpDownClient* friendpos = NULL;
	CUpDownClient* toaddPS = NULL;	
	CUpDownClient* toaddlowPS = NULL;
	UINT	bestscorePS = 0;
	UINT	bestlowscorePS = 0;
	uint8	highestPSPrio = 0;

//>>> WiZaRd::Payback First
	bool bPaybackCheck = false; 
	switch(thePrefs.GetPaybackFirst())
	{
		default:
		case 0: //off
			break;

		case 1: //on - one slot
			bPaybackCheck = m_lPaybackList.IsEmpty() ? true : false;
			break;

		case 2: //on - once every X slots
			bPaybackCheck = m_uiPaybackCount == 5;
			break;

		case 3: //auto - TODO?
			bPaybackCheck = m_lPaybackList.IsEmpty()
				|| m_uiPaybackCount == 5;
			break;
	}
//<<< WiZaRd::Payback First

	POSITION pos1, pos2;
	for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;)
	{
		waitinglist.GetNext(pos1);
		CUpDownClient* cur_client =	waitinglist.GetAt(pos2);
		CKnownFile* file = theApp.sharedfiles->GetFileByID(cur_client->GetUploadFileID());
		//While we are going through this list.. Lets check if a client appears to have left the network..
		ASSERT ( cur_client->GetLastUpRequest() );
		if ((::GetTickCount() - cur_client->GetLastUpRequest() > MAX_PURGEQUEUETIME) /*|| !file*/ )
		{
			//This client has either not been seen in a long time, or we no longer share the file he wanted anymore..
			cur_client->ClearWaitStartTime();
			RemoveFromWaitingQueue(pos2,true);
			continue;
		}

		if(file == NULL)
			continue;
		//else
		{
			if(cur_client->GetFriendSlot()
				&& (!cur_client->HasLowID() || (cur_client->socket && cur_client->socket->IsConnected())))
				friendpos = cur_client;
			if(friendpos)
				continue; //no need to go on...

			// finished clearing
			const uint32 cur_score = cur_client->GetScore(false);

			if (/*file*/cur_client->IsPowerShared()) //>>> taz::no PowerShare for leechers
			{
				uint8 curprio = file->GetUpPriority()+1;
				if(curprio >= 5)
					curprio = 0;
				if(curprio > highestPSPrio
//>>> WiZaRd::Payback First
//					|| (curprio == highestPSPrio && cur_score > bestscorePS))
					|| (curprio == highestPSPrio && SecondIsBetterClient(bPaybackCheck, toaddPS, cur_client, bestscorePS, cur_score)))
//<<< WiZaRd::Payback First
				{
#ifdef CLIENTANALYZER
					//if our upload tries failed at least 3 times in a row we will only grant a slot while being connected already
					//that way, we hopefully ensure a successful upload session
					if(cur_client->GetAntiLeechData()
						&& cur_client->GetAntiLeechData()->ShouldntUploadForBadSessions())
					{
						if(cur_client->socket && cur_client->socket->IsConnected())
						{
							highestPSPrio = curprio;
							if(curprio > highestPSPrio)
							{
								bestscorePS = 0;
								bestlowscorePS = 0;
							}

							bestscorePS = cur_score;
							toaddPS = cur_client;
						}
						continue;
					}
#endif
					highestPSPrio = curprio;
					if(curprio > highestPSPrio)
					{
						bestscorePS = 0;
						bestlowscorePS = 0;
					}

					// cur_client is more worthy than current best client that is ready to go (connected).
					if(!cur_client->HasLowID() || (cur_client->socket && cur_client->socket->IsConnected())) 
					{
						// this client is a HighID or a lowID client that is ready to go (connected)
						// and it is more worthy
						bestscorePS = cur_score;
						toaddPS = cur_client;
					} 
					else if(!cur_client->m_bAddNextConnect) 
					{
						// this client is a lowID client that is not ready to go (not connected)

						// now that we know this client is not ready to go, compare it to the best not ready client
						// the best not ready client may be better than the best ready client, so we need to check
						// against that client
//>>> WiZaRd::Payback First
						if(SecondIsBetterClient(bPaybackCheck, toaddlowPS, cur_client, bestlowscorePS, cur_score))
//						if (cur_score > bestlowscorePS)
//<<< WiZaRd::Payback First
						{
							// it is more worthy, keep it
							bestlowscorePS = cur_score;
							toaddlowPS = cur_client;
						}
					}
				} 
			}
			else 
			{
//>>> WiZaRd::Payback First
				if(SecondIsBetterClient(bPaybackCheck, toadd, cur_client, bestscore, cur_score))
//				if (cur_score > bestscore)
//<<< WiZaRd::Payback First
				{
#ifdef CLIENTANALYZER
					//if our upload tries failed at least 3 times in a row we will only grant a slot while being connected already
					//that way, we hopefully ensure a successful upload session
					if(cur_client->GetAntiLeechData()
						&& cur_client->GetAntiLeechData()->ShouldntUploadForBadSessions())
					{
						if(cur_client->socket && cur_client->socket->IsConnected())
						{
							bestscore = cur_score;
							toadd = cur_client;
						}
						continue;
					}
#endif
					// cur_client is more worthy than current best client that is ready to go (connected).
					if(!cur_client->HasLowID() || (cur_client->socket && cur_client->socket->IsConnected())) 
					{
						// this client is a HighID or a lowID client that is ready to go (connected)
						// and it is more worthy
						bestscore = cur_score;
						toadd = cur_client;
						//newclient = waitinglist.GetAt(toadd);
					} 
					else if(!cur_client->m_bAddNextConnect) 
					{
						// this client is a lowID client that is not ready to go (not connected)

						// now that we know this client is not ready to go, compare it to the best not ready client
						// the best not ready client may be better than the best ready client, so we need to check
						// against that client
//>>> WiZaRd::Payback First
						if(SecondIsBetterClient(bPaybackCheck, toaddlow, cur_client, bestlowscore, cur_score))
//						if (cur_score > bestlowscore)
//<<< WiZaRd::Payback First
						{
							// it is more worthy, keep it
							bestlowscore = cur_score;
							toaddlow = cur_client;
							//lowclient = waitinglist.GetAt(toaddlow);
						}
					}
				}
			}
		}
	}
//>>> WiZaRd::Payback First
//	if (bestlowscorePS > bestscorePS && toaddlowPS)
	if (toaddlowPS && SecondIsBetterClient(bPaybackCheck, toaddPS, toaddlowPS, bestscorePS, bestlowscorePS))
//<<< WiZaRd::Payback First
		toaddlowPS->m_bAddNextConnect = true;
//>>> WiZaRd::Payback First
//	else if (bestlowscore > bestscore && toaddlow)
	else if (toaddlow && SecondIsBetterClient(bPaybackCheck, toadd, toaddlow, bestscore, bestlowscore))
//<<< WiZaRd::Payback First
		toaddlow->m_bAddNextConnect = true;

	if(friendpos)
		return friendpos;
	if(toaddPS)
		return toaddPS;
	return toadd;

/*
	POSITION toadd = 0;
	POSITION toaddlow = 0;
	uint32	bestscore = 0;
	uint32  bestlowscore = 0;
    CUpDownClient* newclient = NULL;
    CUpDownClient* lowclient = NULL;

	POSITION pos1, pos2;
	for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;)
	{
		waitinglist.GetNext(pos1);
		CUpDownClient* cur_client =	waitinglist.GetAt(pos2);
		//While we are going through this list.. Lets check if a client appears to have left the network..
		ASSERT ( cur_client->GetLastUpRequest() );
		if ((::GetTickCount() - cur_client->GetLastUpRequest() > MAX_PURGEQUEUETIME) || !theApp.sharedfiles->GetFileByID(cur_client->GetUploadFileID()) )
		{
			//This client has either not been seen in a long time, or we no longer share the file he wanted anymore..
			cur_client->ClearWaitStartTime();
			RemoveFromWaitingQueue(pos2,true);
			continue;
		}
        else
        {
		    // finished clearing
		    uint32 cur_score = cur_client->GetScore(false);

		    if ( cur_score > bestscore)
		    {
                // cur_client is more worthy than current best client that is ready to go (connected).
#ifdef CLIENTANALYZER
				//if our upload tries failed at least 3 times in a row we will only grant a slot while being connected already
				//that way, we hopefully ensure a successful upload session
				if(cur_client->GetAntiLeechData()
					&& cur_client->GetAntiLeechData()->ShouldntUploadForBadSessions())
				{
					if(cur_client->socket && cur_client->socket->IsConnected())
					{
						bestscore = cur_score;
						toadd = pos2;
						newclient = waitinglist.GetAt(toadd);
					}
					continue;
				}
#endif
                if(!cur_client->HasLowID() || (cur_client->socket && cur_client->socket->IsConnected())) {
                    // this client is a HighID or a lowID client that is ready to go (connected)
                    // and it is more worthy
			        bestscore = cur_score;
			        toadd = pos2;
                    newclient = waitinglist.GetAt(toadd);
                } 
				else if(!cur_client->m_bAddNextConnect) 
				{
                    // this client is a lowID client that is not ready to go (not connected)
    
                    // now that we know this client is not ready to go, compare it to the best not ready client
                    // the best not ready client may be better than the best ready client, so we need to check
                    // against that client
			        if (cur_score > bestlowscore)
			        {
                        // it is more worthy, keep it
				        bestlowscore = cur_score;
				        toaddlow = pos2;
                        lowclient = waitinglist.GetAt(toaddlow);
			        }
                }
            } 
		}
	}
	
	if (bestlowscore > bestscore && lowclient)
		lowclient->m_bAddNextConnect = true;

    if (!toadd)
		return NULL;
    else
	    return waitinglist.GetAt(toadd);
*/
//<<< WiZaRd::PowerShare
}

//>>> WiZaRd::PowerShare //>>> WiZaRd::SlotFocus
uint8 GetClass(const CUpDownClient* client)
{
	if(client->GetFriendSlot())
		return 0;
	if(client->IsPowerShared())
		return 1;
	return 2;
}
//<<< WiZaRd::PowerShare //<<< WiZaRd::SlotFocus

void CUploadQueue::InsertInUploadingList(CUpDownClient* newclient) 
{
//>>> WiZaRd::Payback First
	if(IsPayback(newclient))
		m_lPaybackList.AddTail(newclient); 
//<<< WiZaRd::Payback First

//>>> WiZaRd::PowerShare //>>> WiZaRd::SlotFocus
//>>> USC
	POSITION insertPosition = NULL;
	UINT posCounter = uploadinglist.GetCount();
	const uint8 classID = GetClass(newclient);
	const UINT score = newclient->GetScore(false, newclient->IsDownloading());

	for(POSITION pos = uploadinglist.GetTailPosition(); pos;) 
	{
		CUpDownClient* uploadingClient = uploadinglist.GetAt(pos);
		const uint8 thisClassID = GetClass(uploadingClient);

		//check if the uploadingClient is "better" than the newclient and break - or update the insertPosition accordingly
		if(thisClassID < classID) //lower is better 
			break; //quit it

		if(thisClassID == classID)
		{
			const UINT thisScore = uploadingClient->GetScore(false, true);
			if(thisScore > score) //higher is better
				break; //quit it
		}

//WiZaRd: if we implemented "Count block/success send", we could use this code, too...
/*
		//try to put "good" clients to the top... "good" means that they do not block too much :)
		if(thisClassID == classID) //equal classID - more checks
		{
			//put scheduled clients at the end of the uploadlist
			if(newclient->IsScheduled() && !uploadingClient->IsScheduled())
				break; //quit it
			//OR if he is blocking too much because that may indicate that the client (currently) cannot take enough
			if(uploadingClient->socket 
				&& newclient->socket 
				//remove the 1min limit because slots will jump too much if we keep this
				//				&& uploadingClient->GetUpStartTimeDelay() > MIN2MS(1) 
				//				&& newclient->GetUpStartTimeDelay() > MIN2MS(1)
				&& uploadingClient->GetUpStartTimeDelay() > SEC2MS(15) 
				&& newclient->GetUpStartTimeDelay() > SEC2MS(15)
				&& uploadingClient->socket->GetBlockRatio_overall() <= newclient->socket->GetBlockRatio_overall())
				break; //quit it
		}
*/
		uploadingClient->SetSlotNumber(posCounter+1);
		insertPosition = pos; //the new client is "better" than the current client - save the position of the last "worse" client
		uploadinglist.GetPrev(pos);
		--posCounter;
	}

	//Lets make sure any client that is added to the list has this flag reset!
	newclient->m_bAddNextConnect = false;

	theApp.uploadBandwidthThrottler->AddToStandardList(posCounter, newclient->GetFileUploadSocket());
	if(insertPosition)
		uploadinglist.InsertBefore(insertPosition, newclient); // add it at found pos
	else
		uploadinglist.AddTail(newclient); // add it last
	newclient->SetSlotNumber(posCounter+1);
/*
	//Lets make sure any client that is added to the list has this flag reset!
	newclient->m_bAddNextConnect = false;
    // Add it last
    theApp.uploadBandwidthThrottler->AddToStandardList(uploadinglist.GetCount(), newclient->GetFileUploadSocket());
	uploadinglist.AddTail(newclient);
    newclient->SetSlotNumber(uploadinglist.GetCount());
*/
//<<< WiZaRd::PowerShare //<<< WiZaRd::SlotFocus
}

bool CUploadQueue::AddUpNextClient(LPCTSTR pszReason, CUpDownClient* directadd){
	CUpDownClient* newclient = NULL;
	// select next client or use given client
	if (!directadd)
	{
        newclient = FindBestClientInQueue();

        if(newclient)
		{
		    RemoveFromWaitingQueue(newclient, true);
//		    theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
			theApp.emuledlg->transferwnd->ShowQueueCount();
        }
	}
	else 
		newclient = directadd;

    if(newclient == NULL) 
        return false;

#ifndef CLIENTANALYZER
	if (!thePrefs.TransferFullChunks())
		UpdateMaxClientScore(); // refresh score caching, now that the highest score is removed
#endif

	if (IsDownloading(newclient))
		return false;

//>>> WiZaRd::Optimization
	// statistic
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)newclient->GetUploadFileID());
	if (reqfile == NULL)
	{
		if(thePrefs.GetLogUlDlEvents())
			AddDebugLogLine(false, L"Tried to add client %s to upload list but reqfile wasn't found - prevented failed UL session!", newclient->DbgGetClientInfo());
		return false;
	}
//<<< WiZaRd::Optimization

    if(pszReason && thePrefs.GetLogUlDlEvents())
        AddDebugLogLine(false, _T("Adding client to upload list: %s Client: %s"), pszReason, newclient->DbgGetClientInfo());

//>>> WiZaRd::Small File Slot
	if (reqfile->GetFileSize() < (uint64)MAXPRIORITYCOLL_SIZE && directadd == NULL)
//	if (newclient->HasCollectionUploadSlot() && directadd == NULL)
//<<< WiZaRd::Small File Slot
	{
		ASSERT( false );
//>>> WiZaRd::Small File Slot
//		newclient->SetCollectionUploadSlot(false);
//<<< WiZaRd::Small File Slot
	}

	// tell the client that we are now ready to upload
	if (!newclient->socket || !newclient->socket->IsConnected())
	{
		newclient->SetUploadState(US_CONNECTING);
		if (!newclient->TryToConnect(true))
			return false;
	}
	else
	{
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__AcceptUploadReq", newclient);
		Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
		theStats.AddUpDataOverheadFileRequest(packet->size);
		newclient->SendPacket(packet, true);
		newclient->SetUploadState(US_UPLOADING);
	}
	newclient->SetUpStartTime();
	newclient->ResetSessionUp();
#ifdef CLIENTANALYZER
	newclient->ResetRemainingUp();	// VQB: fullChunk
#endif

    InsertInUploadingList(newclient);

    m_nLastStartUpload = ::GetTickCount();
	
//>>> WiZaRd::Optimization
// 	// statistic
// 	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)newclient->GetUploadFileID());
// 	if (reqfile)
//<<< WiZaRd::Optimization
 		reqfile->statistic.AddAccepted();

	theApp.emuledlg->transferwnd->GetUploadList()->AddClient(newclient);

	return true;
}

void CUploadQueue::UpdateActiveClientsInfo(DWORD curTick) {
    // Save number of active clients for statistics
    uint32 tempHighest = theApp.uploadBandwidthThrottler->GetHighestNumberOfFullyActivatedSlotsSinceLastCallAndReset();

    if(thePrefs.GetLogUlDlEvents() && theApp.uploadBandwidthThrottler->GetStandardListSize() > (uint32)uploadinglist.GetSize()) {
        // debug info, will remove this when I'm done.
        //AddDebugLogLine(false, _T("UploadQueue: Error! Throttler has more slots than UploadQueue! Throttler: %i UploadQueue: %i Tick: %i"), theApp.uploadBandwidthThrottler->GetStandardListSize(), uploadinglist.GetSize(), ::GetTickCount());
    }
	
	if(tempHighest > (uint32)uploadinglist.GetSize()+1) {
        tempHighest = uploadinglist.GetSize()+1;
	}

    m_iHighestNumberOfFullyActivatedSlotsSinceLastCall = tempHighest;

    // save some data about number of fully active clients
    uint32 tempMaxRemoved = 0;
    while(!activeClients_tick_list.IsEmpty() && !activeClients_list.IsEmpty() && curTick-activeClients_tick_list.GetHead() > 20*1000) {
        activeClients_tick_list.RemoveHead();
	    uint32 removed = activeClients_list.RemoveHead();

        if(removed > tempMaxRemoved) {
            tempMaxRemoved = removed;
        }
    }

	activeClients_list.AddTail(m_iHighestNumberOfFullyActivatedSlotsSinceLastCall);
    activeClients_tick_list.AddTail(curTick);

    if(activeClients_tick_list.GetSize() > 1) {
        uint32 tempMaxActiveClients = m_iHighestNumberOfFullyActivatedSlotsSinceLastCall;
        uint32 tempMaxActiveClientsShortTime = m_iHighestNumberOfFullyActivatedSlotsSinceLastCall;
        POSITION activeClientsTickPos = activeClients_tick_list.GetTailPosition();
        POSITION activeClientsListPos = activeClients_list.GetTailPosition();
        while(activeClientsListPos != NULL && (tempMaxRemoved > tempMaxActiveClients && tempMaxRemoved >= m_MaxActiveClients || curTick - activeClients_tick_list.GetAt(activeClientsTickPos) < 10 * 1000)) {
            DWORD activeClientsTickSnapshot = activeClients_tick_list.GetAt(activeClientsTickPos);
            uint32 activeClientsSnapshot = activeClients_list.GetAt(activeClientsListPos);

            if(activeClientsSnapshot > tempMaxActiveClients) {
                tempMaxActiveClients = activeClientsSnapshot;
            }

            if(activeClientsSnapshot > tempMaxActiveClientsShortTime && curTick - activeClientsTickSnapshot < 10 * 1000) {
                tempMaxActiveClientsShortTime = activeClientsSnapshot;
            }

            activeClients_tick_list.GetPrev(activeClientsTickPos);
            activeClients_list.GetPrev(activeClientsListPos);
        }

        if(tempMaxRemoved >= m_MaxActiveClients || tempMaxActiveClients > m_MaxActiveClients) {
            m_MaxActiveClients = tempMaxActiveClients;
        }

        m_MaxActiveClientsShortTime = tempMaxActiveClientsShortTime;
    } else {
        m_MaxActiveClients = m_iHighestNumberOfFullyActivatedSlotsSinceLastCall;
        m_MaxActiveClientsShortTime = m_iHighestNumberOfFullyActivatedSlotsSinceLastCall;
    }
}

/**
 * Maintenance method for the uploading slots. It adds and removes clients to the
 * uploading list. It also makes sure that all the uploading slots' Sockets always have
 * enough packets in their queues, etc.
 *
 * This method is called approximately once every 100 milliseconds.
 */
void CUploadQueue::Process() {

    const DWORD curTick = ::GetTickCount();

    UpdateActiveClientsInfo(curTick);

	if (ForceNewClient()){
        // There's not enough open uploads. Open another one.
        AddUpNextClient(_T("Not enough open upload slots for current ul speed"));
	}

//	ReSortUploadSlots(); //>>> WiZaRd::PowerShare //>>> WiZaRd::SlotFocus //>>> taz::moved

    // The loop that feeds the upload slots with data.
	POSITION pos = uploadinglist.GetHeadPosition();
	while(pos != NULL){
        // Get the client. Note! Also updates pos as a side effect.
		CUpDownClient* cur_client = uploadinglist.GetNext(pos);
		if (thePrefs.m_iDbgHeap >= 2)
			ASSERT_VALID(cur_client);
		//It seems chatting or friend slots can get stuck at times in upload.. This needs looked into..
		if (!cur_client->socket)
		{
			RemoveFromUploadQueue(cur_client, _T("Uploading to client without socket? (CUploadQueue::Process)"));
			if(cur_client->Disconnected(_T("CUploadQueue::Process"))){
				delete cur_client;
			}
		} else {
            cur_client->SendBlockData();
        }
	}

    // Save used bandwidth for speed calculations
	uint64 sentBytes = theApp.uploadBandwidthThrottler->GetNumberOfSentBytesSinceLastCallAndReset();
	avarage_dr_list.AddTail(sentBytes);
    m_avarage_dr_sum += sentBytes;

    (void)theApp.uploadBandwidthThrottler->GetNumberOfSentBytesOverheadSinceLastCallAndReset();

    avarage_friend_dr_list.AddTail(theStats.sessionSentBytesToFriend);

    // Save time between each speed snapshot
    avarage_tick_list.AddTail(curTick);

    // don't save more than 30 secs of data
    while(avarage_tick_list.GetCount() > 3 
		&& !avarage_friend_dr_list.IsEmpty() 
		&& curTick-avarage_tick_list.GetHead() > 30*1000) {
   	    m_avarage_dr_sum -= avarage_dr_list.RemoveHead();
        avarage_friend_dr_list.RemoveHead();
        avarage_tick_list.RemoveHead();
    }

	if (GetDatarate() > HIGHSPEED_UPLOADRATE_START && m_hHighSpeedUploadTimer == 0)
		UseHighSpeedUploadTimer(true);
	else if (GetDatarate() < HIGHSPEED_UPLOADRATE_END && m_hHighSpeedUploadTimer != 0)
		UseHighSpeedUploadTimer(false);
//>>> Spike2::L2HAC [enkeyDEV]
	static DWORD dwLastL2HACCheck = ::GetTickCount();
	if (theApp.IsFirewalled()
		&& curTick - dwLastL2HACCheck > MIN2MS(1)) //do not check TOO often... parsing the whole waitinglist is expensive!
	{
		dwLastL2HACCheck = curTick;
		for (POSITION pos = waitinglist.GetHeadPosition(); pos;)
		{
			CUpDownClient* cur_client = waitinglist.GetNext(pos);
			if (cur_client->IsL2HACEnabled()
				&& cur_client->GetLastL2HACExecution()
				//&& cur_client->GetL2HACTime() // this is already checked in AddClientToQueue
				&& (curTick - cur_client->GetLastL2HACExecution()) > cur_client->GetL2HACTime())
			{
				if (theApp.listensocket->TooManySockets() && !(cur_client->socket && cur_client->socket->IsConnected()) )
					cur_client->SetLastL2HACExecution(curTick - cur_client->GetL2HACTime() + (uint32)ROUND(((float)rand()/RAND_MAX)*300000));
				else
				{
					cur_client->EnableL2HAC(false);
					//if (!cur_client->HasLowID() && cur_client->GetL2HACTime()) // this is already checked in AddClientToQueue
					cur_client->TryToConnect();
				}
			}
		}
	}
//<<< Spike2::L2HAC [enkeyDEV]
};

bool CUploadQueue::AcceptNewClient(bool addOnNextConnect)
{
	uint32 curUploadSlots = (uint32)uploadinglist.GetCount();

	//We allow ONE extra slot to be created to accommodate lowID users.
	//This is because we skip these users when it was actually their turn
	//to get an upload slot..
	if(curUploadSlots == 0) //return true straight away
		return true;

	if(addOnNextConnect && curUploadSlots > 0)
		curUploadSlots--;		

    return AcceptNewClient(curUploadSlots);
}

bool CUploadQueue::AcceptNewClient(uint32 curUploadSlots){
#ifdef CLIENTANALYZER
	if (curUploadSlots < MIN_UP_CLIENTS_ALLOWED)
	{
		m_uiFellBelowSlotsNeeded = 0; //>>> Add2Up Timer - reset
		return true;
	}

	const DWORD dwCurTick = ::GetTickCount();
	const UINT MaxSpeed = (UINT)(thePrefs.IsDynUpEnabled()?theApp.lastCommonRouteFinder->GetUpload():thePrefs.GetMaxUpload()*1024);
	if(dwCurTick - m_nLastStartUpload < MIN_NEXTSLOT_WAITTIME
		|| curUploadSlots >= MAX_UP_CLIENTS_ALLOWED
		|| curUploadSlots * 3072 >= MaxSpeed) //hard coded final limit
	{
		m_uiFellBelowSlotsNeeded = 0; //>>> Add2Up Timer - reset
		return false;
	}

//>>> TRICKLE ORIENTATION
	//length minus active equals the trickle slot count
	UINT curTrickles = 0;
	if((UINT)GetUploadQueueLength() > GetActiveUploadsCount()) //could there be something wrong?
		curTrickles = GetUploadQueueLength() - GetActiveUploadsCount();

	//if we have no trickle slots then we know that not all BW is used up...
	//so I try to estimate the needed trickles and check for them instead to use "fixed" values
	UINT WantedTrickles = 0;
	const UINT datarate = GetDatarate();
	if(datarate < 25600) //less then 25k UL? use 1 trickle...
		WantedTrickles = 1;
	else if(datarate < 102400) //less then 100k UL? use 1 per 25kB
		WantedTrickles = datarate/25600;
	else //really high UL! use 1 per 35kB
		WantedTrickles = datarate/35840;

	//check for slot focus... as speed is concentrated we need more trickles...
//	if(thePrefs.GetClientDataRate() == 0)
//		++WantedTrickles;

	if(curTrickles < WantedTrickles)
	{
		//we do not return true but instead set our timer here
		if(!m_uiFellBelowSlotsNeeded)
		{
			m_uiFellBelowSlotsNeeded = dwCurTick+UPLOAD_RETALIATIONTIME; //give up to UPLOAD_RETALIATIONTIME to regain speed
			return false;
		}
		//only add to up if X seconds passed and still a new slot is requested
		else if(dwCurTick > m_uiFellBelowSlotsNeeded)
		{
			m_uiFellBelowSlotsNeeded = 0; //>>> Add2Up Timer - reset
			return true;
		}
		//otherwise... nope, not yet ;)
		return false;
	}
	//otherwise... nope, not yet ;)
	m_uiFellBelowSlotsNeeded = 0;
	return false;
//<<< TRICKLE ORIENTATION
#else
	// check if we can allow a new client to start downloading from us

	if (curUploadSlots < MIN_UP_CLIENTS_ALLOWED)
		return true;

	uint16 MaxSpeed;
    if (thePrefs.IsDynUpEnabled())
        MaxSpeed = (uint16)(theApp.lastCommonRouteFinder->GetUpload()/1024);
    else
		MaxSpeed = thePrefs.GetMaxUpload();
	
	if (curUploadSlots >= MAX_UP_CLIENTS_ALLOWED ||
        curUploadSlots >= 4 &&
        (
         curUploadSlots >= (datarate/UPLOAD_CHECK_CLIENT_DR) ||
         curUploadSlots >= ((uint32)MaxSpeed)*1024/UPLOAD_CLIENT_DATARATE ||
         (
          thePrefs.GetMaxUpload() == UNLIMITED &&
          !thePrefs.IsDynUpEnabled() &&
          thePrefs.GetMaxGraphUploadRate(true) > 0 &&
          curUploadSlots >= ((uint32)thePrefs.GetMaxGraphUploadRate(false))*1024/UPLOAD_CLIENT_DATARATE
         )
        )
    ) // max number of clients to allow for all circumstances
	    return false;

	return true;
#endif
}

bool CUploadQueue::ForceNewClient(bool allowEmptyWaitingQueue) {
    if(!allowEmptyWaitingQueue && waitinglist.IsEmpty())
        return false;

#ifdef CLIENTANALYZER
	if(::GetTickCount() - m_nLastStartUpload < MIN_NEXTSLOT_WAITTIME_LOW)
#else
	if (::GetTickCount() - m_nLastStartUpload < 1000 && datarate < 102400 )
#endif
		return false;

#ifdef CLIENTANALYZER
	//try to use the proper function... seems to be too complicated for me... :)
	if(!theApp.lastCommonRouteFinder->AcceptNewClient())  // UploadSpeedSense can veto a new slot if USS enabled
		return false;
	return AcceptNewClient();
#else
	uint32 curUploadSlots = (uint32)uploadinglist.GetCount();

	if (curUploadSlots < MIN_UP_CLIENTS_ALLOWED)
		return true;

    if(!AcceptNewClient(curUploadSlots) || !theApp.lastCommonRouteFinder->AcceptNewClient()) { // UploadSpeedSense can veto a new slot if USS enabled
		return false;
    }

	uint16 MaxSpeed;
    if (thePrefs.IsDynUpEnabled())
        MaxSpeed = (uint16)(theApp.lastCommonRouteFinder->GetUpload()/1024);
    else
		MaxSpeed = thePrefs.GetMaxUpload();

	uint32 upPerClient = UPLOAD_CLIENT_DATARATE;

    // if throttler doesn't require another slot, go with a slightly more restrictive method
	if( MaxSpeed > 20 || MaxSpeed == UNLIMITED)
		upPerClient += datarate/43;

	if( upPerClient > 7680 )
		upPerClient = 7680;

	//now the final check

	if ( MaxSpeed == UNLIMITED )
	{
		if (curUploadSlots < (datarate/upPerClient))
			return true;
	}
	else{
		uint16 nMaxSlots;
		if (MaxSpeed > 12)
			nMaxSlots = (uint16)(((float)(MaxSpeed*1024)) / upPerClient);
		else if (MaxSpeed > 7)
			nMaxSlots = MIN_UP_CLIENTS_ALLOWED + 2;
		else if (MaxSpeed > 3)
			nMaxSlots = MIN_UP_CLIENTS_ALLOWED + 1;
		else
			nMaxSlots = MIN_UP_CLIENTS_ALLOWED;
//		AddLogLine(true,"maxslots=%u, upPerClient=%u, datarateslot=%u|%u|%u",nMaxSlots,upPerClient,datarate/UPLOAD_CHECK_CLIENT_DR, datarate, UPLOAD_CHECK_CLIENT_DR);

		if ( curUploadSlots < nMaxSlots )
		{
			return true;
		}
	}

    if(m_iHighestNumberOfFullyActivatedSlotsSinceLastCall > (uint32)uploadinglist.GetSize()) {
        // uploadThrottler requests another slot. If throttler says it needs another slot, we will allow more slots
        // than what we require ourself. Never allow more slots than to give each slot high enough average transfer speed, though (checked above).
        //if(thePrefs.GetLogUlDlEvents() && waitinglist.GetSize() > 0)
        //    AddDebugLogLine(false, _T("UploadQueue: Added new slot since throttler needs it. m_iHighestNumberOfFullyActivatedSlotsSinceLastCall: %i uploadinglist.GetSize(): %i tick: %i"), m_iHighestNumberOfFullyActivatedSlotsSinceLastCall, uploadinglist.GetSize(), ::GetTickCount());
        return true;
    }

    //nope
	return false;
#endif
}

CUpDownClient* CUploadQueue::GetWaitingClientByIP_UDP(uint32 dwIP, uint16 nUDPPort, bool bIgnorePortOnUniqueIP, bool* pbMultipleIPs){
	CUpDownClient* pMatchingIPClient = NULL;
	uint32 cMatches = 0;
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;){
		CUpDownClient* cur_client = waitinglist.GetNext(pos);
		if (dwIP == cur_client->GetIP() && nUDPPort == cur_client->GetUDPPort())
			return cur_client;
		else if (dwIP == cur_client->GetIP() && bIgnorePortOnUniqueIP){
			pMatchingIPClient = cur_client;
			cMatches++;
		}
	}
	if (pbMultipleIPs != NULL)
		*pbMultipleIPs = cMatches > 1;

	if (pMatchingIPClient != NULL && cMatches == 1)
		return pMatchingIPClient;
	else
		return NULL;
}

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

/**
 * Add a client to the waiting queue for uploads.
 *
 * @param client address of the client that should be added to the waiting queue
 *
 * @param bIgnoreTimelimit don't check time limit to possibly ban the client.
 */
void CUploadQueue::AddClientToQueue(CUpDownClient* client, bool bIgnoreTimelimit)
{
	//This is to keep users from abusing the limits we put on lowID callbacks.
	//1)Check if we are connected to any network and that we are a lowID.
	//(Although this check shouldn't matter as they wouldn't have found us..
	// But, maybe I'm missing something, so it's best to check as a precaution.)
	//2)Check if the user is connected to Kad. We do allow all Kad Callbacks.
	//3)Check if the user is in our download list or a friend..
	//We give these users a special pass as they are helping us..
	//4)Are we connected to a server? If we are, is the user on the same server?
	//TCP lowID callbacks are also allowed..
	//5)If the queue is very short, allow anyone in as we want to make sure
	//our upload is always used.
	if (theApp.IsConnected() 
		&& theApp.IsFirewalled()
		&& !client->GetKadPort()
		&& client->GetDownloadState() == DS_NONE 
		&& !client->IsFriend()
		&& theApp.serverconnect
		&& !theApp.serverconnect->IsLocalServer(client->GetServerIP(),client->GetServerPort())
		&& GetWaitingUserCount() > 50)
		return;
	client->AddAskedCount();
	client->SetLastUpRequest();

#ifdef CLIENTANALYZER
//>>> WiZaRd::ClientAnalyzer
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(client->GetUploadFileID());
	if(reqfile == NULL)
		return; //should never happen, just in case, though...
	if(client->GetRequestFile() == reqfile && client->IsCompleteSource())
	{
		if(client->GetAntiLeechData())
			client->GetAntiLeechData()->SetBadForThisSession(AT_FILEFAKER);
		return; //nope - come back later...
	}
//<<< WiZaRd::ClientAnalyzer
#endif

	if (!bIgnoreTimelimit)
		client->AddRequestCount(client->GetUploadFileID());
	if (client->IsBanned())
		return;

//>>> Spike2::L2HAC [enkeyDEV]
	client->SetLastL2HACExecution();
	if (!client->HasLowID() && client->GetL2HACSupport()) 
		client->EnableL2HAC(true);
//<<< Spike2::L2HAC [enkeyDEV]

//>>> WiZaRd::FiX
	//moved here... that way we count the request even in case of an eary return (but still not if the request comes from a banned client)
	// statistic values
#ifndef CLIENTANALYZER
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->GetUploadFileID());
	if (reqfile)
#endif	
		reqfile->statistic.AddRequest();
//<<< WiZaRd::FiX

	uint16 cSameIP = 0;
	// check for double
	POSITION pos1, pos2;
	for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;)
	{
		waitinglist.GetNext(pos1);
		CUpDownClient* cur_client= waitinglist.GetAt(pos2);
		if (cur_client == client)
		{	
			if (client->m_bAddNextConnect && AcceptNewClient(client->m_bAddNextConnect))
			{
				//Special care is given to lowID clients that missed their upload slot
				//due to the saving bandwidth on callbacks.
				if(thePrefs.GetLogUlDlEvents())
					AddDebugLogLine(true, _T("Adding ****lowid when reconnecting. Client: %s"), client->DbgGetClientInfo());
				client->m_bAddNextConnect = false;
				RemoveFromWaitingQueue(client, true);
				// statistic values // TODO: Maybe we should change this to count each request for a file only once and ignore reasks
#ifndef CLIENTANALYZER
				CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->GetUploadFileID());
				if (reqfile)
					reqfile->statistic.AddRequest();
#endif
				AddUpNextClient(_T("Adding ****lowid when reconnecting."), client);
				return;
			}
			client->SendRankingInfo();
			theApp.emuledlg->transferwnd->GetQueueList()->RefreshClient(client);
			return;			
		}
		else if ( client->Compare(cur_client) ) 
		{
			theApp.clientlist->AddTrackClient(client); // in any case keep track of this client

			// another client with same ip:port or hash
			// this happens only in rare cases, because same userhash / ip:ports are assigned to the right client on connecting in most cases
			if (cur_client->credits != NULL && cur_client->credits->GetCurrentIdentState(cur_client->GetIP()) == IS_IDENTIFIED)
			{
				//cur_client has a valid secure hash, don't remove him
				if (thePrefs.GetVerbose())
					AddDebugLogLine(false, GetResString(IDS_SAMEUSERHASH), client->GetUserName(), cur_client->GetUserName(), client->GetUserName());
				return;
			}
			if (client->credits != NULL && client->credits->GetCurrentIdentState(client->GetIP()) == IS_IDENTIFIED)
			{
				//client has a valid secure hash, add him remove other one
				if (thePrefs.GetVerbose())
					AddDebugLogLine(false, GetResString(IDS_SAMEUSERHASH), client->GetUserName(), cur_client->GetUserName(), cur_client->GetUserName());
				RemoveFromWaitingQueue(pos2,true);
				if (!cur_client->socket)
				{
					if(cur_client->Disconnected(_T("AddClientToQueue - same userhash 1")))
						delete cur_client;
				}
			}
			else
			{
				// remove both since we do not know who the bad one is
				if (thePrefs.GetVerbose())
					AddDebugLogLine(false, GetResString(IDS_SAMEUSERHASH), client->GetUserName() ,cur_client->GetUserName(), _T("Both"));
				RemoveFromWaitingQueue(pos2,true);	
				if (!cur_client->socket)
				{
					if(cur_client->Disconnected(_T("AddClientToQueue - same userhash 2")))
						delete cur_client;
				}
				return;
			}
		}
		else if (client->GetIP() == cur_client->GetIP())
		{
			// same IP, different port, different userhash
			cSameIP++;
		}
	}
	if (cSameIP >= 3)
	{
		// do not accept more than 3 clients from the same IP
		if (thePrefs.GetVerbose())
			DEBUG_ONLY( AddDebugLogLine(false,_T("%s's (%s) request to enter the queue was rejected, because of too many clients with the same IP"), client->GetUserName(), ipstr(client->GetConnectIP())) );
		return;
	}
	else if (theApp.clientlist->GetClientsFromIP(client->GetIP()) >= 3)
	{
		if (thePrefs.GetVerbose())
			DEBUG_ONLY( AddDebugLogLine(false,_T("%s's (%s) request to enter the queue was rejected, because of too many clients with the same IP (found in TrackedClientsList)"), client->GetUserName(), ipstr(client->GetConnectIP())) );
		return;
	}
	// done

//>>> WiZaRd::FiX 
	//moved up!
//	// statistic values // TODO: Maybe we should change this to count each request for a file only once and ignore reasks
//#ifndef CLIENTANALYZER
//	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->GetUploadFileID());
//	if (reqfile)
//#endif
//		reqfile->statistic.AddRequest();
//<<< WiZaRd::FiX

	// emule collection will bypass the queue
//>>> WiZaRd::Small File Slot
	if(reqfile && reqfile->GetFileSize() < (uint64)MAXPRIORITYCOLL_SIZE) //i.e. 50kB)
//	if (reqfile != NULL && CCollection::HasCollectionExtention(reqfile->GetFileName()) && reqfile->GetFileSize() < (uint64)MAXPRIORITYCOLL_SIZE
//		&& !client->IsDownloading() && client->socket != NULL && client->socket->IsConnected())
	{
//>>> WiZaRd::Small File Slot
//		client->SetCollectionUploadSlot(true);
//<<< WiZaRd::Small File Slot
		RemoveFromWaitingQueue(client, true);
//>>> WiZaRd::Small File Slot
		AddUpNextClient(L"Small File Priority Slot", client);
//		AddUpNextClient(_T("Collection Priority Slot"), client);
//<<< WiZaRd::Small File Slot
		return;
	}
//>>> WiZaRd::Small File Slot
//	else
//		client->SetCollectionUploadSlot(false);
//<<< WiZaRd::Small File Slot

   // cap the list
    // the queue limit in prefs is only a soft limit. Hard limit is 25% higher, to let in powershare clients and other
    // high ranking clients after soft limit has been reached
#ifdef CLIENTANALYZER
//>>> WiZaRd::QueueSize FiX
	//this makes eMule to keep the PROPER limit that is set via preferences
	//by default: 
	//softlimit = pref-limit
	//hardlimit = soft + 25% of soft but at least 200
	//now (fixed):	
	//hardlimit = preflimit
	//softlimit = 80% of hard but at least 200
	uint32 hardQueueLimit = thePrefs.GetQueueSize();
	uint32 softQueueLimit = (uint32)(thePrefs.GetQueueSize()*0.8f);
	if(hardQueueLimit - softQueueLimit < 200)
		softQueueLimit = hardQueueLimit-200;    
//<<< WiZaRd::QueueSize FiX
#else
    uint32 softQueueLimit = thePrefs.GetQueueSize();
    uint32 hardQueueLimit = thePrefs.GetQueueSize() + max(thePrefs.GetQueueSize()/4, 200);
#endif

    // if soft queue limit has been reached, only let in high ranking clients
	if (!thePrefs.IsInfiniteQueueEnabled())//>>> shadow2004::InfiniteQueue [SLUGFILLER]
    if ((uint32)waitinglist.GetCount() >= hardQueueLimit ||
        (uint32)waitinglist.GetCount() >= softQueueLimit && // soft queue limit is reached
        (client->IsFriend() && client->GetFriendSlot()) == false && // client is not a friend with friend slot
        client->GetCombinedFilePrioAndCredit() < GetAverageCombinedFilePrioAndCredit()) { // and client has lower credits/wants lower prio file than average client in queue

        // then block client from getting on queue
		return;
	}
	if (client->IsDownloading())
	{
//>>> taz::Don't allow file hot swapping [Xman/idea Maella]
		if (client->GetRequestFile())
		{
			RemoveFromUploadQueue(client, L"already downloading from us and no hot swapping", true);
			if (client->GetRequestFile() != reqfile)
			{
				// real swap attemp ===> friendly "kick"
				if (thePrefs.GetVerbose())
					AddDebugLogLine(DLP_DEFAULT, true, L"asking for %s while downloading %s", reqfile->GetFileName(), client->GetRequestFile()->GetFileName());
				client->SendOutOfPartReqsAndAddToWaitingQueue();
				client->SetWaitStartTime(); // soft "punish"
			}
//>>> taz::queue bypass
// this is a false call for getting in queue - therefore a bad UL attempt
// not real punishment unless this client is always trying - otherwise counter will get "0"ed on 1'st "regular" UL session complete
#ifdef CLIENTANALYZER
			if(client->GetAntiLeechData())
				client->GetAntiLeechData()->AddULSession(true);
#endif
//<<< taz::queue bypass
			return;
		}
		else // fairness : we no longer share the file that was downloaded
		{
		// he's already downloading and wants probably only another file
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__AcceptUploadReq", client);
		Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
		theStats.AddUpDataOverheadFileRequest(packet->size);
		client->SendPacket(packet, true);
		return;
		}
//<<< taz::Don't allow file hot swapping [Xman/idea Maella]
	}
//>>> WiZaRd::Startup Flood Prevention
	//Requested by James R. Bath
	//http://forum.emule-project.net/index.php?showtopic=101181
/*
	if (waitinglist.IsEmpty() && ForceNewClient(true))
	{
		AddUpNextClient(_T("Direct add with empty queue."), client);
	}
	else
*/
//<<< WiZaRd::Startup Flood Prevention
	{
		m_bStatisticsWaitingListDirty = true;
		waitinglist.AddTail(client);
		client->SetUploadState(US_ONUPLOADQUEUE);
		theApp.emuledlg->transferwnd->GetQueueList()->AddClient(client,true);
//		theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
		theApp.emuledlg->transferwnd->ShowQueueCount();
		client->SendRankingInfo();
	}
}

float CUploadQueue::GetAverageCombinedFilePrioAndCredit() {
    DWORD curTick = ::GetTickCount();

    if (curTick - m_dwLastCalculatedAverageCombinedFilePrioAndCredit > 5*1000) {
        m_dwLastCalculatedAverageCombinedFilePrioAndCredit = curTick;

        // TODO: is there a risk of overflow? I don't think so...
        double sum = 0;
	    for (POSITION pos = waitinglist.GetHeadPosition(); pos != NULL; /**/){
		    CUpDownClient* cur_client =	waitinglist.GetNext(pos);
            sum += cur_client->GetCombinedFilePrioAndCredit();
        }
        m_fAverageCombinedFilePrioAndCredit = (float)(sum/waitinglist.GetSize());
    }

    return m_fAverageCombinedFilePrioAndCredit;
}

bool CUploadQueue::RemoveFromUploadQueue(CUpDownClient* client, LPCTSTR pszReason, bool updatewindow, bool earlyabort){
    bool result = false;
    uint32 slotCounter = 1;
//>>> WiZaRd::Payback First
	POSITION findPos = m_lPaybackList.Find(client);
	if(findPos)
		m_lPaybackList.RemoveAt(findPos);
//<<< WiZaRd::Payback First
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;){
        POSITION curPos = pos;
        CUpDownClient* curClient = uploadinglist.GetNext(pos);
		if (client == curClient){
			if (updatewindow)
				theApp.emuledlg->transferwnd->GetUploadList()->RemoveClient(client);

			if (thePrefs.GetLogUlDlEvents())
                AddDebugLogLine(DLP_DEFAULT, true,_T("Removing client from upload list: %s Client: %s Transferred: %s SessionUp: %s QueueSessionPayload: %s In buffer: %s Req blocks: %i File: %s"), pszReason==NULL ? _T("") : pszReason, client->DbgGetClientInfo(), CastSecondsToHM( client->GetUpStartTimeDelay()/1000), CastItoXBytes(client->GetSessionUp(), false, false), CastItoXBytes(client->GetQueueSessionPayloadUp(), false, false), CastItoXBytes(client->GetPayloadInBuffer()), client->GetNumberOfRequestedBlocksInQueue(), (theApp.sharedfiles->GetFileByID(client->GetUploadFileID())?theApp.sharedfiles->GetFileByID(client->GetUploadFileID())->GetFileName():_T("")));
            client->m_bAddNextConnect = false;
			uploadinglist.RemoveAt(curPos);

            bool removed = theApp.uploadBandwidthThrottler->RemoveFromStandardList(client->socket);
			(void)removed;
            //if(thePrefs.GetLogUlDlEvents() && !(removed || pcRemoved)) {
            //    AddDebugLogLine(false, _T("UploadQueue: Didn't find socket to delete. Adress: 0x%x"), client->socket);
            //}

			if(client->GetSessionUp() > 0) {
#ifdef CLIENTANALYZER
				if(client->pAntiLeechData)
					client->pAntiLeechData->AddULSession(false);
#endif
				++successfullupcount;
				totaluploadtime += client->GetUpStartTimeDelay()/1000;
            } else if(earlyabort == false)
			{
#ifdef CLIENTANALYZER
				if(client->pAntiLeechData)
					client->pAntiLeechData->AddULSession(true);
#endif
				++failedupcount;
			}

            CKnownFile* requestedFile = theApp.sharedfiles->GetFileByID(client->GetUploadFileID());
            if(requestedFile != NULL) {
                requestedFile->UpdatePartsInfo();
            }
			theApp.clientlist->AddTrackClient(client); // Keep track of this client
			client->SetUploadState(US_NONE);
			client->ClearUploadBlockRequests();
//>>> WiZaRd::Small File Slot
			//client->SetCollectionUploadSlot(false);
//<<< WiZaRd::Small File Slot

            m_iHighestNumberOfFullyActivatedSlotsSinceLastCall = 0;

			result = true;
        } else {
            curClient->SetSlotNumber(slotCounter);
            slotCounter++;
        }
	}
	return result;
}

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);
		return true;
	}
	else
		return false;
}

void CUploadQueue::RemoveFromWaitingQueue(POSITION pos, bool updatewindow){	
	m_bStatisticsWaitingListDirty = true;
	CUpDownClient* todelete = waitinglist.GetAt(pos);
	waitinglist.RemoveAt(pos);
	if (updatewindow) {
		theApp.emuledlg->transferwnd->GetQueueList()->RemoveClient(todelete);
//		theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
		theApp.emuledlg->transferwnd->ShowQueueCount();		
	}
	todelete->m_bAddNextConnect = false;
	todelete->SetUploadState(US_NONE);
}

void CUploadQueue::UpdateMaxClientScore()
{
	m_imaxscore=0;
	for(POSITION pos = waitinglist.GetHeadPosition(); pos != 0; ) {
		uint32 score = waitinglist.GetNext(pos)->GetScore(true, false);
		if(score > m_imaxscore )
			m_imaxscore=score;
	}
}

bool CUploadQueue::CheckForTimeOver(CUpDownClient* client){
	//If we have nobody in the queue, do NOT remove the current uploads..
	//This will save some bandwidth and some unneeded swapping from upload/queue/upload..
#ifndef CLIENTANALYZER
// VQB: fullChunk
//	if ( waitinglist.IsEmpty() || client->GetFriendSlot() )
//		return false;
// VQB: fullChunk
#endif
	
//>>> WiZaRd::Small File Slot
/*
	if(client->HasCollectionUploadSlot())
	{
		CKnownFile* pDownloadingFile = theApp.sharedfiles->GetFileByID(client->requpfileid);
		if(pDownloadingFile == NULL)
			return true;
		if (CCollection::HasCollectionExtention(pDownloadingFile->GetFileName()) && pDownloadingFile->GetFileSize() < (uint64)MAXPRIORITYCOLL_SIZE)
			return false;
		else{
			if (thePrefs.GetLogUlDlEvents())
				AddDebugLogLine(DLP_HIGH, false, _T("%s: Upload session ended - client with Collection Slot tried to request blocks from another file"), client->GetUserName());
			return true;
		}
	}
*/
//<<< WiZaRd::Small File Slot
	
#ifdef CLIENTANALYZER
	if(/*!client->GetFriendSlot() && */client->GetRemainingUp() <= 0) 	// VQB: fullChunk
	{
		if (thePrefs.GetLogUlDlEvents())
			AddDebugLogLine(DLP_DEFAULT, false, _T("%s: Upload session ended due to max transferred amount - uploaded: %s"), client->GetUserName(), CastItoXBytes(client->GetSessionUp(), false, false));
		return true;
	}
#else
	if (!thePrefs.TransferFullChunks()){
	    if( client->GetUpStartTimeDelay() > SESSIONMAXTIME){ // Try to keep the clients from downloading for ever
		    if (thePrefs.GetLogUlDlEvents())
			    AddDebugLogLine(DLP_LOW, false, _T("%s: Upload session ended due to max time %s."), client->GetUserName(), CastSecondsToHM(SESSIONMAXTIME/1000));
		    return true;
	    }

		// Cache current client score
		const uint32 score = client->GetScore(true, true);

		// Check if another client has a bigger score
		if (score < GetMaxClientScore() && m_dwRemovedClientByScore < GetTickCount()) {
			if (thePrefs.GetLogUlDlEvents())
				AddDebugLogLine(DLP_VERYLOW, false, _T("%s: Upload session ended due to score."), client->GetUserName());
			//Set timer to prevent to many uploadslot getting kick do to score.
			//Upload slots are delayed by a min of 1 sec and the maxscore is reset every 5 sec.
			//So, I choose 6 secs to make sure the maxscore it updated before doing this again.
			m_dwRemovedClientByScore = GetTickCount()+SEC2MS(6);
			return true;
		}
	}
	else{
		// Allow the client to download a specified amount per session
		if( client->GetQueueSessionPayloadUp() > SESSIONMAXTRANS ){
			if (thePrefs.GetLogUlDlEvents())
				AddDebugLogLine(DLP_DEFAULT, false, _T("%s: Upload session ended due to max transferred amount. %s"), client->GetUserName(), CastItoXBytes(SESSIONMAXTRANS, false, false));
			return true;
		}
	}
#endif
	return false;
}

void CUploadQueue::DeleteAll(){
	waitinglist.RemoveAll();
	uploadinglist.RemoveAll();
    // PENDING: Remove from UploadBandwidthThrottler as well!
}

UINT CUploadQueue::GetWaitingPosition(CUpDownClient* client)
{
	if (!IsOnUploadQueue(client))
		return 0;
	UINT rank = 1;
	const UINT myscore = client->GetScore(false);
//>>> taz::One-queue-per-file [Maella (idea bloodymad)]
/* shorter but problematic on transition with long upload queue
	for (POSITION pos = waitinglist.GetHeadPosition(); pos != NULL; ){
		CUpDownClient* pOtherClient = waitinglist.GetNext(pos);
		if ((!thePrefs.GetEnableMultiQueue() || md4cmp(client->GetUploadFileID(), pOtherClient->GetUploadFileID()) == 0) && pOtherClient->GetScore(false) > myscore)
			rank++;
	}
*/
	if (thePrefs.GetEnableMultiQueue())
		for (POSITION pos = waitinglist.GetHeadPosition(); pos != 0; ){
			// Compare score only with others clients waiting for the same file
			CUpDownClient* pOtherClient = waitinglist.GetNext(pos);
			if(md4cmp(client->GetUploadFileID(), pOtherClient->GetUploadFileID()) == 0 && pOtherClient->GetScore(false) > myscore)
				rank++;
		}
	else
//<<< taz::One-queue-per-file [Maella (idea bloodymad)]
	for (POSITION pos = waitinglist.GetHeadPosition(); pos != 0; ){
		if (waitinglist.GetNext(pos)->GetScore(false) > myscore)
			rank++;
	}
	return rank;
}

VOID CALLBACK CUploadQueue::UploadTimer(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR /*idEvent*/, DWORD /*dwTime*/)
{
	// NOTE: Always handle all type of MFC exceptions in TimerProcs - otherwise we'll get mem leaks
	try
	{
		// Barry - Don't do anything if the app is shutting down - can cause unhandled exceptions
		if (!theApp.emuledlg->IsRunning())
			return;

		const DWORD curTick = ::GetTickCount(); //cache it...

		// ZZ:UploadSpeedSense -->
		theApp.lastCommonRouteFinder->SetPrefs(thePrefs.IsDynUpEnabled(), 
			theApp.uploadqueue->GetDatarate(), 
			thePrefs.GetMinUpload()*1024, 
			(thePrefs.GetMaxUpload() != 0) ? thePrefs.GetMaxUpload() * 1024 : thePrefs.GetMaxGraphUploadRate(false) * 1024, 
			thePrefs.IsDynUpUseMillisecondPingTolerance(), 
			(thePrefs.GetDynUpPingTolerance() > 100) ? ((thePrefs.GetDynUpPingTolerance() - 100) / 100.0f) : 0, 
			thePrefs.GetDynUpPingToleranceMilliseconds(), 
			thePrefs.GetDynUpGoingUpDivider(), 
			thePrefs.GetDynUpGoingDownDivider(), 
			thePrefs.GetDynUpNumberOfPings(), 
			20); // PENDING: Hard coded min pLowestPingAllowed
		// ZZ:UploadSpeedSense <--

        theApp.uploadqueue->Process();
		theApp.downloadqueue->Process();

//>>> Spike2::ConChecker [eWombat]
			theApp.conchecker.Process(curTick);
//<<< Spike2::ConChecker [eWombat]

			// Elandal:ThreadSafeLogging -->
			// other threads may have queued up log lines. This prints them.
			theApp.HandleLogQueues();
//			theApp.HandleDebugLogQueue();
//			theApp.HandleLogQueue();			
			// Elandal: ThreadSafeLogging <--

		if (thePrefs.ShowOverhead()){
			theStats.CompUpDatarateOverhead();
			theStats.CompDownDatarateOverhead();
		}
		counter++;

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

//>>> WiZaRd::ResourceBars
			//update every second... this saves the timers and we can still handle different update intervals 
			//by using the passed "curTick" - if necessary, that is :)
			theApp.emuledlg->transferwnd->UpdateProgressBars(curTick); 
//<<< WiZaRd::ResourceBars

			// try to use different time intervals here to not create any disk-IO bottle necks by saving all files at once
			theApp.clientcredits->Process();	// 13 minutes
			theApp.serverlist->Process();		// 17 minutes
			theApp.knownfiles->Process();		// 11 minutes
#ifdef CLIENTANALYZER
			theApp.antileechlist->Process();	// 18 minutes  //>>> WiZaRd::ClientAnalyzer
#endif
			theApp.friendlist->Process();		// 19 minutes
			theApp.clientlist->Process();
			theApp.sharedfiles->Process();
			if( Kademlia::CKademlia::IsRunning() )
			{
				Kademlia::CKademlia::Process();
				if(Kademlia::CKademlia::GetPrefs()->HasLostConnection())
				{
					Kademlia::CKademlia::Stop();
					theApp.emuledlg->ShowConnectionState();
				}
			}
			if( theApp.serverconnect->IsConnecting() && !theApp.serverconnect->IsSingleConnect() )
				theApp.serverconnect->TryAnotherConnectionRequest();

			theApp.listensocket->UpdateConnectionsStatus();
			if (thePrefs.WatchClipboard4ED2KLinks()) {
				// TODO: Remove this from here. This has to be done with a clipboard chain
				// and *not* with a timer!!
				theApp.SearchClipboard();
			}

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

			// 2 seconds
			i2Secs++;
			if (i2Secs>=2) {
				i2Secs=0;
				
				// Update connection stats...
				theStats.UpdateConnectionStats((float)theApp.uploadqueue->GetDatarate()/1024, (float)theApp.downloadqueue->GetDatarate()/1024);

#ifdef HAVE_WIN7_SDK_H
				if (thePrefs.IsWin7TaskbarGoodiesEnabled())
					theApp.emuledlg->UpdateStatusBarProgress();
#endif

			}

			// display graphs
			if (thePrefs.GetTrafficOMeterInterval()>0) {
				igraph++;

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

					if (istats >= (uint32)(thePrefs.GetStatsInterval()) ) {
						istats=0;
						theApp.emuledlg->statisticswnd->ShowStatistics();
					}
				}
			}

            theApp.uploadqueue->UpdateDatarates();
            
            //save rates every second
			theStats.RecordRate();
			// mobilemule sockets
			theApp.mmserver->Process();

			// ZZ:UploadSpeedSense -->
            theApp.emuledlg->ShowPing();

             if(!theApp.clientlist->GiveClientsForTraceRoute()) {
                theApp.serverlist->GiveServersForTraceRoute();
            }
			// ZZ:UploadSpeedSense <--

			if (theApp.emuledlg->IsTrayIconToFlash())
				theApp.emuledlg->ShowTransferRate(true);

            sec++;
			// *** 5 seconds **********************************************
			if (sec >= 5) {
#ifdef _DEBUG
				if (thePrefs.m_iDbgHeap > 0 && !AfxCheckMemory())
					AfxDebugBreak();
#endif

				sec = 0;
				theApp.listensocket->Process();
				theApp.OnlineSig(); // Added By Bouc7 
				if (!theApp.emuledlg->IsTrayIconToFlash())
					theApp.emuledlg->ShowTransferRate();

				thePrefs.EstimateMaxUploadCap(theApp.uploadqueue->GetDatarate()/1024);
				
//>>> WiZaRd::Automatic Firewalled Retries
				//15 retries = 30 mins!
#define MAX_FIREWALLED_RETRIES	15
				if(curTick - m_dwFirewalledTimer > MIN2MS(2))
				{
					m_dwFirewalledTimer = curTick;
					if(Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled())
					{
						if(m_iFirewalledRetries < MAX_FIREWALLED_RETRIES)
						{
							++m_iFirewalledRetries;
							theApp.QueueLogLineEx(LOG_WARNING, L"Rechecking firewalled status - try %u out of %u...", m_iFirewalledRetries, MAX_FIREWALLED_RETRIES);
							// Refresh der Portmappings ? [shadow2004]
							// some routers seems to loose the settings after a while
							Kademlia::CKademlia::RecheckFirewalled();
						}
						else if(m_iFirewalledRetries == MAX_FIREWALLED_RETRIES)
						{
							++m_iFirewalledRetries;
							theApp.QueueLogLineEx(LOG_ERROR, L"Rechecking firewalled status failed %u times - stopping checks...", MAX_FIREWALLED_RETRIES);
						}
					}
					else
						m_iFirewalledRetries = 0;
				}
//<<< WiZaRd::Automatic Firewalled Retries

#ifndef CLIENTANALYZER
				if (!thePrefs.TransferFullChunks())
					theApp.uploadqueue->UpdateMaxClientScore();
#endif

				// update cat-titles with downloadinfos only when needed
				if (thePrefs.ShowCatTabInfos() && 
					theApp.emuledlg->activewnd == theApp.emuledlg->transferwnd && 
					theApp.emuledlg->IsWindowVisible()) 
						theApp.emuledlg->transferwnd->UpdateCatTabTitles(false);
				
//                theApp.emuledlg->transferwnd->UpdateListCount(CTransferDlg::wnd2Uploading, -1);
				theApp.emuledlg->transferwnd->UpdateListCount(wnd2Uploading);
			}

			statsave++;
			// *** 60 seconds *********************************************
			if (statsave >= 60) {
				statsave=0;

				theApp.serverconnect->KeepConnectionAlive();

				if (thePrefs.GetPreventStandby())
					theApp.ResetStandByIdleTimer(); // Reset Windows idle standby timer if necessary
			}

			s_uSaveStatistics++;
			if (s_uSaveStatistics >= thePrefs.GetStatsSaveInterval())
			{
				s_uSaveStatistics = 0;
				thePrefs.SaveStats();
			}
		}

		// need more accuracy here. don't rely on the 'sec' and 'statsave' helpers.
		thePerfLog.LogSamples();
	}
	CATCH_DFLT_EXCEPTIONS(_T("CUploadQueue::UploadTimer"))
}

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

void CUploadQueue::UpdateDatarates() {
    // Calculate average datarate
    if(::GetTickCount()-m_lastCalculatedDataRateTick > 500) {
        m_lastCalculatedDataRateTick = ::GetTickCount();

        if(avarage_dr_list.GetSize() >= 2 && (avarage_tick_list.GetTail() > avarage_tick_list.GetHead())) {
	        datarate = (UINT)(((m_avarage_dr_sum - avarage_dr_list.GetHead())*1000) / (avarage_tick_list.GetTail() - avarage_tick_list.GetHead()));
            friendDatarate = (UINT)(((avarage_friend_dr_list.GetTail() - avarage_friend_dr_list.GetHead())*1000) / (avarage_tick_list.GetTail() - avarage_tick_list.GetHead()));
        }
    }
}

uint32 CUploadQueue::GetDatarate() {
    return datarate;
}

uint32 CUploadQueue::GetToNetworkDatarate() {
    if(datarate > friendDatarate) {
        return datarate - friendDatarate;
    } else {
        return 0;
    }
}

void CUploadQueue::ReSortUploadSlots(bool force) 
{
//>>> WiZaRd::PowerShare //>>> WiZaRd::SlotFocus
    DWORD curtick = ::GetTickCount();
    if(uploadinglist.GetCount() < 2
		|| (!force && curtick - m_dwLastResortedUploadSlots <= 10*1000)) //>>> taz::fix activated slots
		return;

    m_dwLastResortedUploadSlots = curtick;

	theApp.uploadBandwidthThrottler->Pause(true);

	CTypedPtrList<CPtrList, CUpDownClient*> tempUploadinglist;

	// Remove all clients from uploading list and store in tempList
	while (!uploadinglist.IsEmpty())
//WiZaRd: this is not needed because we call InsertInUploadingList below which will call theApp.uploadBandwidthThrottler->AddToStandardList(posCounter, newclient->GetFileUploadSocket());
//Within that function, the proper socket (GetFileUploadSocket()) will be removed prior to adding it to the list!
		tempUploadinglist.AddTail(uploadinglist.RemoveHead());

	// Remove one at a time from temp list and reinsert in correct position in uploading list
	// This will insert in correct place
	while(!tempUploadinglist.IsEmpty()) 
		InsertInUploadingList(tempUploadinglist.RemoveHead());

	theApp.uploadBandwidthThrottler->Pause(false);
/*
	DWORD curtick = ::GetTickCount();
	if(force ||  curtick - m_dwLastResortedUploadSlots >= 10*1000) {
		m_dwLastResortedUploadSlots = curtick;

		theApp.uploadBandwidthThrottler->Pause(true);

		CTypedPtrList<CPtrList, CUpDownClient*> tempUploadinglist;

		// Remove all clients from uploading list and store in tempList
		POSITION ulpos = uploadinglist.GetHeadPosition();
		while (ulpos != NULL) {
			POSITION curpos = ulpos;
			uploadinglist.GetNext(ulpos);

			// Get and remove the client from upload list.
			CUpDownClient* cur_client = uploadinglist.GetAt(curpos);

			uploadinglist.RemoveAt(curpos);

			// Remove the found Client from UploadBandwidthThrottler
			theApp.uploadBandwidthThrottler->RemoveFromStandardList(cur_client->socket);

			tempUploadinglist.AddTail(cur_client);
		}

		// Remove one at a time from temp list and reinsert in correct position in uploading list
		POSITION tempPos = tempUploadinglist.GetHeadPosition();
		while(tempPos != NULL) {
			POSITION curpos = tempPos;
			tempUploadinglist.GetNext(tempPos);

			// Get and remove the client from upload list.
			CUpDownClient* cur_client = tempUploadinglist.GetAt(curpos);

			tempUploadinglist.RemoveAt(curpos);

			// This will insert in correct place
			InsertInUploadingList(cur_client);
		}

		theApp.uploadBandwidthThrottler->Pause(false);
	}
*/
//<<< WiZaRd::PowerShare //<<< WiZaRd::SlotFocus
}

void  CUploadQueue::UseHighSpeedUploadTimer(bool bEnable)
{
	if (!bEnable)
	{
		if (m_hHighSpeedUploadTimer != 0)
		{
			KillTimer(0, m_hHighSpeedUploadTimer);
			m_hHighSpeedUploadTimer = 0;
		}
	}
	else
	{
		if (m_hHighSpeedUploadTimer == 0)
			VERIFY( (m_hHighSpeedUploadTimer = SetTimer(0 ,0 , 1, HSUploadTimer)) != 0 );
	}
	DebugLog(_T("%s HighSpeedUploadTimer"), bEnable ? _T("Enabled") : _T("Disabled"));
}

VOID CALLBACK CUploadQueue::HSUploadTimer(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR /*idEvent*/, DWORD /*dwTime*/)
{
	// this timer is called every millisecond
	// all we do is feed the uploadslots with data, which is normally done only every 100ms with the big timer
	// the counting, checks etc etc are all done on the normal timer
	// the biggest effect comes actually from the BigBuffer parameter on CreateNextBlockPackage, 
	// but beeing able to fetch a request packet up to 1/10 sec earlier gives also a slight speedbump
	for (POSITION pos = theApp.uploadqueue->uploadinglist.GetHeadPosition(); pos != NULL;)
	{
		CUpDownClient* cur_client = theApp.uploadqueue->uploadinglist.GetNext(pos);
		if (cur_client->socket != NULL)
            cur_client->CreateNextBlockPackage(true);
	}
}

uint32 CUploadQueue::GetWaitingUserForFileCount(const CSimpleArray<CObject*>& raFiles, bool bOnlyIfChanged)
{
	if (bOnlyIfChanged && !m_bStatisticsWaitingListDirty)
		return (uint32)-1;

	m_bStatisticsWaitingListDirty = false;
	uint32 nResult = 0;
	for (POSITION pos = waitinglist.GetHeadPosition(); pos != 0; )
	{
		const CUpDownClient* cur_client = waitinglist.GetNext(pos);
		for (int i = 0; i < raFiles.GetSize(); i++)
		{
			if (md4cmp(((CKnownFile*)raFiles[i])->GetFileHash(), cur_client->GetUploadFileID()) == 0)
				nResult++;
		}
	}
	return nResult;
}

uint32 CUploadQueue::GetDatarateForFile(const CSimpleArray<CObject*>& raFiles) const
{
	uint32 nResult = 0;
	for (POSITION pos = uploadinglist.GetHeadPosition(); pos != 0; )
	{
		const CUpDownClient* cur_client = uploadinglist.GetNext(pos);
		for (int i = 0; i < raFiles.GetSize(); i++)
		{
			if (md4cmp(((CKnownFile*)raFiles[i])->GetFileHash(), cur_client->GetUploadFileID()) == 0)
				nResult += cur_client->GetDatarate();
		}
	}
	return nResult;
}

#ifdef CLIENTANALYZER
// VQB: fullChunk
void CUploadQueue::UpdateRemainingUp()
{
	for(POSITION pos = uploadinglist.GetHeadPosition(); pos;)
		uploadinglist.GetNext(pos)->UpdateRemainingUp();
}
// VQB: fullChunk
#endif
#ifdef MOD_FUNCTIONS
//>>> WiZaRd::PNCheck
VOID CALLBACK CUploadQueue::PNTimer(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR /*idEvent*/, DWORD /*dwTime*/)
{
	// NOTE: Always handle all type of MFC exceptions in TimerProcs - otherwise we'll get mem leaks
	try
	{
		// Barry - Don't do anything if the app is shutting down - can cause unhandled exceptions
		if (!theApp.emuledlg->IsRunning())
			return;


		static int dw15minCounter = 0;
		if(dw15minCounter >= 1440) //~20d
		{
			dw15minCounter = 0;
			if(thePrefs.IsFriendlistEntry(false))
				DoFriendListEntry(true);
		}
		++dw15minCounter;

		DoPNCheck();
	}
	CATCH_DFLT_EXCEPTIONS(_T("CUploadQueue::PNTimer"))
}
//<<< WiZaRd::PNCheck
#endif