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

class CP7Stream_Ex;

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

    CStreamP7();
    virtual ~CStreamP7();
    void Uninit();
};



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

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


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CP7Importer
class CP7Importer
    : public Bk::IProvider
{
public:
    enum eThreadMain
    {
        eThreadMainExit = MEVENT_SIGNAL_0,
        eThreadMainFile,
        eThreadMainCountSignal
    };

protected:
    //put volatile variables at the top, to obtain 32 bit alignment. 
    //Project has 8 bytes alignment by default
    tINT32 volatile       m_lReference;

    Bk::ICore            *m_pCore;

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

    CLock                 m_cLock;

    tBOOL                 m_bInitialized;

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

    sP7File_Header        m_sFile_Header;

    CBList<CWString*>     m_cFiles_List;

    CPFile                m_cFile;
    tUINT8               *m_pData;
    size_t                m_szData_Max;
    size_t                m_szData_Size;
    size_t                m_szData_Offs;
    tUINT64               m_qwFile_Offs;
    tUINT64               m_qwFile_Size;

    tBOOL                 m_bLittleEndian;

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

    CStreamP7            *m_pChannels[USER_PACKET_CHANNEL_ID_MAX_SIZE];  

    CBList<CStreamP7*>   m_cTmpStreams;
    
public:
    CP7Importer(Bk::IUnknown *i_pCore, Bk::IBNode *i_pNode, CProperty *i_pProp);
    virtual ~CP7Importer();

    tBOOL                 Get_Initialized() { return m_bInitialized; }

    Bk::eResult __stdcall Add_Source(const tXCHAR *i_pSource, void *&o_rToken);
    Bk::eResult __stdcall Del_Source(const void *i_pToken);
    Bk::eResult __stdcall Get_Progress(tUINT32 &o_rProgress);
    Bk::eResult __stdcall Exceptional_Shutdown();

    tINT32      __stdcall Add_Ref();
    tINT32      __stdcall Release();
    Bk::eResult __stdcall Query_Interface(Bk::eInterface i_eId, void *&o_rUnknown);

private:
    tBOOL                 Open_File(const tXCHAR *i_pFile);
    tBOOL                 Close_File();

    Bk::stDataChunk      *Pull_Free_Chunk();
    void                  Push_Free_Chunks(Bk::stDataChunk *i_pFirst);

    inline tBOOL          CreateStorage(CStreamP7 *i_pStream, size_t i_szIndex);

    inline void           RegisterStreams();
    inline void           RegisterAndRemoveStream(CStreamP7 *i_pStream);
    inline void           Zero_Stream_Buffers(CStreamP7 *i_pStream);


    void                  RoutineMain();

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

        CThShell::Cleanup();
        return THSHELL_RET_OK;
    } 

};