// This file is a part of the xMule Project.
//
// Copyright (c) 2004 Theodore R. Smith (hopeseekr@xmule.ws / http://www.xmule.ws/)
// DSA-1024 Fingerprint: 10A0 6372 9092 85A2 BB7F 907B CB8B 654B E33B F1ED
//
// Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.xmule-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.

#ifndef _UPDOWNCLIENT_H
#define _UPDOWNCLIENT_H

#include "mfc.h"                            // Needed for wxString - audited 4 Nov 2004
#include "wintypes.h"                       // Needed for BYTE DWORD - audited 4 Nov 2004
#include "BarShader.h"                      // Needed for CBarShader - audited 5 Nov 2004

#include <iostream>                         // Needed for std::cout std::endl
#include <stdint.h>                         // Needed for uint16_t uint32_t

class CClientCredits;
class CKnownFile;
class CListenSocket;
class CMemFile;
class CPartFile;
class CSafeMemFile;
class Packet;
class Pending_Block_Struct;
class Requested_Block_Struct;
class Requested_File_Struct;
typedef unsigned char byte;
extern long GetTickCount();


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

enum EClientSoftware {
	SO_EMULE			= 0,
	SO_CDONKEY			= 1,
	SO_XMULE			= 2,
	SO_AMULE			= 3,
	SO_SHAREAZA			= 4,
	SO_EDONKEYHYBRID		= 50,
	SO_EDONKEY			= 51,
	SO_MLDONKEY			= 52,
	SO_OLDEMULE			= 53,
	SO_UNKNOWN			= 54,
	SO_NEW_MLDONKEY			= 152,
};

enum ESecureIdentState {
	IS_UNAVAILABLE = 0,
	IS_ALLREQUESTSSEND = 0,
	IS_SIGNATURENEEDED = 1,
	IS_KEYANDSIGNEEDED =2,
};

enum EInfoPacketState {
	IP_NONE = 0,
	IP_EDONKEYPROTPACK = 1,
	IP_EMULEPROTPACK = 2,
	IP_BOTH = 3,
};

class CClientReqSocket;
class CFriend;

class CUpDownClient
{
	friend class CUploadQueue;
public:
	//base
	CUpDownClient(CClientReqSocket* sender = 0);
	CUpDownClient(uint16_t in_port, uint32_t in_userid, uint32_t in_serverup, uint16_t in_serverport,CPartFile* in_reqfile);
	~CUpDownClient();
	void			Destroy();
	void			Disconnected();
	bool			TryToConnect(bool bIgnoreMaxCon = false);
	void			ConnectionEstablished();
	uint32_t			GetUserID()					{return m_nUserID;}
	void			SetUserID(uint32_t nUserID)			{ m_nUserID=nUserID; }
	char*			GetUserName()				{return m_pszUsername;}
	uint32_t			GetIP()						{return m_dwUserIP;}
	bool			HasLowID()					{return (m_nUserID < 16777216);}
	char*			GetFullIP()					{return m_szFullUserIP;}
	uint32_t			GetUserPort()				{return m_nUserPort;}
	uint32_t			GetTransferedUp()			{return m_nTransferedUp;}
	uint32_t			GetTransferedDown()			{return m_nTransferedDown;}
	uint32_t			GetServerIP()				{return m_dwServerIP;}
	void			SetServerIP(uint32_t nIP)		{ m_dwServerIP=nIP; }
	uint16_t			GetServerPort()				{return m_nServerPort;}
	void			SetServerPort(uint16_t nPort)		{ m_nServerPort=nPort; }
	unsigned char*			GetUserHash()				{return (unsigned char*)m_achUserHash;}
	void			SetUserHash(unsigned char* achUserHash);
	bool			HasValidHash()				{return ((int*)m_achUserHash)[0] != 0 || ((int*)m_achUserHash)[1] != 0 ||
												        ((int*)m_achUserHash)[2] != 0 || ((int*)m_achUserHash)[3] != 0; }
	int			GetHashType();
	uint32_t			GetVersion()				{return m_nClientVersion;}
	uint8_t			GetMuleVersion()			{if(m_byEmuleVersion==0x99) return 0x42; else 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;}
	wxString		GetClientFilename_NEW() const		{return m_strClientFilename;}
	bool			SupportsUDP()				{return m_byUDPVer != 0 && m_nUDPPort != 0;}
	uint16_t			GetUDPPort()				{return m_nUDPPort;}
	void			SetUDPPort(uint16_t nPort)	{ m_nUDPPort = nPort; }
	uint8_t			GetUDPVersion()				{return m_byUDPVer;}
	uint8_t			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(char* pachPacket, uint32_t nSize);
	
        wxString                 GetUploadFileInfo();

	void			SetUserName(char* pszNewName);
	EClientSoftware		GetClientSoft()				{return m_clientSoft;}
	void			ReGetClientSoft();
	bool			ProcessHelloAnswer(char* pachPacket, uint32_t nSize);
	bool			ProcessHelloPacket(char* pachPacket, uint32_t nSize);
	void			SendHelloAnswer();
	void			SendHelloPacket();
	void			SendMuleInfoPacket(bool bAnswer);
	void			ProcessMuleInfoPacket(char* pachPacket, uint32_t nSize);
	void			ProcessMuleCommentPacket(char* pachPacket, uint32_t nSize);
	bool			Compare(CUpDownClient* tocomp);
	void			SetLastStateChange()	{m_dwLastStateChange = ::GetTickCount();}
	void			SetLastSrcReqTime()		{m_dwLastSourceRequest = ::GetTickCount();}
	void			SetLastSrcAnswerTime()		{m_dwLastSourceAnswer = ::GetTickCount();}
	void			SetLastAskedForSources()	{m_dwLastAskedForSources = ::GetTickCount();}
	uint32_t			GetLastStateChange()	{return m_dwLastStateChange;}
	uint32_t			GetLastSrcReqTime()			{return m_dwLastSourceRequest;}
	uint32_t			GetLastSrcAnswerTime()		{return m_dwLastSourceAnswer;}
	uint32_t			GetLastAskedForSources()	{ return m_dwLastAskedForSources;}
	bool			GetFriendSlot()				{return m_bFriendSlot;}
	void			SetFriendSlot(bool bNV)		{m_bFriendSlot = bNV;}
	void			SetCommentDirty(bool bDirty = true) {m_bCommentDirty = bDirty;}
	uint8_t			GetSourceExchangeVersion()	{return m_bySourceExchangeVer;}

	void			SendPublicKeyPacket();
	void			SendSignaturePacket();
	void			ProcessPublicKeyPacket(unsigned char* pachPacket, uint32_t nSize);
	void			ProcessSignaturePacket(unsigned char* pachPacket, uint32_t nSize);
	uint8_t			GetSecureIdentState()		{return m_SecureIdentState;}
	void			SendSecIdentStatePacket();
	void			ProcessSecIdentStatePacket(unsigned char* pachPacket,uint32_t nSize);
	uint8_t			GetInfoPacketsReceived() const { return m_byInfopacketsReceived; }
	void			InfoPacketsReceived();
	void			ResetFileStatusInfo();

	bool			SupportsPreview()		{return m_bSupportsPreview;}
	bool			SafeSendPacket(Packet* packet);

	CClientReqSocket*	socket;
private:
	CClientCredits*		credits;
public:
	CFriend*			m_Friend;
	//upload
	uint32_t	compressiongain; /// Add show compression
	uint32_t  notcompressed; // Add show compression
	uint8_t			GetUploadState()			{return m_byUploadState;}
	void			SetUploadState(uint8_t news)	{m_byUploadState = news;}
	uint32_t			GetWaitStartTime()			{return m_dwWaitTime;}
	uint32_t			GetWaitTime()				{return m_dwUploadTime-m_dwWaitTime;}
	bool			IsDownloading()				{return (m_byUploadState == US_UPLOADING);}
	bool			HasBlocks()					{return !(m_BlockSend_queue.IsEmpty() && m_BlockRequests_queue.IsEmpty());}
	uint32_t			GetDatarate()				{return m_nUpDatarate;}	
	uint32_t			GetScore(bool sysvalue, bool isdownloading = false, bool onlybasevalue = false);
	void			AddReqBlock(Requested_Block_Struct* reqblock);
	bool			CreateNextBlockPackage();
	void			SetUpStartTime(uint32_t dwTime = 0);
	uint32_t			GetUpStartTimeDelay()		{return ::GetTickCount() - m_dwUploadTime;}
	void			SetWaitStartTime(uint32_t dwTime = 0);
	void			SendHashsetPacket(char* forfileid);
	void			SetUploadFileID(unsigned char* tempreqfileid);
	unsigned char*			GetUploadFileID()	{return requpfileid;}
	CPartFile*		GetDownloadFile()	{return reqfile;}
	void			SetDownloadFile(CPartFile*);
	uint32_t			SendBlockData(uint32_t maxammount);
	void			ClearUploadBlockRequests();
	void			SendRankingInfo();
	void			SendCommentInfo(CKnownFile *file);
	uint32_t			GetLastAskedDelay();
	void			AddRequestCount(unsigned char* fileid);
	bool 			IsDifferentPartBlock();
	void			UnBan();
	void			Ban();
	uint32_t			GetBanTime()				{return m_dwBanTime;}
	uint32_t			GetAskedCount()				{return m_cAsked;}
	void			AddAskedCount()				{m_cAsked++;}
	void			SetAskedCount( uint32_t 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()			{m_dwLastUpRequest = ::GetTickCount();}
	uint32_t			GetLastUpRequest()			{return m_dwLastUpRequest;}
	void			UDPFileReasked();
	uint32_t			GetSessionUp()			{return m_nTransferedUp - m_nCurSessionUp;}
	void			ResetSessionUp()		{m_nCurSessionUp = m_nTransferedUp;} 
	void			ProcessUpFileStatus(char* packet,uint32_t size);
	uint16_t			GetUpPartCount()			{return m_nUpPartCount;}
	void			DrawUpStatusBar(wxMemoryDC* dc, wxRect rect, bool onlygreyrect, bool  bFlat);

	//download
	uint32_t			GetAskedCountDown()				{return m_cDownAsked;} //<<--
	void			AddAskedCountDown()				{m_cDownAsked++;}
	void			SetAskedCountDown( uint32_t m_cInDownAsked)				{m_cDownAsked = m_cInDownAsked;}
	uint8_t			GetDownloadState()			{return m_nDownloadState;}
	void			SetDownloadState(uint8_t byNewState);
	uint32_t			GetLastAskedTime()			{return m_dwLastAskedTime;}
	
    bool IsPartAvailable(uint16_t iPart)
    {
        bool status = false;
        try
        {
            status = ((iPart >= m_nPartCount) || (!m_abyPartStatus))  ? 0 : m_abyPartStatus[iPart];
        }
        catch(...)
        {
            std::cout << "Caught deadly error in CUpDownClient::IsPartAvailable(" << iPart << ")!" << std::endl;
            status = false;
        }

        return status;
    }

    bool IsUpPartAvailable(uint16_t iPart)
    {
        bool status = false;
        try
        {
            status = ((iPart >= m_nUpPartCount) || (!m_abyUpPartStatus))? 0 : m_abyUpPartStatus[iPart];
        }
        catch(...)
        {
            std::cout << "Caught deadly error in CUpDownClient::IsUpPartAvailable(" << iPart << ")!" << std::endl;
            status = false;
        }

        return status;
    }
	uint8_t*			GetPartStatus()				{return m_abyPartStatus;}
	uint32_t			GetDownloadDatarate()		{return m_nDownDatarate;}
	uint16_t			GetRemoteQueueRank()		{return m_nRemoteQueueRank;}
	void			SetRemoteQueueFull( bool flag )	{m_bRemoteQueueFull = flag;}
	bool			IsRemoteQueueFull()			{return m_bRemoteQueueFull;}
	void			SetRemoteQueueRank(uint16_t nr);
	void			DrawStatusBar(wxMemoryDC* dc, wxRect rect, bool onlygreyrect, bool  bFlat);
	void			AskForDownload();
	void			SendFileRequest_HOPE();
	void			SendFileRequest();
	void			ProcessFileInfo(char* packet,uint32_t size);
	void			ProcessFileStatus(char* packet,uint32_t size);
	void			ProcessHashSet(unsigned char* packet,uint32_t size);
	bool			AddRequestForAnotherFile(CPartFile* file);
	void			SendBlockRequests();
	void			ProcessBlockPacket(char* packet, uint32_t size, bool packed = false);
	uint32_t			CalculateDownloadRate();
	uint16_t			GetAvailablePartCount();
	//			SwapToAnotherFile(bool bIgnoreNoNeeded = false);   Razor 1a - Modif by MikaelB 

	void			UDPReaskACK(uint16_t nNewQR);
	void			UDPReaskFNF();
	void			UDPReaskForDownload();
	bool			IsSourceRequestAllowed();

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

	//chat
	uint8_t			GetChatState()				{return m_byChatstate;}
	void			SetChatState(uint8_t nNewS)	{m_byChatstate = nNewS;}
	bool			m_bIsSpammer;
	uint8_t			m_cMessagesReceived; //Count of chatmessages he sent to me
	uint8_t			m_cMessagesSend; //Count of chatmessages i sent to him

	//File Comment 
    wxString			GetFileComment()			{return m_strComment;} 
    void			SetFileComment(char *desc)	{m_strComment.Printf("%s",desc);}
    uint8_t			GetFileRate()				{return m_iRate;}
    void			SetFileRate(int8_t 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, BYTE *zipped, uint32_t lenZipped, BYTE **unzipped, uint32_t *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; }
	uint8_t	m_cFailed;
    bool deletethis;
    bool SpecialPerson;
private:
	CPartFile*		reqfile;

	// base
	void	Init();
	bool	ProcessHelloTypePacket(CSafeMemFile* data);
	void	SendHelloTypePacket(CMemFile* data);
	bool	m_bIsBotuser;
//	bool	isfriend;
	uint32_t	m_dwUserIP;
	uint32_t	m_dwServerIP;
	uint32_t	m_nUserID;
	int16_t	m_nUserPort;
	int16_t	m_nServerPort;
	uint32_t	m_nClientVersion;
	uint32_t	m_nUpDatarate;
	uint32_t	dataratems;
	uint32_t	m_cSendblock;
	uint8_t	m_byEmuleVersion;
	uint8_t	m_byDataCompVer;
	bool	m_bEmuleProtocol;
	char*	m_pszUsername;
	char	m_szFullUserIP[21];
	char	m_achUserHash[16];
	uint16_t	m_nUDPPort;
	uint8_t	m_byUDPVer;
	uint8_t	m_bySourceExchangeVer;
	uint8_t	m_byAcceptCommentVer;
	uint8_t	m_byExtendedRequestsVer;
	EClientSoftware	m_clientSoft;
	uint32_t	m_dwLastSourceRequest;
	uint32_t	m_dwLastSourceAnswer;
	uint32_t  m_dwLastAskedForSources;
	uint32_t  m_dwLastStateChange;
	int	m_iFileListRequested;
	bool	m_bFriendSlot;
	bool	m_bCommentDirty;
	bool	m_bIsHybrid;
	bool	m_bIsML;
	bool	m_bGPLEvildoer;
	bool	m_bPreviewReqPending;
	bool	m_bPreviewAnsPending;
	uint16_t	m_nKadPort;
	bool	m_bMultiPacket;

	ESecureIdentState	m_SecureIdentState;
	uint8_t	m_byInfopacketsReceived;
	uint32_t	m_dwLastSignatureIP;
	uint8_t	m_bySupportSecIdent;
	bool	m_bySupportsPreview;
	
	uint32_t	m_byCompatibleClient;
	CTypedPtrList<CPtrList, Packet*>				 m_WaitingPackets_list;
	DWORD	m_lastRefreshedDLDisplay;

	//upload
	void CreateStandartPackets(byte* data,uint32_t togo, Requested_Block_Struct* currentblock);
	void CreatePackedPackets(byte* data,uint32_t togo, Requested_Block_Struct* currentblock);
	bool		m_bBanned;
	uint32_t		m_nTransferedUp;
	uint8_t		m_byUploadState;
	uint32_t		m_dwWaitTime;
	uint32_t		m_dwUploadTime;
	uint32_t		m_nMaxSendAllowed;
	uint32_t		m_nAvUpDatarate;
	uint32_t		m_cAsked;
	uint32_t		m_dwLastUpRequest;
	uint32_t		m_dwBanTime;
	bool		m_bUsedComprUp;	//only used for interface output
	uint32_t		m_nCurSessionUp;
	uint16_t		m_nUpPartCount;
	static		CBarShader s_UpStatusBar;
	unsigned char		requpfileid[16];
	uint16_t m_nUpCompleteSourcesCount;
	public:
	uint8_t*		m_abyUpPartStatus;
	uint16_t		m_lastPartAsked;
	DWORD		m_dwEnteredConnectedState;
	wxString		m_strModVersion;
	uint32_t		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
	uint8_t		m_nDownloadState;
	uint16_t		m_nPartCount;
	uint32_t		m_cDownAsked;
	uint8_t*		m_abyPartStatus;
	uint32_t		m_dwLastAskedTime;
	wxString	m_strClientFilename;
	char*		m_pszClientFilename;
	uint32_t		m_nTransferedDown;
	uint32_t      m_nLastBlockOffset;   // Patch for show parts that you download [Cax2]
	uint32_t		m_nDownDatarate;
	uint32_t		m_nDownDataRateMS;
	uint32_t		m_nAvDownDatarate;
	uint16_t		m_cShowDR;
	uint32_t		m_dwLastBlockReceived;
	uint16_t		m_nRemoteQueueRank;
	bool		m_bCompleteSource;
	bool		m_bReaskPending;
	bool		m_bUDPPending;
	uint32_t		m_nSumForAvgDownDataRate;
	bool		m_bHashsetRequested;
	bool		m_bSharedDirectories;
 	bool		m_bNoViewSharedFiles;
	bool		m_bSupportsPreview;

	CList<int,int>	 m_AvarageDDR_list;
	int32_t		sumavgDDR;
	int32_t		sumavgUDR;
	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
	uint8_t m_byChatstate;
	wxString m_strComment;
	int8_t 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 ?
	uint64_t	getUID() 
 	{
			uint64_t ip = ((uint64_t) m_dwUserIP) << 32;
			uint64_t port = ((uint64_t) m_nUserPort) << 16;
			uint64_t uid = ip + port;
			return uid;
	}		
		//return ((uint64_t)m_dwUserIP<<32)+((uint64_t)m_nUserPort<<16); }
	int				leechertype;  // what kind of leecher is it ?
  
};

#endif
