// 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 PARTFILE_H
#define PARTFILE_H

#include "BarShader.h"                      // CBarShader - audited 5 Nov 2004
#include "CFile.h"                          // CFile - audited 5 Nov 2004
#include "KnownFile.h"                      // CKnownFile - audited 5 Nov 2004
#include "mfc.h"                            // CList CTypedPtrList - audited 4 Nov 2004
#include "NewFunctions.h"                   // MAP - audited 5 Nov 2004
#include "otherfunctions.h"                 // GetTickCount - audited 5 Nov 2004
#include "wintypes.h"                       // bool BYTE - audited 4 Nov 2004

#include <stdint.h>                         // uint32_t
#include <wx/dc.h>
#include <wx/dcmemory.h>
#include <wx/treectrl.h>

class CMemFile;
class CSearchFile;
class CUpDownClient;
class Gap_Struct;
class Requested_Block_Struct;

#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 PR_NORMAL           1 // Don't change this - needed for edonkey clients and server!
#define PR_HIGH             2 //*
#define PR_VERYHIGH         3
#define PR_AUTO             5
#define SRV_PR_LOW          2
#define SRV_PR_NORMAL       0
#define SRV_PR_HIGH         1

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

struct PartFileBufferedData
{
    BYTE *data;                     // Barry - This is the data to be written
    uint32_t start;                 // Barry - This is the start offset of the data
    uint32_t 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(wxString 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_t    Process(uint32_t reducedownload);
    bool    LoadPartFile(char* in_directory, char* filename); //filename = *.part.met
    bool    SavePartFile(bool Initial=false);
    void    PartFileHashFinished(CKnownFile* result);

    void    DrawStatusBar(wxMemoryDC* dc, wxRect rect, bool bFlat);
    void    DrawShareStatusBar(wxMemoryDC* dc, wxRect rect, bool onlygreyrect, bool bFlat);
    bool    IsComplete(uint32_t start, uint32_t end);
        
    bool    GetNextRequestedBlock(CUpDownClient* sender,Requested_Block_Struct** newblocks,uint16_t* count);
    void    WritePartStatus(CMemFile* file);
    void    AddSources(CMemFile* sources,uint32_t serverip, uint16_t serverport);
    void    NewSrcPartsInfo();
    char*   GetPartMetFileName()                            {return partmetfilename;}
    uint32_t    GetTransfered()                                 {return transfered;}
    char*   GetFullName()                                   {return fullname;}
    uint16_t    GetSourceCount();
    uint16_t    GetTransferingSrcCount()                        {return transferingsrc;}
    uint32_t    GetDatarate()                                   {return datarate;}
    float   GetPercentCompleted()                           {return percentcompleted;}
    uint16_t  GetNotCurrentSourcesCount();
    int     GetValidSourcesCount();
    bool    IsMovie();
    bool    IsSound();
    bool    IsArchive(); 
    bool    IsCDImage(); 
    bool    IsImage();
    bool    IsText();
    
    
    wxString CPartFile::getPartfileStatus(); //<<--9/21/02
    int32_t CPartFile::getTimeRemaining(); //<<--9/21/02
    time_t  lastseencomplete;
    int     getPartfileStatusRang();
        wxString GetDownloadFileInfo();

    // Barry - Added as replacement for BlockReceived to buffer data before writing to disk
    uint32_t    WriteToBuffer(uint32_t transize, BYTE *data, uint32_t start, uint32_t end, Requested_Block_Struct *block);
    void    FlushBuffer(void);

    // 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_t start,uint32_t end);
    void    DeleteFile();
    void    StopFile();
    void    PauseFile();
    void    ResumeFile();

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

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

    uint32_t    GetLastAnsweredTime()           { return m_ClientSrcAnswered; }
    void    SetLastAnsweredTime()           { m_ClientSrcAnswered = ::GetTickCount(); }
    void    SetLastAnsweredTimeTimeout()        { m_ClientSrcAnswered = 2 * CONNECTION_LATENCY +
                                                                    ::GetTickCount() - SOURCECLIENTREASK; }
    uint64_t    GetLostDueToCorruption()        {return m_iLostDueToCorruption;}
    uint64_t    GetGainDueToCompression()       {return m_iGainDueToCompression;}
    uint32_t    TotalPacketsSavedDueToICH()     {return m_iTotalPacketsSavedDueToICH;}
    bool    IsStopped()                 {return stopped;}
    bool    HasComment()                {return hasComment;}
    bool    HasRating()             {return hasRating;}
    bool    HasBadRating();
    void    SetHasComment(bool in)          {hasComment=in;}
    void    SetHasRating(bool in)           {hasRating=in;}
    void    UpdateFileRatingCommentAvail();

    wxString GetProgressString(uint16_t size);

    int     GetCommonFilePenalty();
    time_t  GetLastChangeDatetime(bool forcecheck=false);
    uint8_t GetCategory();
    void    SetCategory(uint8_t cat)            {m_category=cat;SavePartFile();}

    CFile   m_hpartfile;    //permanent opened handle to avoid write conflicts
    volatile bool m_bPreviewing;
    void    SetDownPriority(uint8_t newDownPriority);
    bool    IsAutoDownPriority()    { return m_bAutoDownPriority; }
    void    SetAutoDownPriority(bool flag) { m_bAutoDownPriority = flag; }
    uint8_t GetDownPriority()   { return m_iDownPriority; }
        // Acess to Flag for SourceSharing
        bool    GetDisableXS()          { return m_DisableXS; }
        void    SetDisableXS(bool in)   { m_DisableXS = in; }
protected:
    void    Init();
    wxMutex     m_FileCompleteMutex;  // Lord KiRon - Mutex for file completion
private:
    int my_id;

    int valid_sources;
    int sources_iterations;

    bool    IsCorruptedPart(uint16_t partnumber);
    bool    HashSinglePart(uint16_t partnumber); // true = ok , false = corrupted   
    void    RemoveAllSources(bool bTryToSwap);
    bool    PerformFileComplete(); // Lord KiRon
    static UINT CompleteThreadProc(CPartFile* pFile); // Lord KiRon - Used as separate thread to complete file
    void    CompleteFile(bool hashingdone);
    void    UpdateCompletedInfos();
    void    AddGap(uint32_t start, uint32_t end);
    void    FillGap(uint32_t start, uint32_t end);
    bool    GetNextEmptyBlockInPart(uint16_t partnumber,Requested_Block_Struct* result);
    bool    IsAlreadyRequested(uint32_t start, uint32_t end);
    bool    IsPureGap(uint32_t start, uint32_t end);
    void    CreatePartFile();

    uint16_t    count;
    uint16_t    transferingsrc;
    uint32_t  completedsize;
    uint64_t    m_iLostDueToCorruption;
    uint64_t    m_iGainDueToCompression;
    uint32_t  m_iTotalPacketsSavedDueToICH;
    uint32_t    datarate;
    char*   fullname;
    char*   partmetfilename;
    uint32_t    transfered;
    bool    paused;
    bool    stopped;
        bool    m_DisableXS;                  // Flag for SourceSharing
    uint8_t m_iDownPriority;
    bool    m_bAutoDownPriority;
    uint8_t status;
    bool    newdate;                 // indicates if there was a writeaccess to the .part file
    uint32_t    lastsearchtime;
    uint32_t    lastpurgetime;
    uint32_t    m_LastNoNeededCheck;
    CTypedPtrList<CPtrList, Gap_Struct*> gaplist;
    CTypedPtrList<CPtrList, Requested_Block_Struct*> requestedblocks_list;
    CArray<uint16_t,uint16_t> m_SrcpartFrequency;
    float   percentcompleted;
    CList<uint16_t,uint16_t>    corrupted_list;
    uint8_t availablePartsCount;
    uint32_t    m_ClientSrcAnswered;
    uint32_t    m_nSavedReduceDownload;
    bool    m_bPercentUpdated;
    static  CBarShader s_LoadBar; 
    static  CBarShader s_ChunkBar; 
    bool    hasRating;
    bool    hasComment;

    unsigned long   m_lastRefreshedDLDisplay;
    unsigned long   m_lastdatetimecheck;
    time_t  m_lastdatecheckvalue;

    // Barry - Buffered data to be written
    CTypedPtrList<CPtrList, PartFileBufferedData*> m_BufferedData_list;
    uint32_t m_nTotalBufferData;
    uint32_t m_nLastBufferFlushTime;
    uint8_t m_category;
    
    unsigned long   m_LastSourceDropTime;

public:
    CTypedPtrList<CPtrList, CUpDownClient*> srclist;
    bool    srcarevisible;      // used for downloadlistctrl
    bool    m_bShowOnlyDownloading; // used for downloadlistctrl
    bool    hashsetneeded;
    uint16_t    GetMaxSourcesPerFile() { return m_MaxSourcesPerFile; }
    void    SetMaxSourcesPerFile(uint16_t in) { m_MaxSourcesPerFile=in; }
    uint32_t  GetCompletedSize()   {return completedsize;}
    uint8_t GetStatus(bool ignorepause = false);
    
/* Razor 1a - Modif by MikaelB */

    /* RemoveNoNeededSources function */
    void  RemoveNoNeededSources();

    /* RemoveFullQueueSources function */
    void  RemoveFullQueueSources();

    /* RemoveHighQueueRatingSources function */
    void  RemoveHighQueueRatingSources();

    /* CleanUpSources function */
    void  CleanUpSources();

    /* AddDownloadingSource function */
    void AddDownloadingSource(CUpDownClient* client);
    
    /* RemoveDownloadingSource function */
    void RemoveDownloadingSource(CUpDownClient* client);

    /* A4AF sources list */
    CTypedPtrList<CPtrList, CUpDownClient*> A4AFSourcesList;

    /* SetA4AFAuto function */
    void SetA4AFAuto(bool A4AFauto)
    {
      this->m_IsA4AFAuto = A4AFauto;
    }

    /* IsA4AFAuto function */
    bool IsA4AFAuto()
    {
      return this->m_IsA4AFAuto;
    }

private:
//    MAP* listof_downloadingSources;


    /* A4AF Auto attribute */
    bool m_IsA4AFAuto;
    uint16_t  m_MaxSourcesPerFile;

/* End modif */
 
};


#endif
