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

#pragma once
#include "knownfile.h"
#include "types.h"
#include "opcodes.h"
#include "BarShader.h"

#define	PS_READY			0
#define	PS_EMPTY			1
#define PS_WAITINGFORHASH	2
#define PS_HASHING			3
#define PS_ERROR			4
#define PS_INSUFFICIENT		5	// SLUGFILLER: checkDiskspace
#define	PS_UNKNOWN			6
#define PS_PAUSED			7
#define PS_COMPLETING		8
#define PS_COMPLETE			9

#define PR_VERYLOW			4 // I Had to change this because it didn't save negative number correctly.. Had to modify the sort function for this change..
#define PR_LOW				0 //*
#define SRV_PR_LOW			2
#define PR_NORMAL			1 // Don't change this - needed for edonkey clients and server!
#define SRV_PR_NORMAL		0
#define	PR_HIGH				2 //*
#define SRV_PR_HIGH			1
#define PR_VERYHIGH			3
#define PR_AUTO				5 //UAP Hunter

//#define BUFFER_SIZE_LIMIT	500000 // Max bytes before forcing a flush
#define BUFFER_TIME_LIMIT	60000   // Max milliseconds before forcing a flush

#define	PARTMET_BAK_EXT	_T(".bak")
#define	PARTMET_TMP_EXT	_T(".backup")

#define STATES_COUNT		13

class CSearchFile;
class CUpDownClient;
class CxImage;

struct PartFileBufferedData
{
	BYTE *data;						// Barry - This is the data to be written
	uint32 start;					// Barry - This is the start offset of the data
	uint32 end;						// Barry - This is the end offset of the data
	Requested_Block_Struct *block;	// Barry - This is the requested block that this data relates to
};

class CPartFile : public CKnownFile {
public:
	friend class CPartFileConvert;

	CPartFile();
	CPartFile(CSearchFile* searchresult);  //used when downloading a new file
	CPartFile(CString edonkeylink);
	CPartFile(class CED2KFileLink* fileLink);
	void InitializeFromLink(CED2KFileLink* fileLink);
	virtual ~CPartFile();
	
	bool	CreateFromFile(LPCTSTR directory,LPCTSTR filename)	{return false;}// not supported in this class
	bool	LoadFromFile(FILE* file)						{return false;}
	bool	WriteToFile(FILE* file)							{return false;}
	bool	IsPartFile()									{return !(status == PS_COMPLETE);}
	uint32	Process(uint32 reducedownload,uint8 m_icounter, uint32 friendReduceddownload);
	uint8	LoadPartFile(LPCTSTR in_directory, LPCTSTR filename, bool getsizeonly=false); //filename = *.part.met
	bool	SavePartFile();
	void	PartFileHashFinished(CKnownFile* result);
	bool	HashSinglePart(uint16 partnumber); // true = ok , false = corrupted	
	uint64	GetRealFileSize();
	bool	IsNormalFile() const { return (m_dwFileAttributes & (FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_SPARSE_FILE)) == 0; }

	void	AddGap(uint32 start, uint32 end);
	void	FillGap(uint32 start, uint32 end);
	void	DrawStatusBar(CDC* dc, RECT* rect, bool bFlat);
	void	DrawShareStatusBar(CDC* dc, RECT* rect, bool onlygreyrect, bool  bFlat);
	bool	IsComplete(uint32 start, uint32 end);
	bool	IsPureGap(uint32 start, uint32 end);
	bool	IsCorruptedPart(uint16 partnumber);
	void	UpdateCompletedInfos();

	bool	GetNextRequestedBlock(CUpDownClient* sender,Requested_Block_Struct** newblocks,uint16* count);
	void	WritePartStatus(CFile* file);
	void	WriteCompleteSourcesCount(CFile* file);
	void	AddSources(CMemFile* sources,uint32 serverip, uint16 serverport);
	static bool	CanAddSource(uint32 userid, uint16 port, uint32 serverip, uint16 serverport, uint8* pdebug_lowiddropped = NULL);
	uint8	GetStatus(bool ignorepause = false);
	bool	GetCompletionError() const { return m_bCompletionError; }
	void	NewSrcPartsInfo();
	void	SetDownPriority(uint8 iNewDownPriority);
	bool	IsAutoDownPriority(void)		{return m_bAutoDownPriority;};
	void	SetAutoDownPriority(bool NewAutoDownPriority) {m_bAutoDownPriority = NewAutoDownPriority;};
	void	UpdateAutoDownPriority();
	const CString& GetPartMetFileName() const				{return m_partmetfilename;}
	uint32	GetTransfered()									{return transfered;}
	uint8	GetDownPriority()								{return m_iDownPriority;}
	const CString& GetFullName() const						{return m_fullname;}
	uint16	GetSourceCount();
	uint16	GetSrcA4AFCount()								{return A4AFsrclist.GetCount();}
	uint16  GetSrcStatisticsValue(uint16 value); // value = EDownloadState
	uint16	GetTransferingSrcCount();			// == GetSrcStatisticsValue(DS_DOWNLOADING) 
	uint32	GetDatarate()									{return datarate;}
	float	GetPercentCompleted()							{return percentcompleted;}
	uint16  GetNotCurrentSourcesCount();
	int		GetValidSourcesCount();
	uint32	GetNeededSpace(); // SLUGFILLER: checkDiskspace
	bool	IsArchive(bool onlyPreviewable=false); // Barry - Also want to preview archives
	CString CPartFile::getPartfileStatus(); //<<--9/21/02
	sint32	CPartFile::getTimeRemaining(); //<<--9/21/02
	CTime	lastseencomplete;
	int		getPartfileStatusRang();
	// CString	GetDownloadFileInfo(); moved to WebServer.h

	// Barry - Added as replacement for BlockReceived to buffer data before writing to disk
	uint32	WriteToBuffer(uint32 transize, BYTE *data, uint32 start, uint32 end, Requested_Block_Struct *block);
	void	FlushBuffer(void);
	// Barry - This will invert the gap list, up to caller to delete gaps when done
	// 'Gaps' returned are really the filled areas, and guaranteed to be in order
	void	GetFilledList(CTypedPtrList<CPtrList, Gap_Struct*> *filled);

	// Barry - Is archive recovery in progress
	volatile bool m_bRecoveringArchive;

	// Barry - Added to prevent list containing deleted blocks on shutdown
	void	RemoveAllRequestedBlocks(void);

	void	RemoveBlockFromList(uint32 start,uint32 end);
	void	RemoveAllSources(bool bTryToSwap);
	void	DeleteFile();
	void	StopFile(bool bCancel = false);
	void	PauseFile(bool bInsufficient = false);
	void	ResumeFile();
	// SLUGFILLER: checkDiskspace
	void	ResumeFileInsufficient();
	// SLUGFILLER: checkDiskspace

	virtual	Packet* CreateSrcInfoPacket(CUpDownClient* forClient);
	void	AddClientSources(CMemFile* sources, uint8 sourceexchangeversion);

	void	PreviewFile();
	bool	PreviewAvailable();
	uint16	GetAvailablePartCount()			{return availablePartsCount;}
	void	UpdateAvailablePartsCount();

	uint32	GetLastAnsweredTime()			{ return m_ClientSrcAnswered; }
	void	SetLastAnsweredTime()			{ m_ClientSrcAnswered = ::GetTickCount(); }
	void	SetLastAnsweredTimeTimeout()	{ m_ClientSrcAnswered = 2 * CONNECTION_LATENCY +
											                        ::GetTickCount() - SOURCECLIENTREASK; }
	uint64	GetLostDueToCorruption()		{return m_iLostDueToCorruption;}
	uint64	GetGainDueToCompression()		{return m_iGainDueToCompression;}
	uint32	TotalPacketsSavedDueToICH()		{return m_iTotalPacketsSavedDueToICH;}
	bool	HasComment()					{return hasComment;}
	bool	HasRating()						{return hasRating;}
	bool	HasBadRating()					{return hasBadRating;}
	bool	IsStopped()						{return stopped;}
	void	SetHasComment(bool in)			{hasComment=in;}
	void	SetHasRating(bool in)			{hasRating=in;}
	void	UpdateFileRatingCommentAvail();
	void	AddDownloadingSource(CUpDownClient* client);
	void	RemoveDownloadingSource(CUpDownClient* client);
	void	SetStatus(uint8 in);
	void	StopPausedFile();

	void	SetA4AFAuto(bool in)			{m_is_A4AF_auto = in;} // [sivka / Tarod]
	bool	IsA4AFAuto()					{return m_is_A4AF_auto;} // [sivka / Tarod]
	CString GetProgressString(uint16 size);
	CString GetInfoSummary(CPartFile* partfile);

	int		GetCommonFilePenalty();
	void	UpdateDisplayedInfo(boolean force=false);
	uint8	GetCategory();
	void	SetCategory(uint8 cat);
	void	GetSizeToTransferAndNeededSpace(uint32& pui32SizeToTransfer, uint32& pui32NeededSpace);
	uint8*	MMCreatePartStatus();

	//preview
	bool	GrabImage(uint8 nFramesToGrab, double dStartTime, bool bReduceColor, uint16 nMaxWidth,void* pSender);
	void	GrabbingFinished(CxImage** imgResults, uint8 nFramesGrabbed,void* pSender);

	CFile	m_hpartfile;	//permanent opened handle to avoid write conflicts
	volatile bool m_bPreviewing;
	CMutex 	m_FileCompleteMutex; // Lord KiRon - Mutex for file completion
	CTypedPtrList<CPtrList, CUpDownClient*> A4AFsrclist; //<<-- enkeyDEV(Ottavio84) -A4AF-
    virtual uint32 GetPartAvailabilityRelativeToKnownSources(CUpDownClient* client, uint16 partNumber);
protected:
	bool	GetNextEmptyBlockInPart(uint16 partnumber,Requested_Block_Struct* result);
	bool	IsAlreadyRequested(uint32 start, uint32 end);
	void	CompleteFile(bool hashingdone);
	void	CreatePartFile();
	void	Init();

private:
	uint32	m_iLastPausePurge;
	uint16	count;
	uint16	m_anStates[STATES_COUNT];
	uint32  completedsize;
	uint64	m_iLostDueToCorruption;
	uint64	m_iGainDueToCompression;
	uint32  m_iTotalPacketsSavedDueToICH; 
	uint32	datarate;
	CString	m_fullname;
	CString	m_partmetfilename;
	uint32	transfered;
	bool	paused;
	bool	stopped;
	bool	insufficient; // SLUGFILLER: checkDiskspace
	bool	m_bCompletionError;
	uint8	m_iDownPriority;
	bool	m_bAutoDownPriority;
	uint8	status;
	bool	newdate;	// indicates if there was a writeaccess to the .part file
	uint32	lastpurgetime;
	uint32	m_LastNoNeededCheck;
	CTypedPtrList<CPtrList, Gap_Struct*> gaplist;
	CTypedPtrList<CPtrList, Requested_Block_Struct*> requestedblocks_list;
	CArray<uint16,uint16> m_SrcpartFrequency;
	float	percentcompleted;
	CList<uint16,uint16>	corrupted_list;
	uint16	availablePartsCount;
	uint32	m_ClientSrcAnswered;
	bool	m_bPercentUpdated;
	static	CBarShader s_LoadBar; 
	static	CBarShader s_ChunkBar; 
	bool	hasRating;
	bool	hasBadRating;
	bool	hasComment;
	bool	updatemystatus;
	BOOL 	PerformFileComplete(); // Lord KiRon
	static UINT CompleteThreadProc(LPVOID pvParams); // Lord KiRon - Used as separate thread to complete file
	DWORD	m_lastRefreshedDLDisplay;
	DWORD   m_lastdatetimecheck;
	CTime	m_lastdatecheckvalue;
	CTypedPtrList<CPtrList, CUpDownClient*> m_downloadingSourceList;
	void	CharFillRange(CString* buffer,uint32 start, uint32 end, char color);

	// Barry - Buffered data to be written
	CTypedPtrList<CPtrList, PartFileBufferedData*> m_BufferedData_list;
	uint32 m_nTotalBufferData;
	uint32 m_nLastBufferFlushTime;
	uint8	m_category;
	bool	m_is_A4AF_auto;
	DWORD	m_dwFileAttributes;
    uint32 m_random_update_wait;
    uint32 m_NumberOfClientsWithPartStatus;
public:
	uint32	lastsearchtime;
	bool	m_bLocalSrcReqQueued;
	CTypedPtrList<CPtrList, CUpDownClient*> srclists[SOURCESSLOTS];
	bool	srcarevisible; // used for downloadlistctrl
	bool	hashsetneeded;
	uint32  GetCompletedSize()   {return completedsize;}
};
