/***************************************************************************
                          cdownloadmanager.h  -  description
                             -------------------
    begin                : Don Mai 16 2002
    copyright            : (C) 2002-2004 by Mathias Küster
    email                : mathen@users.berlios.de
 ***************************************************************************/

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

#ifndef CDOWNLOADMANAGER_H
#define CDOWNLOADMANAGER_H

/**
  *@author Mathias Küster
  */

#include <dclib/dcos.h>
#include <dclib/core/cthread.h>
#include <dclib/core/csingleton.h>
#include <dclib/ctransfer.h>

#define MAX_FILE_PRIORITY 5

typedef enum eShutdownState {
	essNONE,
	essSHUTDOWN,
	essSHUTDOWNREADY
} eShutdownState;

typedef enum eCloseType {
        ectNONE=0,
	ectBOTH,
	ectDLD,
	ectUPLD
} eCloseType;

class  DLL_EXPORT CUserFileInfo : public CObject {
public:
	/** */
	CUserFileInfo() {};
	/** */
	virtual ~CUserFileInfo() {};
	/** */
	eTransferWaitState eWaitState;
	/** */
	eTransferFileState eFileState;
	/** */
	CString sLocalFile;
	/** */
	bool bMulti;
};

class  DLL_EXPORT CExtraUserSlot : public CObject {
public:
	/** */
	CExtraUserSlot() {};
	/** */
	virtual ~CExtraUserSlot() {};
	/** */
	CString sNick;
	/** */
	CString sHubName;
	/** */
	int iSlots;
	/** */
	bool bPermanent;
};

class  DLL_EXPORT DCTransferBanObject : public CObject {
public:
	/** */
	DCTransferBanObject() {
		m_nRequestCount = 0;
		m_tTime         = 0;
	};
	/** */
	virtual ~DCTransferBanObject() {};
	/** */
	CString m_sIP;
	/** */
	unsigned int m_nRequestCount;
	/** */
	time_t m_tTime;
};

class  DLL_EXPORT CDownloadManagerInfo : public CDCMessage {
public:
	/** */
	CDownloadManagerInfo() {
		m_eType  = DC_MESSAGE_DM_INFO;
		rate_ul_settings = 0;
		rate_ul_operator = 0;
		rate_ul_user     = 0;
		rate_ul_special  = 0;
		rate_dl  = 0;
		slot_max = 0;
		slot_use_settings = 0;
		slot_use_operator = 0;
		slot_use_user     = 0;
		slot_use_special  = 0;
	};
	/** */
	virtual ~CDownloadManagerInfo() {};
	/** */
	ulonglong Rate() {
		return rate_ul_settings + rate_ul_operator + rate_ul_user + rate_ul_special;
	}
	/** */
	ulonglong rate_ul_settings;
	/** */
	ulonglong rate_ul_operator;
	/** */
	ulonglong rate_ul_user;
	/** */
	ulonglong rate_ul_special;
	/** */
	ulonglong rate_dl;
	/** */
	int slot_max;
	/** slot usage with the current settings */
	int slot_use_settings;
	/** slot usage for operators */
	int slot_use_operator;
	/** slot usage for users */
	int slot_use_user;
	/** slot usage for special transfers e.g. minimum filelength */
	int slot_use_special;

	CDownloadManagerInfo & operator = (const CDownloadManagerInfo & s)
	{
		rate_ul_settings = s.rate_ul_settings;
		rate_ul_operator = s.rate_ul_operator;
		rate_ul_user     = s.rate_ul_user;
		rate_ul_special  = s.rate_ul_special;
		rate_dl  = s.rate_dl;
		slot_max = s.slot_max;
		slot_use_settings = s.slot_use_settings;
		slot_use_operator = s.slot_use_operator;
		slot_use_user     = s.slot_use_user;
		slot_use_special  = s.slot_use_special;

		return *this;
	};
};

typedef enum eFileManagerStatus {
	efmsNONE=0,
	efmsIDLE,
	efmsCREATESHARELIST,
	efmsCREATESEARCHINDEX,
	efmsCREATEHASHLIST
};

class  DLL_EXPORT CFileManagerInfo : public CDCMessage {
public:
	/** */
	CFileManagerInfo() {
		m_eType = DC_MESSAGE_FM_INFO;
		m_eFileManagerStatus = efmsNONE;
		m_nProgress = 0;
	};
	/** */
	virtual ~CFileManagerInfo() {};
	/** */
	enum eFileManagerStatus m_eFileManagerStatus;
	/** */
	double m_nProgress;

	CFileManagerInfo & operator = (const CFileManagerInfo & s)
	{
		m_eFileManagerStatus = s.m_eFileManagerStatus;
		m_nProgress          = s.m_nProgress;
		return *this;
	};
};

class CListen;
class CDownloadQueue;
class CTransfer;
class DCFileChunkObject;
class DCTransferQueueObject;
class DCTransferFileObject;
class DCTransferWait;
class CThreadStringList;
class CDownloadManager;
class _CCallback;

#ifdef WIN32
template class DLL_EXPORT CList<CExtraUserSlot>;
template class DLL_EXPORT CSingleton<CDownloadManager>;
#endif

class DLL_EXPORT CTransferObject : public CObject {
public:
	/** */
	CTransferObject() {
		m_pTransfer = 0;
		m_UserDisconnectTimeout = time(0);
	}
	/** */
	virtual ~CTransferObject() {
		if ( m_pTransfer )
			delete m_pTransfer;
	}

	/** */
	CTransfer * m_pTransfer;
	/** */
	time_t m_UserDisconnectTimeout;
};

class  DLL_EXPORT CDownloadManager : public CSingleton<CDownloadManager>, public CObject {
public: 
	/** */
	CDownloadManager();
	/** */
	virtual ~CDownloadManager();

	/** load the queue */
	int DLM_LoadQueue();
	/** save the queue */
	int DLM_SaveQueue();
	/** disconnect all transfers for a clean shutdown */
	void DLM_Shutdown();
	/** return the current shutdownstate */
	eShutdownState DLM_ShutdownState() const { return m_eShutdownState; }
	/** add a extra slot to the user */
	void DLM_AddUserSlot( CString nick, CString hubname, int slot, bool permanent = FALSE );
	/** return current used upload slots */
	int DLM_UsedSlots() const { return DownloadManagerInfo.slot_use_settings; }
	/** */
	bool DLM_TransferConnect( CString nick, CString hubname );
	/** */
	bool DLM_TransferClose( ulonglong transferid );
	/** */
	bool DLM_TransferSetRate( ulonglong transferid, ulonglong rate );
	/** */
	bool DLM_TransferGetRate( ulonglong transferid, ulonglong & rate );
	/** */
	CList<CObject> * DLM_TransferGetList();

	/** */
	eDirection DLM_TransferDirection( ulonglong transferid );

	/** */
	void DLM_QueueAdd( CString nick, CString hubname, CString hubhost,
				CString remotename, CString localname,
				CString localpath, CString localrootpath,
				eltMedium medium, ulonglong size,
				ulonglong startposition,
				ulonglong endposition,
				CString hash,
				bool multi = FALSE );
	/** */
	int DLM_QueueCheck( CString nick, CString hubname, CString hubhost,
				CString remotename, CString localname,
				CString localpath, CString localrootpath,
				eltMedium medium, ulonglong size );
	/** change the src-nick/hubname to dst-nick/hubname in the queue */
	bool DLM_QueueEdit( CString srcnick, CString srchubname, CString dstnick, CString dsthubname, CString dsthubhost );
	/** */
	bool DLM_QueuePause( CString nick, CString hubname, CString remotefile, bool pause );
	/** */
	bool DLM_QueueRemove( CString nick, CString hubname, CString remotefile );
	/** */
	bool DLM_QueueRemove( CString localfile );
	/** */
	bool DLM_QueueSetFilePriority( CString nick, CString hubname, CString remotefile, int priority );
	/** */
	bool DLM_QueueGetFileInfo( CString nick, CString hubname, CString hubhost, CString file, CUserFileInfo * UserFileInfo );
	/** */
	DCFileChunkObject * DLM_QueueGetFileChunk( CString file );
	/** */
	bool DLM_QueueUpdateHub( CString nick, CString hubname );
	/** */
	void DLM_QueueGetHub( CString nick, CString hubname, CList<DCHubObject> * list );

	/** */
	bool DLM_AddTransferRequest( CString nick, CString userhost, CString hubname, CString hubhost );
	/** */
	void DLM_AddTransferRequest( CString host, int port, CString hubname, CString hubhost );

	/** */
	bool DLM_GetDownloadManagerInfo( CDownloadManagerInfo * pinfo );
	/** handle search */
	bool DLM_HandleSearch( CMessageSearchResult * MessageSearchResult );

	/** callback function */
	int Callback( CObject * Object1, CObject * Object2 );
	/** callback function */
	virtual int DC_DownloadManagerCallBack( CObject * ) { return -1; };

	/** listen callback function */
	int DM_ListenCallBack( CObject * Sender, CObject * Object );

protected:
	/** */
	int DM_TransferCallBack( CObject * Sender, CObject * Object );

	/** */
	void SendFileManagerInfo( CFileManagerInfo * info );

private:
	/** */
	friend class CSingleton<CDownloadManager>;
	/** */
	friend class CFileManager;

	/** */
	void SendFileInfo( DCTransferQueueObject * TransferObject, DCTransferFileObject * TransferFileItem = 0, bool bRemoveFile = FALSE );
	/** */
	void SendTransferInfo( CTransfer * Transfer, bool remove = FALSE );
	/** */
	void SendSlotInfo( CExtraUserSlot * Object );
	/** */
	void SendLogInfo( CString message, CTransfer * Transfer = 0 );
	/** */
	void SendDownloadManagerInfo( CDownloadManagerInfo * dminfo );
	/** */
	void SendTrafficInfo();

	/** create a messagedmtransferobject from a transfer */
	CMessageDMTransferObject * CreateDMTransferObject( CTransfer * Transfer );
	/** */
	void FileListDone( CTransfer * Transfer );

	/** */
	bool CheckUserSlot( CString nick, CString hubname );
	/** */
	void OptimizeChunks( DCFileChunkObject * FileChunkObject );
	/** */
	bool GetNextChunk( CString file, ulonglong * lstart, ulonglong * lend );
	/** */
	int UpdateChunk( CString file, ulonglong lstart, ulonglong lend, ulonglong lcurrent );
	/** */
	bool GetNewChunkEnd( CString file, ulonglong lstart, ulonglong lend, ulonglong lcurrent, ulonglong * lnstart, ulonglong *lnend );

	/** */
	void UpdateQueueList( time_t ttimeout );
	/** */
	void UpdateTransferList( time_t ttimeout );
	/** */
	void UpdateBanList( time_t ttimeout );

	/** */
	eDirection CheckWaitTransfer( CTransfer * Transfer );
	/** */
	bool UpdateWaitTransfer( CTransfer * Transfer, bool rem = FALSE );
	/** */
	bool ChangeDirection( CTransfer * Transfer );
	/** */
	bool SetNextFile( CTransfer * Transfer );
	/** */
	bool SetDirection( CTransfer * Transfer );
	/** */
	bool SetFile( CTransfer * Transfer );
	/** */
	void UpdateFileState( CTransfer * Transfer, eTransferFileState eState );
	/** */
	bool CheckHash( CTransfer * Transfer );

	/** */
	bool RemoveQueueFile( CString nick, CString hubname, CString remotefile );
	/** */
	bool RemoveQueueFile( CString localfile );

	/** */
	bool InitSearch( time_t ttimeout );

	/** */
	ulonglong GetNewID();

	/** */
	eShutdownState m_eShutdownState;

	/** */
	CThreadList<CExtraUserSlot> *m_pExtraUserSlotList;

	/** */
	_CCallback * m_pCallback;

	/** */
	CDownloadManagerInfo DownloadManagerInfo;
	/** */
	CThread TransferCallBackThread;
	/** */
	CThread LogThread;
	/** */
	ulonglong m_nID;

	/** */
	time_t m_tDownloadQueueTimeout;
	/** */
	time_t m_tUpdateTransferTimeout;
	/** timeout for a new hubsearch */
	time_t m_tHubSearchTimeout;
	/** timeout for a single search */
	time_t m_tSearchTimeout;

	/** */
	CDownloadQueue * m_pDownloadQueue;
	/** */
	CThreadStringList * m_pTransferList;
	/** */
	CThreadList<DCTransferWait> * m_pTransferWaitList;
	/** */
	CThreadStringList * m_pTransferBanList;
	/** */
	CThreadList<CMessageSearchResult> * m_pSearchList;
	/** */
	CList<CObject> * m_pSearchQueryList;
};

#endif
