////////////////////////////////////////////////////////////////////////////////
//                                                                             /
// 2012-2019 (c) Baical                                                        /
//                                                                             /
// This library is free software; you can redistribute it and/or               /
// modify it under the terms of the GNU Lesser General Public                  /
// License as published by the Free Software Foundation; either                /
// version 3.0 of the License, or (at your option) any later version.          /
//                                                                             /
// This library 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           /
// Lesser General Public License for more details.                             /
//                                                                             /
// You should have received a copy of the GNU Lesser General Public            /
// License along with this library.                                            /
//                                                                             /
////////////////////////////////////////////////////////////////////////////////
#pragma once


//forward declaration
class CP7Stream_Ex;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CTail
{
public:
    CBList<CTail*> *pOwner;
    tUINT8         *pTail;
    size_t          szTail;
    size_t          szTailRest;
    size_t          szTailOffs;
    CTail          *pNext; 

    CTail(CBList<CTail*> *i_pOwner, size_t i_szTail = 1024);
    virtual ~CTail();
    inline void Realloc(size_t i_szNewSize);
    inline void Release();
};


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CStreamP7
{
public:
    Bk::IStorage    *m_iStorare;
    CP7Stream_Ex    *m_pStreamEx;
    Bk::stDataChunk *m_pFirst;
    Bk::stDataChunk *m_pLast;
    tBOOL            m_bError;
    CTail           *m_pTail;

    CStreamP7();
    virtual ~CStreamP7();
    void Uninit();
    inline void PushTail(CTail *i_pTail);
    inline void ReleaseTails();
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CDataBlock
{
    tUINT8          *m_pData;
    size_t           m_szCount;
    Bk::stDataChunk *m_pFirst;
    Bk::stDataChunk *m_pLast;

public:
    CDataBlock(size_t i_szCount = 1024);
    virtual ~CDataBlock();
    Bk::stDataChunk *Get_First() { return m_pFirst;}
    Bk::stDataChunk *Get_Last() { return m_pLast;}
};


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CConnectionP7
{
public:
    enum eThreadMain
    {
        eThreadExit = MEVENT_SIGNAL_0,
        eThreadCountSignals
    };

protected:
    IP7_Server         *m_pServer;
    IP7S_Address       *m_pAddress;
    IP7S_Connnection   *m_pConnection;
    CProperty          *m_pPropRoot;
    CDNS_Resolver      *m_pDns_Resolver;

    IP7_Trace          *m_iP7_Trace;
    IP7_Trace::hModule  m_hP7_TraceModule;
    IP7_Telemetry      *m_iP7_Tel;

    CMEvent             m_cExit_Event; 
    CThShell::tTHREAD   m_hThread;
    tBOOL               m_bIsThread;

    tBOOL               m_bActive;
    Bk::ICore          *m_pCore;

    CLock               m_cLock;

    tBOOL               m_bBigEndian;

    CStreamP7          *m_pChannels[USER_PACKET_CHANNEL_ID_MAX_SIZE];  

    CBList<CDataBlock*> m_cDataBlocks;
    Bk::stDataChunk    *m_pFirstChunk;

    CBList<CStreamP7*>  m_cTmpStreams;

public:
    CConnectionP7(Bk::ICore        *i_pCore,
                  IP7_Server       *i_pServer,
                  IP7S_Address     *i_pAddress,
                  IP7S_Connnection *i_pConnection,
                  CProperty        *i_pPropRoot,
                  CDNS_Resolver    *i_pDns_Resolver,
                  IP7_Trace        *i_iP7_Trace,
                  IP7_Telemetry    *i_iP7_Tel
                 );
    virtual ~CConnectionP7();

    tBOOL       Get_Active();

    tBOOL       Is_BigEndian();
    Bk::eResult Get_Status(Bk::stStreamStatus *o_pStatus);
    Bk::eResult Put_Packet(tUINT32 i_uChannel, const tUINT8 *i_pBuffer, tUINT32 i_dwSize);

private:
    inline Bk::stDataChunk *Pull_Free_Chunk();
    inline void             Push_Free_Chunks(Bk::stDataChunk *i_pFirst);
    inline tBOOL            CreateStorage(CStreamP7 *i_pStream, size_t i_szIndex);

    inline void             Register_Streams();
    inline void             Register_Stream(CStreamP7 *i_pStream);
    inline void             Zero_Stream_Buffers(CStreamP7 *i_pStream);

    void  Routine();

    static THSHELL_RET_TYPE THSHELL_CALL_TYPE Static_Routine(void *i_pContext)
    {
        CConnectionP7 * l_pRoutine = (CConnectionP7 *)i_pContext;
        if (l_pRoutine)
        {
            l_pRoutine->Routine();
        }

        CThShell::Cleanup();
        return THSHELL_RET_OK;
    } 

};