// This file is a part of the xMule Project.
//
// Copyright (c) 2004 Theodore R. Smith (donate@xmule.org / http://www.xmule.org/)
// RSA-1024 Fingerprint: 4145 9DFD 5338 4FCC 1636  86E5 2E5A 42D8 BA13 460B
//
// This file was a part of eMule
// Copyright (c) 2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

// Some worthless comment to commemorate how Avi single-handedly brought cvs down to a crashing halt (well just a little overstated) by trying to rename this file :o 
#ifndef UPDOWNCLIENT_H
#define UPDOWNCLIENT_H

#include <wx/defs.h>                    // Needed before any other wx/*.h
#include <wx/dcmemory.h>                // Needed for wxMemoryDC
#include <wx/gdicmn.h>                  // Needed for wxRect

#include <wx/string.h>                  // Needed for wxString
//#include "wintypes.h"                   // Needed for wxUint32
#include "CTypedPtrList.h"              // Needed for CTypedPtrList

class CPartFile;
class CClientReqSocket;
class CClientCredits;
class Packet;
class CFriend;
class Requested_Block_Struct;
class CKnownFile;
class Pending_Block_Struct;
class CSafeMemFile;
class CMemFile;
class CBarShader;
class Requested_File_Struct;
class TransferredData;

// uploadstate
#define	US_UPLOADING		0
#define	US_ONUPLOADQUEUE	1
#define	US_WAITCALLBACK		2
#define	US_CONNECTING		3
#define	US_PENDING			4
#define	US_LOWTOLOWIP		5
#define US_BANNED			6
#define US_ERROR			7
#define US_NONE				8

// downloadstate
#define	DS_DOWNLOADING		0
#define	DS_ONQUEUE			1
#define	DS_CONNECTED		2
#define	DS_CONNECTING		3
#define	DS_WAITCALLBACK		4
#define	DS_REQHASHSET		5
#define	DS_NONEEDEDPARTS	6
#define	DS_TOOMANYCONNS		7
#define	DS_LOWTOLOWIP		8
#define DS_BANNED			9
#define DS_ERROR			10
#define	DS_NONE				11

// m_byChatstate
#define	MS_NONE				0
#define	MS_CHATTING			1
#define	MS_CONNECTING		2
#define	MS_UNABLETOCONNECT	3

// clientsoft
#define SO_EMULE			0
#define SO_CDONKEY			1
#define SO_xmule			2
#define SO_EDONKEYHYBRID	50
#define	SO_EDONKEY			51
#define SO_MLDONKEY			52
#define SO_NEW_MLDONKEY			152
#define SO_OLDEMULE			53
#define SO_UNKNOWN			54

class CClientReqSocket;
class CFriend;

class CUpDownClient
{
	friend class CUploadQueue;
public:
	//base
	CUpDownClient(CClientReqSocket* sender = 0);
	CUpDownClient(wxUint16 in_port, wxUint32 in_userid, wxUint32 in_serverup, wxUint16 in_serverport,CPartFile* in_reqfile);
	~CUpDownClient();
	void			Destroy();
	void			Disconnected();
	void			TryToConnect(bool bIgnoreMaxCon = false);
	void			ConnectionEstablished();
	wxUint32			GetUserID()					{return m_nUserID;}
	void				SetUserID(wxUint32 nUserID)	{ m_nUserID=nUserID; }	
	char*			GetUsername()				{return m_pszUsername;}
	wxUint32			GetIP()						{return m_dwUserIP;}
	bool			HasLowID()					{return (m_nUserID < 16777216);}
	char*			GetFullIP()					{return m_szFullUserIP;}
	wxUint32			GetUserPort()				{return m_nUserPort;}
	wxUint32			GetTransferedUp()			{return m_nTransferedUp;}
	wxUint32			GetTransferedDown()			{return m_nTransferedDown;}
	wxUint32			GetServerIP()				{return m_dwServerIP;}
	void				SetServerIP(wxUint32 nIP)		{ m_dwServerIP=nIP; }
	wxUint16			GetServerPort()				{return m_nServerPort;}
	void				SetServerPort(wxUint16 nPort)		{ m_nServerPort=nPort; }
	wxByte*			GetUserHash()				{return (wxByte*)m_achUserHash;}
	void			SetUserHash(wxByte* achUserHash)		{if(achUserHash) memcpy(m_achUserHash,achUserHash,16); else memset(m_achUserHash,0,16); }
	bool			HasValidHash()				{return ((int*)m_achUserHash)[0] != 0 || ((int*)m_achUserHash)[1] != 0 ||
												        ((int*)m_achUserHash)[2] != 0 || ((int*)m_achUserHash)[3] != 0; }
	wxUint32			GetVersion()				{return m_nClientVersion;}
	wxUint8			GetMuleVersion()			{return m_byEmuleVersion;}
	bool			ExtProtocolAvailable()		{return m_bEmuleProtocol;}
	bool			IsEmuleClient()				{return m_byEmuleVersion;}
	CClientCredits* Credits()					{return credits;}
	bool			IsBanned()					{return (m_bBanned && m_nDownloadState != DS_DOWNLOADING);}
	char*			GetClientFilename()			{return m_pszClientFilename;}
	bool			SupportsUDP()				{return m_byUDPVer != 0 && m_nUDPPort != 0;}
	wxUint16			GetUDPPort()				{return m_nUDPPort;}
	void			SetUDPPort(wxUint16 nPort)	{ m_nUDPPort = nPort; }
	wxUint8			GetUDPVersion()				{return m_byUDPVer;}
	wxUint8			GetExtendedRequestsVersion(){return m_byExtendedRequestsVer;}
	bool			IsFriend()					{return m_Friend != NULL;}
	float			GetCompression()	{return (float)compressiongain/notcompressed*100.0f;} // Add rod show compression
	void			ResetCompressionGain() {compressiongain = 0; notcompressed=1;} // Add show compression

	void			RequestSharedFileList();
	void			ProcessSharedFileList(unsigned char* payload, wxUint32 nSize);
	
        wxString                 GetUploadFileInfo();

	void			SetUserName(char const* pszNewName);
	wxUint8			GetClientSoft()				{return m_clientSoft;}
	void			ReGetClientSoft();
	void			ProcessHelloAnswer(unsigned char* payload, wxUint32 nSize);
	void			ProcessHelloPacket(unsigned char* payload, wxUint32 nSize);
	void			SendHelloAnswer();
	void			SendHelloPacket();
	void			SendMuleInfoPacket(bool bAnswer);
	void			ProcessMuleInfoPacket(unsigned char* payload, wxUint32 nSize);
	void			ProcessMuleCommentPacket(unsigned char* payload, wxUint32 nSize);
	bool			Compare(CUpDownClient* tocomp);
	void			SetLastSrcReqTime();
	void			SetLastSrcAnswerTime();
	wxUint32			GetLastSrcReqTime()			{return m_dwLastSourceRequest;}
	wxUint32			GetLastSrcAnswerTime()		{return m_dwLastSourceAnswer;}
	bool			GetFriendSlot()				{return m_bFriendSlot;}
	void			SetFriendSlot(bool bNV)		{m_bFriendSlot = bNV;}
	void			SetCommentDirty(bool bDirty = true) {m_bCommentDirty = bDirty;}
	wxUint8			GetSourceExchangeVersion()	{return m_bySourceExchangeVer;}

	CClientReqSocket*	socket;
	CClientCredits*		credits;
	CFriend*			m_Friend;
	//upload
	wxUint32	compressiongain; /// Add show compression
	wxUint32  notcompressed; // Add show compression
	wxUint8			GetUploadState()			{return m_byUploadState;}
	void			SetUploadState(wxUint8 news)	{m_byUploadState = news;}
	wxUint32			GetWaitStartTime()			{return m_dwWaitTime;}
	wxUint32			GetWaitTime()				{return m_dwUploadTime-m_dwWaitTime;}
	bool			IsDownloading()				{return (m_byUploadState == US_UPLOADING);}
	bool			HasBlocks()					{return !(m_BlockSend_queue.IsEmpty() && m_BlockRequests_queue.IsEmpty());}
	wxUint32			GetDatarate()				{return m_nUpDatarate;}	
	wxUint32			GetScore(bool sysvalue, bool isdownloading = false, bool onlybasevalue = false);
	void			AddReqBlock(Requested_Block_Struct* reqblock);
	bool			CreateNextBlockPackage();
	void			SetUpStartTime(wxUint32 dwTime = 0);
	wxUint32			GetUpStartTimeDelay();
	void			SetWaitStartTime(wxUint32 dwTime = 0);
	void			SendHashsetPacket(unsigned char* forfileid);
	void			SetUploadFileID(wxByte* tempreqfileid);
	wxByte*			GetUploadFileID()	{return requpfileid;}
	CPartFile*		GetDownloadFile()	{return reqfile;}
	void			SetDownloadFile(CPartFile*);
	wxUint32			SendBlockData(wxUint32 maxammount);
	void			ClearUploadBlockRequests();
	void			SendRankingInfo();
	void			SendCommentInfo(CKnownFile *file);
	wxUint32			GetLastAskedDelay();
	void			AddRequestCount(wxByte* fileid);
	bool 			IsDifferentPartBlock();
	void			UnBan();
	void			Ban();
	wxUint32			GetBanTime()				{return m_dwBanTime;}
	wxUint32			GetAskedCount()				{return m_cAsked;}
	void			AddAskedCount()				{m_cAsked++;}
	void			SetAskedCount( wxUint32 m_cInAsked)				{m_cAsked = m_cInAsked;}
	void			FlushSendBlocks();			// call this when you stop upload, or the socket might be not able to send
	void			SetLastUpRequest();
	wxUint32			GetLastUpRequest()			{return m_dwLastUpRequest;}
	void			UDPFileReasked();
	wxUint32			GetSessionUp()			{return m_nTransferedUp - m_nCurSessionUp;}
	void			ResetSessionUp()		{m_nCurSessionUp = m_nTransferedUp;} 
	void			ProcessUpFileStatus(unsigned char* payload, wxUint32 size);
	wxUint16			GetUpPartCount()			{return m_nUpPartCount;}
	void			DrawUpStatusBar(wxMemoryDC* dc, wxRect rect, bool onlygreyrect, bool  bFlat);

	//download
	wxUint32			GetAskedCountDown()				{return m_cDownAsked;} //<<--
	void			AddAskedCountDown()				{m_cDownAsked++;}
	void			SetAskedCountDown( wxUint32 m_cInDownAsked)				{m_cDownAsked = m_cInDownAsked;}
	wxUint8			GetDownloadState()			{return m_nDownloadState;}
	void			SetDownloadState(wxUint8 byNewState);
	wxUint32			GetLastAskedTime()			{return m_dwLastAskedTime;}
	inline bool			IsPartAvailable(wxUint16 iPart)	{return	( (iPart >= m_nPartCount) || (!m_abyPartStatus) )? 0:m_abyPartStatus[iPart];}
	bool			IsUpPartAvailable(wxUint16 iPart) {return ( (iPart
 >= m_nUpPartCount) || (!m_abyUpPartStatus) )? 0:m_abyUpPartStatus[iPart];}
	wxUint8*			GetPartStatus()				{return m_abyPartStatus;}
	wxUint32			GetDownloadDatarate()		{return m_nDownDatarate;}
	wxUint16			GetRemoteQueueRank()		{return m_nRemoteQueueRank;}
	void			SetRemoteQueueFull( bool flag )	{m_bRemoteQueueFull = flag;}
	bool			IsRemoteQueueFull()			{return m_bRemoteQueueFull;}
	void			SetRemoteQueueRank(wxUint16 nr);
	void			DrawStatusBar(wxMemoryDC* dc, wxRect rect, bool onlygreyrect, bool  bFlat);
	void			AskForDownload();
	void			SendFileRequest();
	void			ProcessFileInfo(unsigned char* payload, wxUint32 size);
	void			ProcessFileStatus(unsigned char* payload, wxUint32 size);
	void			ProcessHashSet(unsigned char* payload, wxUint32 size);
	bool			AddRequestForAnotherFile(CPartFile* file);
	void			SendBlockRequests();
	void			ProcessBlockPacket(unsigned char* payload, wxUint32 size, bool packed = false);
	wxUint32			CalculateDownloadRate();
	wxUint16			GetAvailablePartCount();
	//			SwapToAnotherFile(bool bIgnoreNoNeeded = false);   Razor 1a - Modif by MikaelB 
	void			UDPReaskACK(wxUint16 nNewQR);
	void			UDPReaskFNF();
	void			UDPReaskForDownload();
	bool			IsSourceRequestAllowed();

	wxUint16 GetUpCompleteSourcesCount() { return m_nUpCompleteSourcesCount; }
	void SetUpCompleteSourcesCount(wxUint16 n) { m_nUpCompleteSourcesCount = n; }
	
	int				sourcesslot;

	//chat
	wxUint8			GetChatState()				{return m_byChatstate;}
	void			SetChatState(wxUint8 nNewS)	{m_byChatstate = nNewS;}

	//File Comment 
    wxString			GetFileComment()			{return m_strComment;} 
    void			SetFileComment(wxChar const *desc)	{ m_strComment = desc; }
    wxUint8			GetFileRate()				{return m_iRate;}
    void			SetFileRate(wxInt8 iNewRate)	{m_iRate=iNewRate;}

	// Barry - Process zip file as it arrives, don't need to wait until end of block
	int unzip(Pending_Block_Struct *block, wxByte *zipped, wxUint32 lenZipped, wxByte **unzipped, wxUint32 *lenUnzipped, bool recursive = false);
	// Barry - Sets string to show parts downloading, eg NNNYNNNNYYNYN
	void ShowDownloadingParts(wxString &partsYN);
	void UpdateDisplayedInfo(bool force=false);
	int  GetFileListRequested() { return m_iFileListRequested; }
	void SetFileListRequested(int iFileListRequested) { m_iFileListRequested = iFileListRequested; }

private:
	CPartFile*		reqfile;

	// base
	void	Init();
	void	ProcessHelloTypePacket(CSafeMemFile const& data);
	void	SendHelloTypePacket(CMemFile& data);
	bool	m_bIsBotuser;
//	bool	isfriend;
	wxUint32	m_dwUserIP;
	wxUint32	m_dwServerIP;
	wxUint32	m_nUserID;
	wxInt16	m_nUserPort;
	wxInt16	m_nServerPort;
	wxUint32	m_nClientVersion;
	wxUint32	m_nUpDatarate;
	wxUint32	dataratems;
	wxUint32	m_cSendblock;
	wxUint8	m_byEmuleVersion;
	wxUint8	m_byDataCompVer;
	bool	m_bEmuleProtocol;
	char*	m_pszUsername;
	char	m_szFullUserIP[21];
	char	m_achUserHash[16];
	wxUint16	m_nUDPPort;
	wxUint8	m_byUDPVer;
	wxUint8	m_bySourceExchangeVer;
	wxUint8	m_byAcceptCommentVer;
	wxUint8	m_byExtendedRequestsVer;
	wxUint8	m_cFailed;
	wxUint8	m_clientSoft;
	wxUint32	m_dwLastSourceRequest;
	wxUint32	m_dwLastSourceAnswer;
	int	m_iFileListRequested;
	bool	m_bFriendSlot;
	bool	m_bCommentDirty;
	bool	m_bIsHybrid;
	bool	m_bIsNewMLD;
	wxUint32	m_byCompatableClient;
	CTypedPtrList<CPtrList, Packet*>				 m_WaitingPackets_list;
	wxUint32	m_lastRefreshedDLDisplay;

	//upload
	void CreateStandartPackets(wxByte* data,wxUint32 togo, Requested_Block_Struct* currentblock);
	void CreatePackedPackets(wxByte* data,wxUint32 togo, Requested_Block_Struct* currentblock);
	bool		m_bBanned;
	wxUint32		m_nTransferedUp;
	wxUint8		m_byUploadState;
	wxUint32		m_dwWaitTime;
	wxUint32		m_dwUploadTime;
	wxUint32		m_nMaxSendAllowed;
	wxUint32		m_nAvUpDatarate;
	wxUint32		m_cAsked;
	wxUint32		m_dwLastUpRequest;
	wxUint32		m_dwBanTime;
	bool		m_bUsedComprUp;	//only used for interface output
	wxUint32		m_nCurSessionUp;
	wxUint16		m_nUpPartCount;
	static		CBarShader s_UpStatusBar;
	wxByte		requpfileid[16];
	wxUint16 m_nUpCompleteSourcesCount;
	public:
	wxUint8*		m_abyUpPartStatus;
	wxUint32		m_nSumForAvgUpDataRate;

	private:
	CList<int,int>									 m_AvarageUDR_list;
	CTypedPtrList<CPtrList, Packet*>				 m_BlockSend_queue;
	CTypedPtrList<CPtrList, Requested_Block_Struct*> m_BlockRequests_queue;
	CTypedPtrList<CPtrList, Requested_Block_Struct*> m_DoneBlocks_list;
	CTypedPtrList<CPtrList, Requested_File_Struct*>	 m_RequestedFiles_list;
	//download
	bool		m_bRemoteQueueFull;
	bool		usedcompressiondown; //only used for interface output
	wxUint8		m_nDownloadState;
	wxUint16		m_nPartCount;
	wxUint32		m_cDownAsked;
	wxUint8*		m_abyPartStatus;
	wxUint32		m_dwLastAskedTime;
	char*		m_pszClientFilename;
	wxUint32		m_nTransferedDown;
	wxUint32      m_nLastBlockOffset;   // Patch for show parts that you download [Cax2]
	wxUint32		m_nDownDatarate;
	wxUint32		m_nDownDataRateMS;
	wxUint32		m_nAvDownDatarate;
	wxUint16		m_cShowDR;
	wxUint32		m_dwLastBlockReceived;
	wxUint16		m_nRemoteQueueRank;
	bool		m_bCompleteSource;
	bool		m_bReaskPending;
	bool		m_bUDPPending;
	wxUint32		m_nSumForAvgDownDataRate;
	bool		m_bHashsetRequested;

	CList<int,int>									 m_AvarageDDR_list;
	CTypedPtrList<CPtrList, Pending_Block_Struct*>	 m_PendingBlocks_list;
 // CTypedPtrList<CPtrList, CPartFile*>	 m_OtherRequests_list;    ---> See Razor 1a modif  : becomes public
	CTypedPtrList<CPtrList, Requested_Block_Struct*> m_DownloadBlocks_list;
	CTypedPtrList<CPtrList, CPartFile*>				 m_OtherNoNeeded_list;

	static CBarShader s_StatusBar;
	// chat
	wxUint8 m_byChatstate;
	wxString m_strComment;
	wxInt8 m_iRate;

  /* Razor 1a - Modif by MikaelB */
  
      public:

          /* m_OtherRequests_list --> public instead of private */
          CTypedPtrList<CPtrList, CPartFile*>	 m_OtherRequests_list;

          /* IsValidSource function
           * @return true id it's valid source
           */
          bool IsValidSource() const
          {
            return m_ValidSource;
          };

          /* SetValidSource function
           * @param boolean - set valid source
           */
          void SetValidSource(bool in)
          {
            m_ValidSource = in;
          };

          /* SwapToThisFile function
           * @param CPartFile* - the file
           */
          void SwapToThisFile(CPartFile* file);

          /* SwapToAnotherFile function */
          bool SwapToAnotherFile();

      private:
      
          /* valid source attribute */
          bool m_ValidSource;

  /* End modif */
	  
  // Support for tag ET_MOD_VERSION [BlackRat]
  public:
	
  		const wxString	GetClientModString() const { return m_clientModString; }
		const wxString	GetClientVerString() const { return m_clientVerString; }

  private:
	  
	    wxString		m_clientModString; 
	    wxString		m_clientVerString;
	
  // Hash anti-thief from HoaX_69 [BlackRat]
  public:

	bool			thief;  // is a thief ?
	wxUint64	getUID() 
 	{
			wxUint64 ip = ((wxUint64) m_dwUserIP) << 32;
			wxUint64 port = ((wxUint64) m_nUserPort) << 16;
			wxUint64 uid = ip + port;
			return uid;
	}		
		//return ((wxUint64)m_dwUserIP<<32)+((wxUint64)m_nUserPort<<16); }
	int				leechertype;  // what kind of leecher is it ?
  
};

#endif // UPDOWNCLIENT_H
