//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.
#pragma once

class CUpDownClient;
class CEdt; // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --

typedef CTypedPtrList<CPtrList, CUpDownClient*> CUpDownClientPtrList;

class CUploadQueue
{
	friend class CEdt; // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
	friend class CClientUDPSocket; // NEO: FIX - [NewUploadState] <-- Xanatos --
	friend class CClientReqSocket; // NEO: FIX - [NewUploadState] <-- Xanatos --

public:
	CUploadQueue();
	~CUploadQueue();

	void	Process();
	void	CalculateUploadRate(); // NEO: ASM - [AccurateSpeedMeasure] <-- Xanatos --
	void	AddClientToQueue(CUpDownClient* client,bool bIgnoreTimelimit = false);
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	void	AddLanClient(CUpDownClient* client);
#endif //LANCAST // NEO: NLC END <-- Xanatos --
	bool	RemoveFromUploadQueue(CUpDownClient* client, LPCTSTR pszReason = NULL, bool updatewindow = true, bool earlyabort = false);
	bool	RemoveFromWaitingQueue(CUpDownClient* client,bool updatewindow = true);
	void	InsertToUploadingList(CUpDownClient* newclient)	{AddUpNextClient(_T("PrivateAdd"),newclient);} // NEO: MOD <-- Xanatos --
	bool	IsOnUploadQueue(CUpDownClient* client)	const {return (waitinglist.Find(client) != 0);}
	bool	IsDownloading(CUpDownClient* client)	const {return (uploadinglist.Find(client) != 0);}

#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	uint32	GetDatarate() {return datarate;}
#else
    void    UpdateDatarates();
	uint32	GetDatarate();
    uint32  GetToNetworkDatarate();
#endif // NEO_BC // NEO: NBC END <-- Xanatos --

	bool	CheckForTimeOver(CUpDownClient* client);
	int		GetWaitingUserCount()					{return waitinglist.GetCount();}

	// NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos --> 
#if defined(NEO_UBT) || defined(LANCAST)
	// NEO: NLC - [NeoLanCast]
	int		GetLanUploadsCount()					{return lanSlots;}
	int		GetUploadQueueLength()					{return uploadinglist.GetCount() - lanSlots;}
	// NEO: NLC END
#elif defined(NEO_UBT)
	int		GetUploadQueueLength()					{return uploadinglist.GetCount();}
#else
	int		GetUploadQueueLength()					{return uploadinglist.GetCount();}
	uint32	GetActiveUploadsCount()					{return m_MaxActiveClientsShortTime;}
#endif // NEO_UBT 
#ifdef NEO_UBT
	int		GetActiveUploadsCount()					{return activeSlots;}
	// NEO: BM - [BandwidthModeration]
	uint32	GetReservedDatarate()					{return reservedDatarate;}
	uint32	GetReservedSlots()						{return reservedSlots;}
	// NEO: BM END
#endif // NEO_UBT 
	// NEO: NUBT END <-- Xanatos --

	int		GetPrivatSlots()						{return privatSlots;} // NEO: NMFS - [NiceMultiFriendSlots] <-- Xanatos --
	int		GetReleaseSlots()						{return releaseSlots;} // NEO: RT - [ReleaseTweaks] <-- Xanatos --

	POSITION GetFirstFromUploadList()				{return uploadinglist.GetHeadPosition();}
	CUpDownClient* GetNextFromUploadList(POSITION &curpos)	{return uploadinglist.GetNext(curpos);}
	CUpDownClient* GetQueueClientAt(POSITION &curpos)	{return uploadinglist.GetAt(curpos);}

	POSITION GetFirstFromWaitingList()				{return waitinglist.GetHeadPosition();}
	CUpDownClient* GetNextFromWaitingList(POSITION &curpos)	{return waitinglist.GetNext(curpos);}
	CUpDownClient* GetWaitClientAt(POSITION &curpos)	{return waitinglist.GetAt(curpos);}

	CUpDownClient*	GetWaitingClientByIP_UDP(uint32 dwIP, uint16 nUDPPort);
	CUpDownClient*	GetWaitingClientByIP(uint32 dwIP);
	CUpDownClient*	GetNextClient(const CUpDownClient* update);

	void			AddClientDirectToQueue(CUpDownClient* client); // NEO: UPC - [UploadingProblemClient] <-- Xanatos --

	
	void	DeleteAll();
	UINT	GetWaitingPosition(CUpDownClient* client);
	
	uint32	GetSuccessfullUpCount()					{return successfullupcount;}
	uint32	GetFailedUpCount()						{return failedupcount;}
	uint32	GetAverageUpTime();

    CUpDownClient* FindBestClientInQueue();
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	void ReSortUploadSlots(CUpDownClient* client);
#else
    void ReSortUploadSlots(bool force = false);
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

	CUpDownClientPtrList waitinglist;
	CUpDownClientPtrList uploadinglist;

	void GetTransferTipInfo(CString &info); // NEO: NTT - [NewToolTips] <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	CUpDownClient*	FindClientByWebCacheUploadId(const uint32 id); 
#endif // NEO: WC END <-- Xanatos --

protected:
	friend class CemuleDlg; // NEO: ND - [NeoDebug] <-- Xanatos --

	void		RemoveFromWaitingQueue(POSITION pos, bool updatewindow);
	bool		AcceptNewClient(bool addOnNextConnect = false);
#ifndef NEO_UBT // NEO: NUBT -- Xanatos -->
	bool		AcceptNewClient(uint32 curUploadSlots);
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
	bool		AddUpNextClient(LPCTSTR pszReason, CUpDownClient* directadd = 0);
	bool		ForceNewClient(bool allowEmptyWaitingQueue = false);

	static VOID CALLBACK UploadTimer(HWND hWnd, UINT nMsg, UINT nId, DWORD dwTime);
	static void			 UploadTimer(); // NEO: ND - [NeoDebug] <-- Xanatos --

	uint32	m_uLastKadFirewallRecheck; // NEO: RKF - [RecheckKadFirewalled]

private:
	void	UpdateMaxClientScore();
	uint32	GetMaxClientScore()						{return m_imaxscore;}

    void InsertInUploadingList(CUpDownClient* newclient);
	void UpdateActiveClientsInfo(DWORD curTick);
    float GetAverageCombinedFilePrioAndCredit();

	// By BadWolf - Accurate Speed Measurement
	typedef struct TransferredData {
		uint32	datalen;
		DWORD	timestamp;
	};
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	CList<TransferredData> avarage_dr_list;
	uint32	datarate;
	uint64	m_datarateMS;
#else
	CList<uint64> avarage_dr_list;
	CList<DWORD,DWORD> avarage_tick_list;

    CList<uint64> avarage_friend_dr_list;
    uint32  friendDatarate; // datarate of sent to friends (included in above total)
	uint32	datarate;   //datarate sent to network (including friends)

	CList<int,int> activeClients_list;
    CList<DWORD,DWORD> activeClients_tick_list;
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
	// By BadWolf - Accurate Speed Measurement

	UINT_PTR h_timer;
	uint32	successfullupcount;
	uint32	failedupcount;
	uint32	totaluploadtime;
	uint32	m_nLastStartUpload;
	uint32	m_dwRemovedClientByScore;

	uint32	m_imaxscore;

    DWORD   m_dwLastCalculatedAverageCombinedFilePrioAndCredit;
    float   m_fAverageCombinedFilePrioAndCredit;
#ifndef NEO_UBT // NEO: NUBT -- Xanatos -->
    uint32  m_iHighestNumberOfFullyActivatedSlotsSinceLastCall;
    uint32  m_MaxActiveClients;
    uint32  m_MaxActiveClientsShortTime;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

    DWORD   m_lastCalculatedDataRateTick;
    uint64  m_avarage_dr_sum;

    DWORD   m_dwLastResortedUploadSlots;
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	uint32	lastUploadSlotCheck;
	bool	lastupslotHighID;
	UINT	activeSlots;
	int		waituntilnextlook;
	int		dataratestocheck;
	// NEO: BM - [BandwidthModeration]
	uint32	reservedDatarate;
	uint32	reservedSlots;
	// NEO: BM END
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	uint16	lanSlots;
#endif //LANCAST // NEO: NLC END <-- Xanatos --
	uint16	releaseSlots; // NEO: RT - [ReleaseTweaks] <-- Xanatos --
	uint16	privatSlots; // NEO: NMFS - [NiceMultiFriendSlots] <-- Xanatos --
};
