//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"
#include "StoredSources.h" //added mr fry

#define	PS_READY			0
#define	PS_EMPTY			1
#define PS_WAITINGFORHASH	2
#define PS_HASHING			3
#define PS_ERROR			4
#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	5000   // Max milliseconds before forcing a flush

class CSearchFile;
class CUpDownClient;

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:
	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(char* directory,char* 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(sint16 reducedownload);
	bool	LoadPartFile(char* in_directory, char* filename); //filename = *.part.met
	bool	SavePartFile();
	void	PartFileHashFinished(CKnownFile* result);
	bool	HashSinglePart(uint16 partnumber); // true = ok , false = corrupted	

	void	AddGap(uint32 start, uint32 end);
	void	FillGap(uint32 start, uint32 end);
	void	DrawStatusBar(CDC* dc, RECT* rect, 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	AddSources(CMemFile* sources,uint32 serverip, uint16 serverport);

	//////////////////////////////////////////////////
	//for saving sources: (by Mr.Fry)

		//save a CStoredSources-object to disk (to [eMule Temp-Folder]\[this PartMetFile-Name].src)
		//this function should only be called by the other saving-functions
	bool	SaveSourcesToFile(CStoredSources* toSave, bool debug=false);
		//load all sources OF THIS part-file FROM DISK (from [eMule Temp-Folder]\[this PartMetFile-Name].src)
		//this function should only be called by the other loading-functions
		//returns NULL, if no file was found or could not be loaded
	CStoredSources*	LoadSourcesFromFile(bool debug=false);
		//load all sources OF THIS part-file from the CStoredSources-object
		//of this part-file
		//and add them as CUpDownClients to theApp.downloadqueue
		//
		//if (param) limit is not equal (default is -1) -1, then the count of sources
		//that are loaded at once is equally (param) limit
		//if (param) reset is true, the loaded-completely status is reset to false (-> load ALL sources again)
	bool	AddFromStoredSources(	  CStoredSources* storedSources
									, bool sendUDPRequest=false
									, int  limit=-1
									, bool reset=false
									, bool debug=false);
		//load all sources OF THIS part-file FROM DISK
		//and add them as CUpDownClients to theApp.downloadqueue
		//
		//if (param) limit is not equal (default is -1) -1, then the count of sources
		//that are loaded at once is equally (param) limit
		//if (param) reset is true, the loaded-completely status is reset to false (-> load ALL sources again)
	bool	LoadAndAddSources(	  bool keepSourcesOpen	= false
								, bool sendUDPRequest	= false
								, int  limit= -1
								, bool reset= false
								, bool debug= false
								, bool addImmediately	= true);
	//	//add all sources from (param) storedSources to the source-list of this part-file
	//bool	AddFromStoredSources(CStoredSources* storedSources, bool sendUDPRequest=false,int limit=-1,bool reset=false, bool debug=false);
		
		//save (param) toSave to the CStoredSources-object
		//m_stscrStoringSources
	bool	SaveToStoredSources(CUpDownClient* toSave);
	bool	SaveToStoredSources();
		//save all sources from Download-Queue and this' CStoredSources-object to disk
	bool	SaveSources(bool loadSourcesFirst=true);

		//get/set loading-(stored-)sources time-interval
	uint32	GetLoadSourcesTimeInterval()					{return this->m_iLoadingSourcesTimeInterval;};
	void	SetLoadSourcesTimeInterval(uint32 newInterval)	{this->m_iLoadingSourcesTimeInterval = newInterval;};
		//get/set loading-(stored-)sources partial (-> 'slow-loading') time-interval
	uint32	GetLoadSourcesSlowTimeInterval()					{return this->m_iLoadingSourcesPartialTimeInterval;};
	void	SetLoadSourcesSlowTimeInterval(uint32 newInterval)	{this->m_iLoadingSourcesPartialTimeInterval = newInterval;};
		//get/set time-interval for saving sources
	uint32	GetSaveSourcesTimeInterval()					{return this->m_iSavingSourcesTimeInterval;};
	void	SetSaveSourcesTimeInterval(uint32 newInterval)	{this->m_iSavingSourcesTimeInterval = newInterval;};
		//get/set size of a block that is loaded at once in 'slow-loading' mode
	uint16	GetLoadSourcesAtOnceLimit()					{return this->m_iLoadSourcesAtOnceLimit;};
	void	SetLoadSourcesAtOnceLimit(uint16 newLimit)	{this->m_iLoadSourcesAtOnceLimit = newLimit;};
		//get/set loaded-sources-completely-inidcator
	bool	GetLoadedSourcesCompletely()				{return this->m_bLoadedSourcesCompletely;};
	void	SetLoadedSourcesCompletely(bool setTo)		{this->m_bLoadedSourcesCompletely = setTo;};

	CStoredSources* GetStoredSources()					{return this->m_stscrStoringSources;};
	//////////////////////////////////////////////////

	uint8	GetStatus(bool ignorepause = false);
	void	NewSrcPartsInfo();
	void	SetPriority(uint8 np);
	char*	GetPartMetFileName()							{return partmetfilename;}
	uint32	GetTransfered()									{return transfered;}
	uint8	GetPriority()									{return priority;}
	char*	GetFullName()									{return fullname;}
	uint16	GetSourceCount()								{return srclist.GetCount();}
	uint16	GetTransferingSrcCount()						{return transferingsrc;}
	uint32	GetDatarate()									{return datarate;}
	float	GetPercentCompleted()							{return percentcompleted;}
	uint16  GetNotCurrentSourcesCount();
	int		GetValidSourcesCount();
	bool	IsMovie();
	bool	IsArchive(); // Barry - Also want to preview archives
	CString CPartFile::getPartfileStatus(); //<<--9/21/02
	sint32	CPartFile::getTimeRemaining(); //<<--9/21/02
	CTime	lastseencomplete;
	int		getPartfileStatusRang();

	// 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();
	void	PauseFile();
	void	ResumeFile();

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

	void	PreviewFile();
	bool	PreviewAvailable();
	uint8   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;}

	int		GetCommonFilePenalty();

	CFile	m_hpartfile;	//permanent opened handle to avoid write conflicts
	volatile bool m_bPreviewing;
	//UAP Hunter
	void    UpdateDownloadAutoPriority(void) ;
	bool	IsAutoPrioritized() { return m_bAutoPriority ; }
	void	SetAutoPriority(bool newAutoPriority) { this->m_bAutoPriority = newAutoPriority ; }
	//end UAP

	// Added by Tarod -useful functions
	void	RemoveNoNeededSources(uint32 number_sources_to_remove = 0xffffffff);
	bool	IsA4AFAuto() { return m_is_A4AF_auto; }
	void	SetA4AFAuto(bool in_A4AF_auto);

protected:
	bool	GetNextEmptyBlockInPart(uint16 partnumber,Requested_Block_Struct* result);
	bool	IsAlreadyRequested(uint32 start, uint32 end);
	void	CompleteFile(bool hashingdone);
	void	CreatePartFile();
	void	Init();
private:
	uint16	count;
	uint16	transferingsrc;
	uint32  completedsize;
	uint64	m_iLostDueToCorruption;
	uint64	m_iGainDueToCompression;
	uint32  m_iTotalPacketsSavedDueToICH; 
	uint32	datarate;
	char*	fullname;
	char*	partmetfilename;
	uint32	transfered;
	bool	paused;
	uint8	priority;
	uint8	status;
	bool	newdate;	// indicates if there was a writeaccess to the .part file
	uint32	lastsearchtime;
	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;
	uint8	availablePartsCount;
	uint32	m_ClientSrcAnswered;
	bool	m_bPercentUpdated;
	static	CBarShader s_LoadBar; 
	static	CBarShader s_ChunkBar; 
    bool	m_bAutoPriority ;	//UAP Hunter
	bool	m_is_A4AF_auto;		// Added by Tarod

	/////////////////////////////////////
	//for saving sources: (by Mr.Fry)

	CStoredSources*	m_stscrStoringSources;
		//were the sources of this part-file loaded completely?
	bool	m_bLoadedSourcesCompletely;
		//index of the current source-entry (in CStoredSources)
	uint16	m_iSourceIndex;
		//indes of the User-ID of the current source-entry
		//
	int		m_iSourceIDIndex;
		//indicates, if eMule was connected to a server the last time
		//it processed this part-file (in CPartFile::Process(...))
	bool	m_bWasConnectedToServerLastTime;
		//the last time, sources of this part-file were saved to disk
		//(is set in  this->SaveSources())
	uint32	m_iLastTimeSourcesSaved;
		//the last time, sources of this part-file were loaded from disk AND
		//added to theApp.downloadqueue
		//(is set in  this->LoadAndAddSources())
	uint32	m_iLastTimeSourcesLoaded;
		//for 'slow-loading' of sources
	uint32	m_iLastTimeSourcesLoadedPartial;
		//time-interval for start loading sources
	uint32	m_iLoadingSourcesTimeInterval;
		//time-interval for loading seperate blocks (size of a block is defined by the
		//variable m_iLoadSourcesAtOnceLimit) in 'slow-loading' mode
	uint32	m_iLoadingSourcesPartialTimeInterval;
		//time-interval for saving sources
	uint32	m_iSavingSourcesTimeInterval;
		//size of a block that is loaded at once in 'slow-loading' mode
	uint16	m_iLoadSourcesAtOnceLimit;
		//tells the part-file, if it should load the saved sources from disk
		//(needs to load them one time in any case, because this information
		// is saved in the CStoredSources-objects)
	//TODO: implement this feature (if false, deactivate loading/saving sources for this part-file)
	bool	m_bLoadSavedSources;
	//////////////////////////////////////

	// Barry - Buffered data to be written
	CTypedPtrList<CPtrList, PartFileBufferedData*> m_BufferedData_list;
	uint32 m_nTotalBufferData;
	uint32 m_nLastBufferFlushTime;

public:
	CTypedPtrList<CPtrList, CUpDownClient*> srclist;
	bool	srcarevisible; // used for downloadlistctrl
	bool	hashsetneeded;							
	uint32  GetCompletedSize()   {return completedsize;}
};
