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

#ifndef PACKETS_H
#define PACKETS_H

#include "opcodes.h"                        // OP_EDONKEYPROT - audited 5 Nov 2004
#include "wintypes.h"                       // UINT - audited 4 Nov 2004

#include <cstdio>                           // FILE
#include <exception>                        // std::exception
#include <stdint.h>                         // uint32_t

class CFile;
class CMemFile;
struct Packet_int;

//          CLIENT TO SERVER
//          PACKET CLASS
// TODO some parts could need some work to make it more efficient
class Packet
{
public:
    Packet(const uint8_t protocol = OP_EDONKEYPROT);
    Packet(const char* header); // only used for receiving packets
    Packet(const char* type, const char* pPacketPart, const uint32_t nSize, const bool bLast, const bool bFromPF = true);//only used for spl. packets!
    Packet(const char* type, const int8_t in_opcode, const uint32_t in_size, const uint8_t protocol = OP_EDONKEYPROT, const bool bFromPF = true);
    Packet(const char* pPacketPart, const uint32_t nSize, const bool bLast); // only used for splitted packets!

    Packet(const int8_t in_opcode, const uint32_t in_size, const uint8_t protocol, const unsigned char* buffer);
    Packet(const int8_t in_opcode, const uint32_t in_size, const uint8_t protocol = OP_EDONKEYPROT);
    Packet(CMemFile* datafile, const uint8_t protocol = OP_EDONKEYPROT);
    //Packet(int8_t in_opcode,CMemFile* datafile,uint8_t protocol = OP_EDONKEYPROT);

    ~Packet();
    char* GetHeader();
    char* GetUDPHeader();
    char* GetPacket();
    char* DetachPacket();
    uint32_t  GetRealPacketSize()     {return size+6;}
    bool IsSplitted() const;
    bool IsLastSplitted() const;
    void    PackPacket();
    bool    UnPackPacket(UINT uMaxDecompressedSize = 50000);
    char*   pBuffer;
    uint32_t  size;
    uint8_t   opcode;
    uint8_t   prot;
    // -khaos--+++> Returns either -1, 0 or 1.  -1 is unset, 0 is from complete file, 1 is from part file
    
    bool IsFromPF() const;
    // <-----khaos-

private:
    Packet_int* my;
};

struct Tag_Struct{
    int8_t    type;
    char*   tagname;
    char*   stringvalue;
    uint32_t  intvalue;
    int8_t    specialtag;

};

class CInvalidPacket : public std::exception
{
public:
    CInvalidPacket(const char* = "not specified");

    virtual const char* what() const throw();

private:
    char m_acWhat[256];
};

class CStrangePacket : public CInvalidPacket
{
public:
    CStrangePacket(const char* w = "not specified") : CInvalidPacket(w)
    { }
};

enum TTagType
{
    TAG_UNSPEC = -1,
    TAG_STRING = 2,
    TAG_INTEGER = 3
};

class CTag {
public:
    CTag(char* name,uint32_t intvalue);
    CTag(int8_t special, uint32_t intvalue);
    CTag(char* name,char* strvalue);
    CTag(int8_t special, char* strvalue);
    CTag(Tag_Struct* in_tag);
    CTag(CFile* in_data);
    CTag(CMemFile* in_data);
    CTag(FILE* in_data);
    ~CTag();
    CTag* CloneTag()    {return new CTag(tag);};
    bool WriteTagToFile(CFile* file) const; //used for CMemfiles
    bool WriteTagToFile(CMemFile* file) const;
    bool WriteTagToFile(FILE* file) const;
    Tag_Struct* tag;
    void DumpToStdout() const;
    TTagType GetType() const;
};

#endif
