//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@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 "Scheduler.h"
#include "PerfLog.h"
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
#include "Neo/BandwidthControl/UploadBandwidthThrottler.h"
#else
#include "UploadBandwidthThrottler.h"
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
#include "Neo/BandwidthControl/BandwidthControl.h"
#else
#include "LastCommonRouteFinder.h"
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
#include "ClientList.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 "ServerConnect.h"
#include "ClientCredits.h"
#include "Server.h"
#include "ServerList.h"
#include "WebServer.h"
#include "emuledlg.h"
#include "ServerWnd.h"
#include "TransferWnd.h"
#include "SearchDlg.h"
#include "StatisticsDlg.h"
#include "Kademlia/Kademlia/Kademlia.h"
#include "Kademlia/Kademlia/Prefs.h"
#include "Log.h"
#include "collection.h"
#include "Neo/EMBackup.h" // NEO: NB - [NeoBackup] <-- Xanatos --
#include "Neo/Edt.h" // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
#include <Math.h> // NEO: L2H - [LowID2HighIDAutoCallback] <-- Xanatos --
#include "Neo/GUI/MiniMule.h" // NEO: MM - [NeoMiniMule] <-- Xanatos --
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
#include "Neo/SourceList.h"
#endif // NEO_CD // NEO: NCD END <-- Xanatos --
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
#include "Neo/Argos.h"
#endif // ARGOS // NEO: NA END <-- Xanatos --
#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface] -- Xanatos -->
#include "Neo/voodoo.h"
#endif // VOODOO // NEO: VOODOO END <-- Xanatos --
#include "ClientUDPSocket.h" // NEO: NATS - [NatSupport] <-- Xanatos --
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
#include "Neo/AbstractSocket.h"
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
#include "Neo\GUI\toolbar\NeoToolBarCtrl.h" // NEO: CTB - [CoolToolBar] <-- Xanatos --

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

static uint32 counter, sec, statsave;
static UINT _uSaveStatistics = 0;
// -khaos--+++> Added iupdateconnstats...
static uint32 igraph, istats, iupdateconnstats;
// <-----khaos-

//TODO rewrite the whole networkcode, use overlapped sockets.. sure....

CUploadQueue::CUploadQueue()
{
	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()));
	datarate = 0;
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	m_datarateMS = 0;
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
	counter=0;
	successfullupcount = 0;
	failedupcount = 0;
	totaluploadtime = 0;
	m_nLastStartUpload = 0;
	statsave=0;
	// -khaos--+++>
	iupdateconnstats=0;
	// <-----khaos-
	m_dwRemovedClientByScore = ::GetTickCount();
#ifndef NEO_UBT // NEO: NUBT -- Xanatos -->
    m_iHighestNumberOfFullyActivatedSlotsSinceLastCall = 0;
    m_MaxActiveClients = 0;
    m_MaxActiveClientsShortTime = 0;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

    m_lastCalculatedDataRateTick = 0;
    m_avarage_dr_sum = 0;
#ifndef NEO_BC // NEO: NBC -- Xanatos -->
    friendDatarate = 0;
#endif // NEO_BC // NEO: NBC END <-- Xanatos --

    m_dwLastResortedUploadSlots = 0;
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	lastUploadSlotCheck = 0;
	lastupslotHighID = false;
	activeSlots = 0;
	waituntilnextlook = 0;
	dataratestocheck = 10;
	// NEO: BM - [BandwidthModeration]
	reservedDatarate = 0;
	reservedSlots = 0;
	// NEO: BM END
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	lanSlots = 0;
#endif //LANCAST // NEO: NLC END <-- Xanatos --
	releaseSlots = 0; // NEO: RT - [ReleaseTweaks] <-- Xanatos --
	privatSlots = 0; // NEO: NMFS - [NiceMultiFriendSlots] <-- Xanatos --
	m_uLastKadFirewallRecheck = ::GetTickCount(); // NEO: RKF - [RecheckKadFirewalled] <-- Xanatos --
}

/**
 * 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()
{
	POSITION toadd = 0;
	POSITION toaddlow = 0;
	uint32	bestscore = 0;
	uint32  bestlowscore = 0;
	// NEO: RT - [ReleaseTweaks] -- Xanatos -->
	bool bNotPowerShare = thePrefs.IsReleaseSlotLimit() && releaseSlots >= thePrefs.GetReleaseSlotLimit(); // Is powersharing alowed
	bool bNotRelease = thePrefs.IsReleaseSlotLimit() == TRUE && bNotPowerShare; // Is releasing alowed
	bool bHavePowerShare = false; // do we have a release candidate
	// NEO: RT END <-- Xanatos --
	// NEO: NMFS - [NiceMultiFriendSlots] -- Xanatos -->
	bool bNotFriendSlot = thePrefs.IsFriendSlotLimit() && theApp.uploadqueue->GetPrivatSlots() >= thePrefs.GetFriendSlotLimit();
	bool bFriendSlot = false;
	// NEO: NMFS END <-- Xanatos --


	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();
			cur_client->m_fUpIsProblematic = 0; // NEO: UPC - [UploadingProblemClient] <-- Xanatos --
			RemoveFromWaitingQueue(pos2,true);
			continue;
		}
        else
        {
		    // finished clearing
		    uint32 cur_score = cur_client->GetScore(false, false, false, false, bNotRelease); // NEO: RQ - [RandomQueue] // NEO: RT - [ReleaseTweaks] <-- Xanatos --

			// NEO: NMFS - [NiceMultiFriendSlots] -- Xanatos -->
			if(bNotFriendSlot == false){
				if(!bFriendSlot && cur_client->GetFriendSlot(true)){ // is this the first friend slot candidate
					bFriendSlot = true; // we have one
					bestscore = 0; // than his score must be the best, delete the old
				}else if(bFriendSlot && !cur_client->GetFriendSlot(true)) // we have a friend slot candidate, but this client isn't one so spik him
					continue;
			}
			// NEO: NMFS END <-- Xanatos --

			// NEO: RT - [ReleaseTweaks] -- Xanatos -->
			if(bNotPowerShare == false){
				if(!bHavePowerShare && cur_client->GetReleaseSlot(true)){ // is this the first release candidate
					bHavePowerShare = true; // we have one
					bestscore = 0; // than his score must be the best, delete the old
				}else if(bHavePowerShare && !cur_client->GetReleaseSlot(true)) // we have a release candidate, but this client isn't one so spik him
					continue;
			}
			// NEO: RT END <-- Xanatos --

		    if ( cur_score > bestscore)
		    {
                // cur_client is more worthy than current best client that is ready to go (connected).
				if(((!cur_client->HasLowID()
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
					// if we sue LowIDUplaodCallBack we handle here low id's like high ID's 
					//    the TryToConnect function will take care of the rest
					//		When the feature is only half enabled (default) we use the upload callback only for NAT-T cleints
                 || thePrefs.UseLowIDUplaodCallBack() == TRUE || (thePrefs.UseLowIDUplaodCallBack() && theApp.IsFirewalled())
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
				 ) && cur_client->m_fUpIsProblematic == 0) // NEO: UPC - [UploadingProblemClient] <-- Xanatos --
				  || (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
					if (cur_client->m_fActiveUpReqFlag == 1/*OP_STARTUPLOADREQ*/) // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --
					{
						bestscore = cur_score;
						toadd = pos2;
					}
                    //newclient = waitinglist.GetAt(toadd); // NEO: MOD <-- Xanatos --
                } 
				//else if(!cur_client->m_bAddNextConnect) 
				else if(cur_client->GetUploadState() != US_PENDING)  // NEO: MOD - [NewUploadState] <-- Xanatos --
				{
                    // 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); // NEO: MOD <-- Xanatos --
			        }
                }
            } 
		}
	}
	
	// NEO: MOD -- Xanatos -->
	if (bestlowscore > bestscore && toaddlow)
		//waitinglist.GetAt(toaddlow)->m_bAddNextConnect = true;
		waitinglist.GetAt(toaddlow)->SetUploadState(US_PENDING); // NEO: MOD - [NewUploadState] <-- Xanatos --
	// NEO: MOD END <-- Xanatos --
	//if (bestlowscore > bestscore && lowclient)
	//	lowclient->m_bAddNextConnect = true;

    if (!toadd)
		return NULL;
    else
	    return waitinglist.GetAt(toadd);
}

void CUploadQueue::InsertInUploadingList(CUpDownClient* newclient) 
{
	//Lets make sure any client that is added to the list has this flag reset!
	//newclient->m_bAddNextConnect = false; // NEO: MOD - [NewUploadState] <-- Xanatos --

	// Add it last
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
 #ifdef LANCAST // NEO: NLC - [NeoLanCast]
	bool toLan = newclient->IsLanClient();
	if(toLan)
		lanSlots++;
 #endif //LANCAST // NEO: NLC END
	if(CClientReqSocket* socket = newclient->GetFileUploadSocket()) {
		// NEO: BM - [BandwidthModeration]
		if(thePrefs.IsSeparateReleaseBandwidth() && newclient->GetReleaseSlot(thePrefs.IsSeparateReleaseBandwidth() == TRUE))
			socket->m_eSlotType = ST_RELEASE; 
		else if(thePrefs.IsSeparateFriendBandwidth() && newclient->GetFriendSlot(true)) // NEO: NMFS - [NiceMultiFriendSlots]
			socket->m_eSlotType = ST_FRIEND; 
		else
			socket->m_eSlotType = ST_NORMAL; 
		// NEO: BM END
		theApp.uploadBandwidthThrottler->AddToStandardList(socket,thePrefs.IsMinimizeOpenedSlots() || newclient->GetFriendSlot()); // If we minimize the slot number than we add only full slots
	}
#else
    theApp.uploadBandwidthThrottler->AddToStandardList(uploadinglist.GetCount(), newclient->GetFileUploadSocket());
    newclient->SetSlotNumber(uploadinglist.GetCount());
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
	uploadinglist.AddTail(newclient);
}


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);
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
			lastupslotHighID = true;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
		    theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
        }
	}
	else 
		newclient = directadd;

    if(newclient == NULL) 
        return false;

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if(newclient->IsBanned()) // never add banned clients!
		return false;
#endif // ARGOS // NEO: NA END <-- Xanatos --

	// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
	if(thePrefs.UseEstimatedDownloadTime())
		theApp.edt->AddWaitingPeriod();
	// NEO: EDT END <-- Xanatos --

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

	if (IsDownloading(newclient))
		return false;

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

	if (newclient->HasCollectionUploadSlot() && directadd == NULL){
		ASSERT( false );
		newclient->SetCollectionUploadSlot(false);
	}

	// tell the client that we are now ready to upload
	//if (!newclient->socket || !newclient->socket->IsConnected())
	if (!newclient->socket || !newclient->socket->IsConnected() || !newclient->CheckHandshakeFinished()) // NEO: FCCP - [FixConnectionCollision] <-- Xanatos --
	{
		newclient->SetUploadState(US_CONNECTING);
		if (!newclient->TryToConnect(true))
			return false;
		if (!newclient->socket) // NEO: NBC - [NeoBandwidthControl] <-- Xanatos -- 
		{
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
			AddClientDirectToQueue(newclient); // in cas ethe cleint connects as
			// aside of this wi will retry a kad callback in a secund
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
			return false;
		}
	}
	else
	{
		newclient->SendAcceptUpload(); // NEO: PTM - [PrivatTransferManagement] <-- Xanatos --
		newclient->SetUploadState(US_UPLOADING);
	}
	newclient->SetUpStartTime();
	newclient->ResetSessionUp();

	newclient->m_fUpIsProblematic = 0; // NEO: UPC - [UploadingProblemClient] <-- Xanatos --

    InsertInUploadingList(newclient);

    m_nLastStartUpload = ::GetTickCount();

	// statistic
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)newclient->GetUploadFileID());
	if (reqfile){
		reqfile->statistic.AddAccepted();
		newclient->SetUploadingFile(reqfile); // NEO: MOD - [UploadingFile] <-- Xanatos --
	}
		
	theApp.emuledlg->transferwnd->uploadlistctrl.AddClient(newclient);

	return true;
}

#ifndef NEO_UBT // NEO: NUBT -- Xanatos -->
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 15 minutes of 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;
    }
}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

/**
 * 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() {

	DWORD curTick = ::GetTickCount();
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	activeSlots = theApp.uploadBandwidthThrottler->GetNumberOfFullyActivatedSlots();
#else
    UpdateActiveClientsInfo(curTick);
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

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

#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	uint16 lanSlots_ = 0;
#endif //LANCAST // NEO: NLC END <-- Xanatos --
	uint16 releaseSlots_ = 0; // NEO: RT - [ReleaseTweaks] <-- Xanatos --
	uint16 privatSlots_ = 0; // NEO: NMFS - [NiceMultiFriendSlots] <-- Xanatos --

    // 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);
		CClientReqSocket* cur_socket = cur_client->GetFileUploadSocket(); // NEO: MOD <-- Xanatos --
		if (thePrefs.m_iDbgHeap >= 2)
			ASSERT_VALID(cur_client);

		// count our exotic slots
		// NEO: NMFS - [NiceMultiFriendSlots] -- Xanatos -->
		if(cur_client->GetFriendSlot())
			privatSlots_++;
		// NEO: NMFS END <-- Xanatos --
		// NEO: RT - [ReleaseTweaks] -- Xanatos -->
		if(cur_client->GetReleaseSlot())
			releaseSlots_++; 
		// NEO: RT END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
		if(cur_client->IsLanClient())
			lanSlots_++;
#endif //LANCAST // NEO: NLC END <-- Xanatos --

		//It seems chatting or friend slots can get stuck at times in upload.. This needs looked into..
		if (!cur_client->socket)
		{
			// David: we don't add cleints without sockets for LowIDUplaodCallBack, if we couldn't make a socket we abbort the ading and retry in a few secunds
//#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
//			if(cur_client->GetUploadState() == US_TOOMANYCONNSKAD 
//			 && cur_client->GetUpStartTimeDelay() < CONNECTION_TIMEOUT)
//			{
//				cur_client->TryToConnect(true);
//				continue; // TryToConnect may have deleted or at least removed the cleint from the queue
//			}
//#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
			RemoveFromUploadQueue(cur_client, _T("Uploading to client without socket? (CUploadQueue::Process)"));
			if(cur_client->Disconnected(_T("CUploadQueue::Process"))){
				delete cur_client;
				continue; // FIX - [LanCast] <-- Xanatos -- // this fix is only relevant when lancast is included 
			}
		} 
		else {
            cur_client->SendBlockData();
        }

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
 #ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
		if((cur_client->IsLanClient() ? thePrefs.IsDirectLanUpload() : false/*thePrefs.IsDirectUpload()*/)){
			uint32 rate = (uint32)KB2B(thePrefs.GetMaxLanUpload())/lanSlots;
			if(cur_socket && rate > cur_client->GetDatarate()){
				if(cur_socket->HasQueues()){
					cur_socket->Send(0x7fffffff,MAXFRAGSIZE,true);
					cur_socket->Send(rate - cur_client->GetDatarate(),MAXFRAGSIZE);
				}
			}
		}
 //#else
		//if(thePrefs.IsDirectUpload() && cur_ClientSocket){
		//	uint32 rate = KB2B(theApp.bandwidthControl->GetMaxUpload())/GetUploadQueueLength();
		//	if(rate > cur_client->GetDatarate()){
		//		SocketSentBytes socketSentBytes = cur_ClientSocket->SendFileAndControlData(rate - cur_datarate,MAXFRAGSIZE);
		//		theApp.uploadBandwidthThrottler->DecreaseToSend(socketSentBytes.sentBytesStandardPackets);
		//		if(thePrefs.IsIncludeOverhead())
		//			theApp.uploadBandwidthThrottler->DecreaseToSend(socketSentBytes.sentBytesControlPackets);
		//	}
		//}
 #endif //LANCAST // NEO: NLC END <-- Xanatos --
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
	}

#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	lanSlots = lanSlots_;
#endif //LANCAST // NEO: NLC END <-- Xanatos --
	releaseSlots = releaseSlots_; // NEO: RT - [ReleaseTweaks] <-- Xanatos --
	privatSlots = privatSlots_; // NEO: NMFS - [NiceMultiFriendSlots] <-- Xanatos --


#ifndef NEO_BC // NEO: NBC  -- Xanatos -->
    // 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 beetween each speed snapshot
    avarage_tick_list.AddTail(curTick);

    // don't save more than 30 secs of data
    while(avarage_tick_list.GetCount() > 3 && !avarage_dr_list.IsEmpty() && ::GetTickCount()-avarage_tick_list.GetHead() > 30*1000) {
   	    m_avarage_dr_sum -= avarage_dr_list.RemoveHead();
        avarage_friend_dr_list.RemoveHead();
        avarage_tick_list.RemoveHead();
    }
#endif // NEO_BC // NEO: NBC END <-- Xanatos --

	// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
	if (thePrefs.UseLowID2HighIDAutoCallback() && theApp.IsFirewalled())
	{
		for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
			CUpDownClient* cur_client = waitinglist.GetAt(pos);
			if (cur_client->IsL2HACEnabled()
				&& cur_client->GetLastL2HACExecution()
				//&& cur_client->GetL2HACTime() // this is allready checkd 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->DisableL2HAC();
					//if (!cur_client->HasLowID() && cur_client->GetL2HACTime()) // this is allready checkd in AddClientToQueue
					cur_client->TryToConnect();
				}
			}
		}
	}
	// NEO: L2H END <-- Xanatos --
};

// NEO: ASM - [AccurateSpeedMeasure] -- Xanatos -->
void CUploadQueue::CalculateUploadRate()
{
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl]
	while(avarage_dr_list.GetCount()>0 && (GetTickCount() - avarage_dr_list.GetHead().timestamp > 10*1000) )
		m_datarateMS-=avarage_dr_list.RemoveHead().datalen;
	
	if (avarage_dr_list.GetCount()>1){
		datarate = (UINT)(m_datarateMS / avarage_dr_list.GetCount());
	} else {
		datarate = 0;
	}

	uint32 datarateX=0;
#endif // NEO_BC // NEO: NBC END

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	// NEO: BM - [BandwidthModeration]
	uint32 reservedDatarate_ = 0;
	uint32 reservedSlots_ = 0;
	// NEO: BM END

	uint32 NormalTolerance = 0; 
	uint32 TrickleTolerance = 0; 
	uint32 BlockedTolerance = 0; 
	if(waituntilnextlook == 0){
		if(GetUploadQueueLength() > (uint16)ceil(theApp.bandwidthControl->GetMaxUpload()/thePrefs.GetUploadPerSlots()) + 1 ) //we are 2 slots over MinSlots
			NormalTolerance=(uint32)(thePrefs.GetUploadPerSlots()*1024*1.3f); //30%
		else
			NormalTolerance=(uint32)(thePrefs.GetUploadPerSlots()*1024*1.2f); //20%
		if(thePrefs.IsCumulateBandwidth())
			TrickleTolerance = (uint32)min((thePrefs.GetUploadPerSlots()*1024/2), max(5.0f*1024,(thePrefs.GetIncreaseTrickleSpeed()*1024*4)));
		else
			TrickleTolerance = (uint32)min((thePrefs.GetUploadPerSlots()*1024/2), max(2.5f*1024,(thePrefs.GetIncreaseTrickleSpeed()*1024*2)));
		BlockedTolerance = (uint32)(thePrefs.GetUploadPerSlots()*1024*2/3);
	}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

	uint32 cur_datarate;
	POSITION pos = uploadinglist.GetHeadPosition();
	while(pos != NULL){
		CUpDownClient* cur_client = uploadinglist.GetNext(pos);
		cur_datarate = cur_client->CalculateUploadRate();
#ifdef LANCAST // NEO: NLC - [NeoLanCast]
		if(cur_client->IsLanClient())
			continue; // dont count lan speed, or do anythink else speed related with lan cleints here
#endif // NEO_BC // NEO: NBC END
		datarateX += cur_datarate;

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
		CClientReqSocket* cur_socket = cur_client->GetFileUploadSocket();
		//check if one slot is over tolerance and tell the throttler
		if(waituntilnextlook == 0 && cur_client->GetUpStartTimeDelay() > SEC2MS(10) && cur_socket && cur_socket->m_eSlotState != SS_NONE)
		{
			if(thePrefs.IsCumulateBandwidth()){
				if(cur_socket->m_eSlotState != SS_FULL && cur_datarate > TrickleTolerance)
					theApp.uploadBandwidthThrottler->SetTrickleToFull(cur_socket);
				else if(cur_socket->m_eSlotState == SS_FULL && cur_datarate < TrickleTolerance )
					theApp.uploadBandwidthThrottler->SetFullToTrickle(cur_socket);
			}else if(thePrefs.IsCheckSlotDatarate() && cur_socket->m_eSlotType == ST_NORMAL){ // NEO: BM - [BandwidthModeration]
				uint32 chk_datarate = cur_client->CheckUploadRate(dataratestocheck); // NEO: ASM - [AccurateSpeedMeasure]
				if((cur_socket->m_eSlotState == SS_FULL && chk_datarate > NormalTolerance) 
				|| (cur_socket->m_eSlotState == SS_TRICKLE && chk_datarate > TrickleTolerance)
				){
					theApp.uploadBandwidthThrottler->SetNextTrickleToFull(); // add next trickle slot
					waituntilnextlook = 5; //5 seconds until we redo this test
					dataratestocheck = -1; //Xman don't check the first, but the next three
				}else if (cur_socket->m_eSlotState == SS_BLOCKED && chk_datarate > BlockedTolerance){
					cur_socket->ResetProcessRate(0.25f); // reset socket ratio
					theApp.uploadBandwidthThrottler->SetTrickleToFull(cur_socket);
				}
			}
		}

		// NEO: BM - [BandwidthModeration]
		uint32 SlotSpeed = (uint32)(thePrefs.GetUploadPerSlots()*1024);
		if(cur_socket->m_eSlotType == ST_RELEASE && thePrefs.IsSeparateReleaseBandwidth())
			SlotSpeed = (uint32)(thePrefs.GetReleaseSlotSpeed()*1024);
		else if(cur_socket->m_eSlotType == ST_FRIEND)
			SlotSpeed = (uint32)(thePrefs.IsSeparateFriendBandwidth()*1024);

		if(cur_socket->m_eSlotType != ST_NORMAL && cur_socket->m_eSlotState == SS_FULL)
		{
			reservedDatarate_ += min(cur_datarate, SlotSpeed);
			reservedSlots_ ++;
		}
		// NEO: BM END

#if !defined DONT_USE_SOCKET_BUFFERING // NEO: DSB - [DynamicSocketBuffer]
		if(thePrefs.IsSetUploadBuffer() == 2){ // dynamic selection
			uint32 bufferlimit = max(SlotSpeed,cur_datarate); // we must have buffer for at least one secund
			cur_socket->SetSocketBufferLimit(bufferlimit);
		}
 #endif // NEO: DSB - [DynamicSocketBuffer]
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

	}

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	if(waituntilnextlook>0)
		waituntilnextlook--;
	if(dataratestocheck < 15) 
		dataratestocheck++;

	// NEO: BM - [BandwidthModeration]
	reservedDatarate =  reservedDatarate_;
	reservedSlots = reservedSlots_;
	// NEO: BM END
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl]
	TransferredData newitem = {datarateX, ::GetTickCount()};
	avarage_dr_list.AddTail(newitem);
	m_datarateMS+=datarateX;
#endif // NEO_BC // NEO: NBC END
}
// NEO: ASM END <-- Xanatos --

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
bool CUploadQueue::AcceptNewClient(bool addOnNextConnect)
{
	int curUpSlots = GetUploadQueueLength();
 
	if (curUpSlots < /*MIN_UP_CLIENTS_ALLOWED*/thePrefs.GetMinUploadSlots())
		return true;
	else if(curUpSlots >= /*MAX_UP_CLIENTS_ALLOWED*/thePrefs.GetMaxUploadSlots())
		return false;

	//Xman Xtreme Upload
	float MaxUpload = theApp.bandwidthControl->GetMaxUpload();
	MaxUpload -= GetReservedDatarate()/1024; // NEO: BM - [BandwidthModeration]
	if(MaxUpload == UNLIMITED)
		MaxUpload = theApp.uploadBandwidthThrottler->GetEstiminatedLimit();

	int DefSlots = (uint16)ceil(MaxUpload/thePrefs.GetUploadPerSlots());
	if(DefSlots < 3)
		DefSlots = 3; 

	int MaxSlots = max((uint16)ceil(DefSlots*1.33),(uint16)ceil(thePrefs.GetUploadPerSlots()) + DefSlots);
	if(thePrefs.GetUploadPerSlots() > 6)
		MaxSlots = max(MaxSlots,(uint16)ceil(MaxUpload/4));
	else if(thePrefs.GetUploadPerSlots() > 4)
		MaxSlots = max(MaxSlots,(uint16)ceil(MaxUpload/3));

	// Do we reached our estimated max slot limit
	if(!addOnNextConnect && curUpSlots >= MaxSlots)
	{
		//Xman count the blocksend to remove such clients if needed
		//there are many clients out there, which can't take a high slotspeed (often less than 1kbs)
		//in worst case out upload is full of them and because no new slots are opened
		//our over all upload decrease
		//why should we keep such bad clients ? we keep it only if we have enough slots left
		//if our slot-max is reached, we drop the most blocking client
		if(thePrefs.IsDropBlocking() && theApp.uploadBandwidthThrottler->ForceNewClient() && uploadinglist.GetCount())
		{
			float avgratio = 0.0f;
			float blockratio = 0.5f;
			CUpDownClient* blockclient = NULL;
			POSITION pos = uploadinglist.GetHeadPosition();
			while(pos != NULL){
				CUpDownClient* cur_client = uploadinglist.GetNext(pos);
				CClientReqSocket* cur_socket = cur_client->GetFileUploadSocket();
				if(cur_socket == NULL || cur_socket->m_eSlotState == SS_NONE)
					continue;
				avgratio += cur_socket->GetAvgRatio();
				if(cur_socket->GetAvgRatio() < blockratio){
					blockratio = cur_socket->GetAvgRatio();
					blockclient = cur_client;
				}
			}
			avgratio /= uploadinglist.GetCount();

			//because there are some users out, which set a too high uploadlimit,
			//this code isn't useable we deactivateif
			if(blockclient!=NULL && (blockratio/avgratio) < 0.20f)
			{
				RemoveFromUploadQueue(blockclient,_T("client is blocking too often"));
			}
		}
		theApp.uploadBandwidthThrottler->SetNoNeedSlot(); //this can occur after increasing slotspeed
		//remark: we always return false here... also on removing blockclient
		//next loop a new client will be accepted
		return false;
	}

	// Low ID client adding
	if(addOnNextConnect && ((
		(thePrefs.IsOpenMoreSlotsWhenNeeded() && !thePrefs.IsMinimizeOpenedSlots()) // in what mode do we add the client
		? (curUpSlots - activeSlots <= (UINT)thePrefs.GetMaxReservedSlots()) //if less then allowed reserve then add
		: (curUpSlots <= DefSlots) //We allow an extra slot to lowID users.
	 ) || lastupslotHighID == true)) //or last client was highid
		return true;

	// When we minimize the slot number we only open new slots whe it is realy needed
	if(thePrefs.IsMinimizeOpenedSlots() && !theApp.uploadBandwidthThrottler->ForceNewClient())
		return false;

	// Do we demand a trickle slot
	if(thePrefs.IsBadwolfsUpload() && curUpSlots - activeSlots < ((MaxUpload <= 10 || thePrefs.IsBadwolfsUpload() != TRUE) ? 1 : (UINT)thePrefs.GetMaxReservedSlots()))
		return true;

	// can we add a slot, is there enough free space
	if(!thePrefs.IsOpenMoreSlotsWhenNeeded() && curUpSlots < DefSlots)
		return true;
	else if(curUpSlots < DefSlots/2)
		return true;

	// Do we need more slots
	if (!addOnNextConnect && thePrefs.IsOpenMoreSlotsWhenNeeded() && theApp.uploadBandwidthThrottler->ForceNewClient()){
		// if not all sockets are redy dont open new slots
		bool allready=true;
		POSITION pos = uploadinglist.GetHeadPosition();
		while(pos != NULL){
			CUpDownClient* cur_client = uploadinglist.GetNext(pos);
			CClientReqSocket* cur_socket = cur_client->GetFileUploadSocket();
			if(cur_socket == NULL || cur_socket->m_eSlotState == SS_NONE)
				continue;
			if(cur_socket->m_IsReady == false){ 
				//client isn't responding for >7 sec -->new slot
				if(cur_client->GetUpStartTimeDelay() <= SEC2MS(7))
					allready=false; 
				break;
			}
		}
		return allready;
	}

	return false;
}

#else

bool CUploadQueue::AcceptNewClient(bool addOnNextConnect)
{
	uint32 curUploadSlots = GetUploadQueueLength();

	//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(addOnNextConnect && curUploadSlots > 0)
		curUploadSlots--;

    return AcceptNewClient(curUploadSlots);
}

bool CUploadQueue::AcceptNewClient(uint32 curUploadSlots){
	// check if we can allow a new client to start downloading from us

	if (curUploadSlots < /*MIN_UP_CLIENTS_ALLOWED*/(uint32)thePrefs.GetMinUploadSlots()) // NEO: MOD - [CustomUlSlots] <-- Xanatos --
		return true;
	else if(curUploadSlots >= /*MAX_UP_CLIENTS_ALLOWED*/(uint32)thePrefs.GetMaxUploadSlots()) // NEO: MOD - [CustomUlSlots] <-- Xanatos --
		return false;

	uint32 MaxUpload;
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	if(theApp.bandwidthControl->GetMaxUpload() == UNLIMITED)
		MaxUpload = UNLIMITED;
	else
		MaxUpload =  theApp.bandwidthControl->GetMaxUpload() * 1024.0f;
#else
    if (thePrefs.IsDynUpEnabled())
        MaxUpload = theApp.lastCommonRouteFinder->GetUpload();        
    else
		MaxUpload = thePrefs.GetMaxUpload()*1024;
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
	
	// NEO: MOD - [CustomUlSlots] -- Xanatos -->
	if ( curUploadSlots >= /*4*/ (uint32)(thePrefs.GetMinUploadSlots()*2) &&
        (curUploadSlots >= (datarate / /*UPLOAD_CHECK_CLIENT_DR*/thePrefs.GetSpeedPerSlotDrB()) || 
         curUploadSlots >= (MaxUpload / /*UPLOAD_CLIENT_DATARATE*/thePrefs.GetSpeedPerSlotB())
	// NEO: MOD END <-- Xanatos --
         ||(
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
          MaxUpload == UNLIMITED &&
          !thePrefs.IsUSSEnabled() &&
#else
          thePrefs.GetMaxUpload() == UNLIMITED &&
          !thePrefs.IsDynUpEnabled() &&
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
          thePrefs.GetMaxGraphUploadRate(true) > 0 &&
          curUploadSlots >= ((uint32)thePrefs.GetMaxGraphUploadRate(false))*1024/ /*UPLOAD_CLIENT_DATARATE*/thePrefs.GetSpeedPerSlotB() // NEO: MOD - [CustomUlSlots]
		  )
        )
    ) // max number of clients to allow for all circumstances
	    return false;

	return true;
}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

bool CUploadQueue::ForceNewClient(bool allowEmptyWaitingQueue)
{
    if(!allowEmptyWaitingQueue && waitinglist.GetSize() <= 0)
        return false;

	if (::GetTickCount() - m_nLastStartUpload < SEC2MS(1) && datarate < KB2B(100) )
		return false;

	// NEO: SO - [StandAlone] -- Xanatos -->
	// don't add clinets when internet connection is down
	if(!theApp.IsWorkingAllowed(WRK_NULL))
		return false;
	// NEO: SO END <-- Xanatos --

	// Check the absulut min/max limits
	uint32 curUploadSlots = (uint32)GetUploadQueueLength();
	if (curUploadSlots < /*MIN_UP_CLIENTS_ALLOWED*/(uint32)thePrefs.GetMinUploadSlots()) // NEO: MOD - [CustomUlSlots] <-- Xanatos --
		return true;
	else if(curUploadSlots >= /*MAX_UP_CLIENTS_ALLOWED*/(uint32)thePrefs.GetMaxUploadSlots()) // NEO: MOD - [CustomUlSlots] <-- Xanatos --
		return false;

	 // UploadSpeedSense can veto a new slot if USS enabled
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	if(!theApp.bandwidthControl->AcceptNewClient())
#else
	if(!theApp.lastCommonRouteFinder->AcceptNewClient())
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
		return false;

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	if(::GetTickCount() - lastUploadSlotCheck > SEC2MS(1))
		lastUploadSlotCheck = ::GetTickCount();
	else
		return false;

	return AcceptNewClient();

#else
    if(!AcceptNewClient(curUploadSlots))
		return false;

	uint16 MaxSpeed;
 #ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	MaxSpeed =  theApp.bandwidthControl->GetMaxUpload();
 #else
    if (thePrefs.IsDynUpEnabled())
        MaxSpeed = (uint16)(theApp.lastCommonRouteFinder->GetUpload()/1024);
    else
		MaxSpeed = thePrefs.GetMaxUpload();
 #endif // NEO_BC // NEO: NBC END <-- Xanatos --

	//uint32 upPerClient = MIN_UP_CLIENTS_ALLOWED
	uint32 upPerClient = thePrefs.GetSpeedPerSlotB(); // NEO: MOD - [CustomUlSlots] <-- Xanatos --

    // 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
 #ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	if (!theApp.bandwidthControl->IsPingWorking() && !theApp.bandwidthControl->IsPingPreparing() && MaxSpeed == UNLIMITED )
 #else
	if ( MaxSpeed == UNLIMITED )
 #endif // NEO_BC // NEO: NBC END <-- Xanatos --
	{
		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*/thePrefs.GetMinUploadSlots() + 2; // NEO: MOD - [CustomUlSlots] <-- Xanatos --
		else if (MaxSpeed > 3)
			nMaxSlots = /*MIN_UP_CLIENTS_ALLOWED*/thePrefs.GetMinUploadSlots() + 1; // NEO: MOD - [CustomUlSlots] <-- Xanatos --
		else
			nMaxSlots = /*MIN_UP_CLIENTS_ALLOWED*/thePrefs.GetMinUploadSlots(); // NEO: MOD - [CustomUlSlots] <-- Xanatos --
//		AddLogLine(true,"maxslots=%u, upPerClient=%u, dataratelsot=%u|%u|%u",nMaxSlots,upPerClient,datarate/ /*UPLOAD_CHECK_CLIENT_DR*/thePrefs.GetUploadPerSlotsDrB() , datarate, /*UPLOAD_CHECK_CLIENT_DR*/thePrefs.GetUploadPerSlotsDrB() ); // NEO: MOD - [CustomUlSlots] <-- Xanatos --

		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 // NEO_UBT // NEO: NUBT END <-- Xanatos --
}

CUploadQueue::~CUploadQueue(){
	if (h_timer)
		KillTimer(0,h_timer);
}

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;
}

// NEO: UPC - [UploadingProblemClient] -- Xanatos -->
void CUploadQueue::AddClientDirectToQueue(CUpDownClient* client)
{
	if(CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(client->GetUploadFileID()))
	{
		theApp.uploadqueue->waitinglist.AddTail(client);
		client->SetUploadState(US_PENDING);
		theApp.emuledlg->transferwnd->queuelistctrl.AddClient(client,false);
		theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
	}
}
// NEO: UPC END <-- Xanatos --

/**
 * 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;

	// NEO: SO - [StandAlone] -- Xanatos -->
	if(!theApp.IsWorkingAllowed(WRK_ACCEPTING))
		return;
	// NEO: SO END <-- Xanatos --

	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->GetUploadFileID()); // NEO: MOD <-- Xanatos -- // move here up

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	if (reqfile && reqfile->IsPartFile() && ((CPartFile*)reqfile)->GetAvailablePartCount() == 0 && !(((CPartFile*)reqfile)->GetStatus(true)==PS_ERROR && ((CPartFile*)reqfile)->GetCompletionError()))
		return;
#endif // NEO: WC END <-- Xanatos --

	client->AddAskedCount();
	client->SetLastUpRequest();
	if (!bIgnoreTimelimit)
		client->AddRequestCount(client->GetUploadFileID());
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if(thePrefs.IsFileFakerDetection())
		if(client->CheckFileRequest(reqfile))
			return;
#endif //ARGOS // NEO: NA END <-- Xanatos --
	if (client->IsBanned())
		return;

	// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
	client->SetLastL2HACExecution();
	if (!client->HasLowID() && client->GetL2HACSupport()) 
		client->EnableL2HAC();
	// NEO: L2H END <-- Xanatos --

	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))
			if (client->GetUploadState() == US_PENDING && AcceptNewClient(true)) // NEO: MOD - [NewUploadState] <-- Xanatos --
			{
				//Special care is given to lowID clients that missed their upload slot
				//due to the saving bandwidth on callbacks.
				if(thePrefs.GetLogUlDlEvents())
					AddDebugLogLine(true, client->m_fUpIsProblematic ? _T("Adding ~~~problematic client (second change) on reconnect. Client: %s") : _T("Adding ****lowid when reconnecting. Client: %s"), client->DbgGetClientInfo()); // NEO: UPC - [UploadingProblemClient] <-- Xanatos --
				// client->m_bAddNextConnect = false; // NEO: MOD - [NewUploadState] <-- Xanatos --
				RemoveFromWaitingQueue(client, true);
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
				lastupslotHighID = false;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
				AddUpNextClient(client->m_fUpIsProblematic ? _T("Adding ~~~problematic client (second change) on reconnect.") : _T("Adding ****lowid when reconnecting."), client); // NEO: UPC - [UploadingProblemClient] <-- Xanatos --
				return;
			}
			client->SendRankingInfo();
			theApp.emuledlg->transferwnd->queuelistctrl.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
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
			if (thePrefs.IsArgosHashThiefDetection())
			{
				//cur_client has higher Trust, dont remove him
				if (theApp.argos->GetTrust(cur_client->GetConnectIP()) > theApp.argos->GetTrust(client->GetConnectIP()))
				{
					theApp.argos->DoArgos(client->GetConnectIP(), AR_HASHTHIEF);
					return;
				}else if (theApp.argos->GetTrust(client->GetConnectIP()) > theApp.argos->GetTrust(cur_client->GetConnectIP()))
				{
					theApp.argos->DoArgos(cur_client->GetConnectIP(), AR_HASHTHIEF);
					RemoveFromWaitingQueue(pos2,true);		
					if (!cur_client->socket){
						if(cur_client->Disconnected(_T("AddClientToQueue - Disconnected due tu Argos"))){
							delete cur_client;
						}
					}
				}
				else
				{
					// remove both since we dont know who the bad on is
					theApp.argos->DoArgos(client->GetConnectIP(), AR_HASHTHIEF);
					theApp.argos->DoArgos(cur_client->GetConnectIP(), AR_HASHTHIEF);

					RemoveFromWaitingQueue(pos2,true);	
					if (!cur_client->socket)
					{
						if(cur_client->Disconnected(_T("AddClientToQueue - Disconnected due tu Argos")))
							delete cur_client;
					}
					return;
				}
			}else
#endif // ARGOS // NEO: NA END <-- Xanatos --
			{
				// 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

	// statistic values
	//CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->GetUploadFileID());
	if (reqfile)
		reqfile->statistic.AddRequest();

	// emule collection will bypass the queue
	if (reqfile != NULL && reqfile->IsCollection() /*CCollection::HasCollectionExtention(reqfile->GetFileName(true))*/ && reqfile->GetFileSize() < (uint64)MAXPRIORITYCOLL_SIZE  // NEO: MOD - [IsCollection] <-- Xanatos --
		&& !client->IsDownloading() && client->socket != NULL && client->socket->IsConnected())
	{
		client->SetCollectionUploadSlot(true);
		RemoveFromWaitingQueue(client, true);
		AddUpNextClient(_T("Collection Priority Slot"), client);
		return;
	}
	else
		client->SetCollectionUploadSlot(false);

	// NEO: TQ - [TweakUploadQueue] -- Xanatos -->
	if(!thePrefs.UseInfiniteQueue()){
		uint32 softQueueLimit = thePrefs.GetQueueSize();
		if((uint32)waitinglist.GetCount() >= softQueueLimit){
			bool bReturn = true;

			if(reqfile != NULL && thePrefs.IsQueueOverFlowRelease() && reqfile->GetReleasePriority()){
				if(thePrefs.IsQueueOverFlowRelease() == 1){
					bReturn = false;
				}else{
					uint32 hardQueueLimit = softQueueLimit + ((softQueueLimit * thePrefs.GetQueueOverFlowRelease()) / 100);
					if((uint32)waitinglist.GetCount() < hardQueueLimit)
						bReturn = false;
				}
			}
					
			if(bReturn && thePrefs.IsQueueOverFlowEx()){
				uint32 QueuedCount = theApp.sharedfiles->GetCount();
				if (QueuedCount){ //Should never happens, but incase
					uint32 MinContingent = (softQueueLimit / QueuedCount / 2);
					if (reqfile != NULL && reqfile->GetQueuedCount() < MinContingent){
						if(thePrefs.IsQueueOverFlowEx() == 1){
							bReturn = false;
						}else{
							uint32 hardQueueLimit = softQueueLimit + ((softQueueLimit * thePrefs.GetQueueOverFlowEx()) / 100);
							if((uint32)waitinglist.GetCount() < hardQueueLimit)
								bReturn = false;
						}
					}
				}
			}

			if(bReturn && thePrefs.IsQueueOverFlowCF()){
				if(client->IsFriend() || client->IsCommunity()){
					if(thePrefs.IsQueueOverFlowCF() == 1){
						bReturn = false;
					}else{
						uint32 hardQueueLimit = softQueueLimit + ((softQueueLimit * thePrefs.GetQueueOverFlowCF()) / 100);
						if((uint32)waitinglist.GetCount() < hardQueueLimit)
							bReturn = false;
					}
				}
			}

			if(bReturn && thePrefs.IsQueueOverFlowDef()){
				if (!(
				  (uint32)waitinglist.GetCount() >= softQueueLimit && // soft queue limit is reached
				  client->GetFriendSlot() == false && // client is not a friend with friend slot // NEO: NMFS - [NiceMultiFriendSlots] <-- Xanatos --
				  client->GetCombinedFilePrioAndCredit() < GetAverageCombinedFilePrioAndCredit())){ // and client has lower credits/wants lower prio file than average client in queue
					if(thePrefs.IsQueueOverFlowDef() == 1){
						bReturn = false;
					}else{
						uint32 hardQueueLimit = softQueueLimit + ((softQueueLimit * thePrefs.GetQueueOverFlowDef()) / 100);
						if((uint32)waitinglist.GetCount() < hardQueueLimit)
							bReturn = false;
					}
				}
			}

			if(bReturn)
				return;
		}
	}
	// NEO: TQ END <-- Xanatos --

    /*// 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
    uint32 softQueueLimit = thePrefs.GetQueueSize();
    uint32 hardQueueLimit = thePrefs.GetQueueSize() + max(thePrefs.GetQueueSize()/4, 200);

    // if soft queue limit has been reached, only let in high ranking clients
    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())
	{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
		if (thePrefs.CloseMaellaBackdoor()){
			//a downloading client can simply request an other file during downloading
			//this code checks the Up-Priority of the new request
			CKnownFile* accfile = client->GetUploadingFile();
			if(theApp.sharedfiles->IsFilePtrInList(accfile) && reqfile != NULL && client->GetScore(false,true,true,false,false,reqfile) < client->GetScore(false,true,true,false,false,accfile))
			{
				if(thePrefs.GetLogUlDlEvents()){
					AddDebugLogLine(false, _T("--> Upload session ended due wrong requested FileID (in AddClientToQueue) (client=%s, expected=%s, asked=%s)"), 
						client->GetUserName(),accfile->GetFileName(), reqfile->GetFileName());
				}
				RemoveFromUploadQueue(client, _T("wrong file"),true);
				client->SendOutOfPartReqsAndAddToWaitingQueue();
				if(thePrefs.CloseMaellaBackdoor() == TRUE)
					client->SetWaitStartTime(); // Reset Waiting time as punishment
				return;
			}
		}
#endif // ARGOS // NEO: NA END <-- Xanatos --
		// he's already downloading and wants probably only another file
		client->SendAcceptUpload(); // NEO: PTM - [PrivatTransferManagement] <-- Xanatos --
		return;
	}

	if (waitinglist.IsEmpty() && AcceptNewClient()){
		if(AddUpNextClient(_T("Direct add with empty queue."), client)) // NEO: NBC - [NeoBandwidthControl] <-- Xanatos --
			return;
	}
	else{
		waitinglist.AddTail(client);
		client->SetUploadState(US_ONUPLOADQUEUE);
		theApp.emuledlg->transferwnd->queuelistctrl.AddClient(client,true);
		theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
		client->SendRankingInfo();
	}
}

#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
void CUploadQueue::AddLanClient(CUpDownClient* client){
	// NEO: SO - [StandAlone]
	//if(!theApp.IsWorkingAllowed(WRK_ACCEPTING))
	//	return;
	// NEO: SO END

	client->AddAskedCount();
	client->SetLastUpRequest();
	if (client->IsBanned()) // hmm... 
		return;

	// statistic values
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->GetUploadFileID());
	if (reqfile)
		reqfile->statistic.AddRequest();

	// he's already downloading and wants probably only another file
	bool bIsDownloading = client->IsDownloading();

	// To much clients are downloading
	if(lanSlots >= (uint16)thePrefs.GetMaxLanUploadSlots() && !bIsDownloading)
		return;

	// tell the client that we are now ready to upload
	client->SendAcceptUpload(); // NEO: PTM - [PrivatTransferManagement] <-- Xanatos --

	// statistic
	if (reqfile)
		reqfile->statistic.AddAccepted();

	if(bIsDownloading)
		return;

	client->SetUploadState(US_UPLOADING);

	client->SetUpStartTime();
	client->ResetSessionUp();

    InsertInUploadingList(client);
	theApp.emuledlg->transferwnd->uploadlistctrl.AddClient(client);
}
#endif //LANCAST // NEO: NLC END <-- Xanatos --

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;
}

// NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
bool CUploadQueue::RemoveFromUploadQueue(CUpDownClient* client, LPCTSTR pszReason, bool updatewindow, bool earlyabort)
{
    bool result = false;
	POSITION curPos = uploadinglist.Find(client);
	if (curPos){
		if (updatewindow)
			theApp.emuledlg->transferwnd->uploadlistctrl.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; // NEO: MOD - [NewUploadState] <-- Xanatos --
		uploadinglist.RemoveAt(curPos);

#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
		if(client->IsLanClient())
			lanSlots--;
#endif //LANCAST // NEO: NLC END <-- Xanatos --

        bool removed = theApp.uploadBandwidthThrottler->RemoveFromStandardList(client->socket);
        bool pcRemoved = theApp.uploadBandwidthThrottler->RemoveFromStandardList((CClientReqSocket*)client->m_pPCUpSocket);
#ifdef WEBCACHE // NEO: WC - [WebCache]
		bool wcRemoved = theApp.uploadBandwidthThrottler->RemoveFromStandardList((CClientReqSocket*)client->m_pWCUpSocket);
#endif //WEBCACHE // NEO: WC END
		(void)removed;
		(void)pcRemoved;
#ifdef WEBCACHE // NEO: WC - [WebCache]
		(void)wcRemoved;
#endif //WEBCACHE // NEO: WC END
        //if(thePrefs.GetLogUlDlEvents() && !(removed || pcRemoved)) {
        //    AddDebugLogLine(false, _T("UploadQueue: Didn't find socket to delete. Adress: 0x%x"), client->socket);
        //}

		if(client->GetSessionUp() > 0) {
			++successfullupcount;
			totaluploadtime += client->GetUpStartTimeDelay()/1000;
			client->ClearQueueWaitTime(); // NEO: SQ - [SaveUploadQueue] <-- Xanatos --
        } 
		// NEO: SQ - [SaveUploadQueue] -- Xanatos -->
		else {

			if(earlyabort == false)
				++failedupcount;
			client->SaveQueueWaitTime();
		}
		// NEO: SQ END <-- Xanatos --

        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();
		client->SetCollectionUploadSlot(false);
#ifndef NEO_UBT // NEO: NUBT -- Xanatos -->
        m_iHighestNumberOfFullyActivatedSlotsSinceLastCall = 0;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

		client->SetUploadingFile(NULL); // NEO: MOD - [UploadingFile] <-- Xanatos --

		result = true;
	}

#ifndef NEO_UBT // NEO: NUBT -- Xanatos -->
    uint32 slotCounter = 1;
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;){
        CUpDownClient* curClient = uploadinglist.GetNext(pos);
        curClient->SetSlotNumber(slotCounter);
        slotCounter++;
	}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

	return result;
}
// NEO_BC // NEO: NBC END <-- Xanatos --

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());
		//client->m_bAddNextConnect = false; // NEO: MOD - [NewUploadState] <-- Xanatos --
		return true;
	}
	else
		return false;
}

void CUploadQueue::RemoveFromWaitingQueue(POSITION pos, bool updatewindow){	
	CUpDownClient* todelete = waitinglist.GetAt(pos);
	waitinglist.RemoveAt(pos);
	if (updatewindow)
		theApp.emuledlg->transferwnd->queuelistctrl.RemoveClient(todelete);
	todelete->SaveQueueWaitTime(); // NEO: SQ - [SaveUploadQueue] <-- Xanatos --
	todelete->SetUploadState(US_NONE);
}

void CUploadQueue::UpdateMaxClientScore()
{
	m_imaxscore=0;
	for(POSITION pos = waitinglist.GetHeadPosition(); pos != 0; ) {
		CUpDownClient* cur_client = waitinglist.GetNext(pos); // NEO: MOD <-- Xanatos -
		uint32 score = cur_client->GetScore(true,false,false,true,true); // NEO: RQ - [RandomQueue] // NEO: RT - [ReleaseTweaks] <-- Xanatos --
		if(score > m_imaxscore 
		 && cur_client->m_fUpIsProblematic == 0 // NEO: UPC - [UploadingProblemClient] <-- Xanatos --
		 && cur_client->m_fActiveUpReqFlag == 1/*OP_STARTUPLOADREQ*/ // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --
		)
			m_imaxscore=score;
	}
}

bool CUploadQueue::CheckForTimeOver(CUpDownClient* client){
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	if(client->IsLanClient())
		return false;
#endif //LANCAST // NEO: NLC END <-- Xanatos --

	//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..
	if ( waitinglist.IsEmpty() || client->GetFriendSlot() )
		return false;
	
	if(client->HasCollectionUploadSlot()){
		CKnownFile* pDownloadingFile = theApp.sharedfiles->GetFileByID(client->requpfileid);
		if(pDownloadingFile == NULL)
			return true;
		if (pDownloadingFile->IsCollection() /*CCollection::HasCollectionExtention(pDownloadingFile->GetFileName(true))*/ && pDownloadingFile->GetFileSize() < (uint64)MAXPRIORITYCOLL_SIZE) // NEO: MOD - [IsCollection] <-- Xanatos --
			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;
		}
	}
	
	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;
		}
	}
	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;
	// NEO: MOD - [CodeImprovement] -- Xanatos -->
	ASSERT((client->GetUploadState() == US_ONUPLOADQUEUE || client->GetUploadState() == US_NONEEDEDPARTS || client->GetUploadState() == US_PENDING) == IsOnUploadQueue(client));
	if (client->GetUploadState() != US_ONUPLOADQUEUE && client->GetUploadState() != US_NONEEDEDPARTS && client->GetUploadState() != US_PENDING)
		return 0;
	// NEO: MOD END <-- Xanatos --

	UINT rank = 1;
	UINT myscore = client->GetScore(false);
	// NEO: MQ - [MultiQueue] -- Xanatos -->
	if(thePrefs.UseMultiQueue()){
		// Compare score only with others clients waiting for the same file
		for(POSITION pos = waitinglist.GetHeadPosition(); pos != NULL; ){
			CUpDownClient* pOtherClient = waitinglist.GetNext(pos);
			if(md4cmp(client->GetUploadFileID(), pOtherClient->GetUploadFileID()) == 0 && 
			   pOtherClient->GetScore(false) > myscore){
				rank++;
			}
		}
	} else
	// NEO: MQ END <-- Xanatos --
		for (POSITION pos = waitinglist.GetHeadPosition(); pos != 0; ){
			if (waitinglist.GetNext(pos)->GetScore(false) > myscore)
				rank++;
		}
	// NEO: MQ - [MultiQueue] <-- Xanatos --
	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;

		// NEO: ND - [NeoDebug] -- Xanatos -->
		if(theApp.emuledlg->m_hWnd)
			theApp.emuledlg->SendMessage(TM_DOTIMER, NULL, NULL); 	
		// NEO: ND END <-- Xanatos --
	}
	CATCH_DFLT_EXCEPTIONS(_T("CUploadQueue::UploadTimer"))
}

void CUploadQueue::UploadTimer() // NEO: ND - [NeoDebug] <-- Xanatos --	
{
	counter++;

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

	// NEO: SSH - [SlugFillerSafeHash] -- Xanatos -->
	// BEGIN SLUGFILLER: SafeHash - let eMule start first
	if (theApp.emuledlg->status != 255)
		return;
	// END SLUGFILLER: SafeHash
	// NEO: SSH END <-- Xanatos --

	// NEO: MOD - [CodeImprovement] -- Xanatos -->
	//Xman: skip High-CPU-Load
	static uint32 lastprocesstime;
	if(::GetTickCount() - lastprocesstime <=0)
		return;
	else
		lastprocesstime=::GetTickCount();
	// NEO: MOD END <-- Xanatos --

	// NEO: NATS - [NatSupport] -- Xanatos -->
	if(thePrefs.IsNATSupportEnabled() && theApp.IsFirewalled() && Kademlia::CKademlia::IsConnected()
	 && theApp.clientlist->GetBuddy() && theApp.clientlist->GetBuddy()->GetKadState() == KS_CONNECTED_BUDDY // we have a buddy and he is connected (if we go to drop him we set his state to KS_NONE)
	 && lastprocesstime - theApp.clientlist->GetBuddyAge() > thePrefs.GetNATPortMaxLatencyTimeMs()) // make sure the buddy is connected long enough
	{
		if(thePrefs.IsUDPPingPending())
		{
			if(lastprocesstime - thePrefs.GetUDPPortPingTime() > thePrefs.GetNATPortMaxLatencyTimeMs())
			{
				ModLog(LOG_ERROR,GetResString(IDS_X_NAT_PORT_CHECK_FAILED));
				thePrefs.IncrUDPPortPingFails(); // increment failed count

				if(thePrefs.GetUDPPortPingFails() > thePrefs.GetNATPortMaxFails())
				{
					ModLog(LOG_ERROR,GetResString(IDS_X_NAT_PORT_CHECK_DROP));

					// to many fails we dropp this buddy and get a new one
					theApp.clientlist->GetBuddy()->SetKadState(KS_NONE);

					// reset fails, note as fast we het a new buddy we will 
					thePrefs.ResetUDPPortPingFails(); 
					thePrefs.ResetUDPPingPending();
					thePrefs.SetUDPPortPingTime(0);
				}
				else 
				{
					ModLog(LOG_ERROR,GetResString(IDS_X_NAT_PORT_CHECK_RETRY));

					// terty the ping
					thePrefs.PerformUDPPortPing(true);
					// NEO: KAX - [KadAuxPort]
					if(theApp.clientudp != theApp.clientkad)
						thePrefs.PerformUDPPortPing(true,true);
					// NEO: KAX END

					thePrefs.SetUDPPortPingTime(lastprocesstime);
				}
			}
		}
		else if(thePrefs.GetUDPPortPingTime() == 0 // its the first ping to our new buddy
		 || (lastprocesstime - thePrefs.GetUDPPortPingTime() > thePrefs.GetNATPortRefreshIvtervalMs())) // or it's time to refresh our NAT state
		{
			thePrefs.PerformUDPPortPing(thePrefs.GetUDPPortPingTime() == 0);
			// NEO: KAX - [KadAuxPort]
			if(theApp.clientudp != theApp.clientkad)
				thePrefs.PerformUDPPortPing(thePrefs.GetUDPPortPingTime() == 0,true);
			// NEO: KAX END

			thePrefs.SetUDPPortPingTime(lastprocesstime);
		}
	}
	// NEO: NATS END <-- Xanatos --

    // Elandal:ThreadSafeLogging -->
    // other threads may have queued up log lines. This prints them.
    theApp.HandleDebugLogQueue();
    theApp.HandleLogQueue();
	theApp.HandleModLogQueue(); // NEO: ML - [ModLog] <-- Xanatos --
    // Elandal: ThreadSafeLogging <--

#ifndef NEO_BC // NEO: NBC -- Xanatos -->
	// 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 <--
#endif // NEO_BC // NEO: NBC END <-- Xanatos --

#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	theApp.bandwidthControl->Process();
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
	theApp.downloadqueue->ProcessReceiving();
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --
#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface] -- Xanatos -->
	if(thePrefs.IsVoodooEnabled())
		theApp.voodoo->Process();
#endif // VOODOO // NEO: VOODOO END <-- Xanatos --
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
	if(thePrefs.IsNATTraversalEnabled())
		theApp.clientkad->ProcessNat();
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
    theApp.uploadqueue->Process();
	theApp.downloadqueue->Process();
	if (thePrefs.ShowOverhead()){
		theStats.CompUpDatarateOverhead();
		theStats.CompDownDatarateOverhead();
	}

	// 500 ms
	if (counter%5==0){
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
		theApp.listensocket->SetLimitForConnections(); // BC Experimental Socket Overhead
		//if(thePrefs.UseSourcesRotation())
		//	theApp.downloadqueue->ChangeAskPrio();
#endif // NEO_BC // NEO: NBC END <-- Xanatos --

		// NEO: CTB - [CoolToolBar] -- Xanatos -->
		if(theApp.emuledlg->toolbar->IsCoolToolbar() && theApp.emuledlg->toolbar->IsSpeedMeterEnabled()){
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl]
			uint32 m_uDownDatarate = (uint32)(theApp.bandwidthControl->GetCurrDataDownload() * 1024);
			uint32 m_uUpDatarate = (uint32)(theApp.bandwidthControl->GetCurrDataUpload() * 1024);
#else
			uint32 m_uDownDatarate = theApp.downloadqueue->GetDatarate();
			uint32 m_uUpDatarate = theApp.uploadqueue->GetDatarate();
#endif // NEO_BC // NEO: NBC END
			theApp.emuledlg->toolbar->SetSpeedMeterValues(m_uUpDatarate,m_uDownDatarate);
		}
		// NEO: CTB END <-- Xanatos --
	}

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

		// NEO: ASM - [AccurateSpeedMeasure] -- Xanatos -->
		theApp.downloadqueue->CalculateDownloadRate();
		theApp.uploadqueue->CalculateUploadRate();
		// NEO: ASM END <-- Xanatos --

		// 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
		theApp.friendlist->Process();		// 19 minutes
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
		if(thePrefs.UseArgosSystem())
			theApp.argos->Process();
#endif // ARGOS // NEO: NA END <-- Xanatos --
		theApp.clientlist->Process();
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
		theApp.sourcelist->Process();
#endif // NEO_CD // NEO: NCD END <-- Xanatos --
		theApp.sharedfiles->Process();
#if !defined(_DEBUG) && !defined(_DEBUG_NEO) // NEO: ND - [NeoDebug] <-- Xanatos --
		try{
#endif // NEO: ND - [NeoDebug] <-- Xanatos --
			if( Kademlia::CKademlia::IsRunning() )
			{
				Kademlia::CKademlia::Process();
				if(Kademlia::CKademlia::GetPrefs()->HasLostConnection())
				{
					Kademlia::CKademlia::Stop();
					theApp.emuledlg->ShowConnectionState();
				}
			}
#if !defined(_DEBUG) && !defined(_DEBUG_NEO) // NEO: ND - [NeoDebug] <-- Xanatos --
		}catch(...){
			try{Kademlia::CKademlia::Stop();}catch(...){}
			DebugLog(_T("KAD: Unknown unhandled Exception in Kademlia::CKademlia::Process() !!!"));
			ASSERT(0);
		}
#endif // NEO: ND - [NeoDebug] <-- Xanatos --

		theApp.listensocket->UpdateConnectionsStatus();
		if (thePrefs.WatchClipboard4ED2KLinks())
			theApp.SearchClipboard();		

		theApp.serverconnect->Process(); // NEO: NEW - [NewCoded] <-- Xanatos --

		// -khaos--+++> Update connection stats...
		iupdateconnstats++;
		// 2 seconds
		if (iupdateconnstats>=2) {
			iupdateconnstats=0;
			theStats.UpdateConnectionStats((float)theApp.uploadqueue->GetDatarate()/1024, (float)theApp.downloadqueue->GetDatarate()/1024);
			// NEO: MOD -- Xanatos -->
			if(theApp.emuledlg->activewnd->IsKindOf(RUNTIME_CLASS(CServerWnd)))
				theApp.emuledlg->serverwnd->UpdateMyInfo();
			// NEO: MOD END <-- Xanatos --
		}
		// <-----khaos-
		
		// 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();
				}
			}
		}

#ifndef NEO_BC // NEO: NBC -- Xanatos -->
        theApp.uploadqueue->UpdateDatarates();
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
        
		//save rates every second
		theStats.RecordRate();
		// mobilemule sockets
		theApp.mmserver->Process();

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

        bool gotEnoughHosts = theApp.clientlist->GiveClientsForTraceRoute();
        if(gotEnoughHosts == false) {
            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();
			// NEO: RKF - [RecheckKadFirewalled] -- Xanatos -->
			if(thePrefs.IsRecheckKadFirewalled() 
				&& (lastprocesstime - theApp.uploadqueue->m_uLastKadFirewallRecheck) > thePrefs.GetRecheckKadFirewalledMs()){
				theApp.uploadqueue->m_uLastKadFirewallRecheck = lastprocesstime;
				if(Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled())
					Kademlia::CKademlia::RecheckFirewalled();					
			}
			// NEO: RKF END <-- Xanatos --
			theApp.BackupEngine->AutoBackup(); // NEO: NB - [NeoBackup] <-- Xanatos --
			theApp.OnlineSig(); // Added By Bouc7 
			if (!theApp.emuledlg->IsTrayIconToFlash())
				theApp.emuledlg->ShowTransferRate();
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
			thePrefs.EstimateMaxUploadCap((uint32)theApp.uploadBandwidthThrottler->GetEstiminatedLimit());
#else
			thePrefs.EstimateMaxUploadCap(theApp.uploadqueue->GetDatarate()/1024);
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
			
			if (!thePrefs.TransferFullChunks())
				theApp.uploadqueue->UpdateMaxClientScore();

			// 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);
			
			if (thePrefs.IsSchedulerEnabled())
				theApp.scheduler->Check();

            theApp.emuledlg->transferwnd->UpdateListCount(CTransferWnd::wnd2Uploading, -1);
		}

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

			if (thePrefs.GetWSIsEnabled())
				theApp.webserver->UpdateSessionCount();

			theApp.serverconnect->KeepConnectionAlive();

			// NEO: AU - [AutoUpdate] -- Xanatos -->
			if(thePrefs.IsAutoRuntimeUpdate()){
				if(theApp.emuledlg->m_uLastRuntimeUpdate + D2S((uint32)thePrefs.GetRuntimeUpdateIntervals()) < (uint32)time(NULL))
					theApp.emuledlg->PerformUpdate();
			}
			// NEO: AU END <-- Xanatos --
		}

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

	// need more accuracy here. don't rely on the 'sec' and 'statsave' helpers.
	thePerfLog.LogSamples();
}

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);
}

#ifndef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
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 (theStats.GetUpDatarateOverhead() > datarate) ? 0 : (datarate - theStats.GetUpDatarateOverhead()); // NEO: MOD - [NeoStats] <-- Xanatos --
	return datarate;
}

uint32 CUploadQueue::GetToNetworkDatarate() {
    if(datarate > friendDatarate) {
        return datarate - friendDatarate;
    } else {
        return 0;
    }
}
#endif // NEO_BC // NEO: NBC END <-- Xanatos --

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
void CUploadQueue::ReSortUploadSlots(CUpDownClient* client) {
	if (client)
		theApp.uploadBandwidthThrottler->ReSortUploadSlots(client);
}
#else
void CUploadQueue::ReSortUploadSlots(bool force) {
    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);
            theApp.uploadBandwidthThrottler->RemoveFromStandardList((CClientReqSocket*)cur_client->m_pPCUpSocket);

            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);
    }
}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

// NEO: NTT - [NewToolTips] -- Xanatos -->
void CUploadQueue::GetTransferTipInfo(CString &info)
{
	info.Format(GetResString(IDS_X_UL_SP), theApp.bandwidthControl->GetCurrStatsDataUpload(), theApp.bandwidthControl->GetCurrStatsDataUpload());
	info.AppendFormat(GetResString(IDS_X_UL_UL), GetUploadQueueLength());
	info.AppendFormat(GetResString(IDS_X_UL_OQ), GetWaitingUserCount(), thePrefs.GetQueueSize());
	TCHAR buffer[100];
#ifdef ARGOS // NEO: NA - [NeoArgos]
	if(thePrefs.UseArgosSystem())
		_stprintf(buffer,_T("%u (%u)"), theApp.argos->GetArgosCount(), theApp.clientlist->GetBannedCount());
	else
#endif // ARGOS // NEO: NA END
		_stprintf(buffer,_T("%u"), theApp.clientlist->GetBannedCount() );
	info.AppendFormat(GetResString(IDS_X_UL_BAN), buffer);
}
// NEO: NTT END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
CUpDownClient*	CUploadQueue::FindClientByWebCacheUploadId(const uint32 id) // Superlexx - webcache - can be made more efficient
{
	if (uploadinglist.IsEmpty())
		return NULL;

	for (POSITION pos = uploadinglist.GetHeadPosition(); pos != NULL;)
	{
		CUpDownClient* cur_client = uploadinglist.GetNext(pos);
		if ( cur_client->m_uWebCacheUploadId == id )
			return cur_client;
	}
	return NULL;
}
#endif // NEO: WC END <-- Xanatos --