////////////////////////////////////////////////////////////////////////////////
//                                                                             /
// 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.                                            /
//                                                                             /
////////////////////////////////////////////////////////////////////////////////
#ifndef BK_ENGINE_H
#define BK_ENGINE_H

#include "options.h"
#include "PSharedLib.h"

#define LOG_SUB_FOLDER                                              TM("\\Logs\\")

#define CRASH_PROCESS_END_WAIT_FALG                                 TM("/wait")
#define CONFIG_PATH_PREFIX                                          TM("/cfg:")


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CRcList
template <typename tData_Type>
class CRcList
    : public CBList<tData_Type>
{
protected:
    ////////////////////////////////////////////////////////////////////////////
    //CAList::Data_Release
    // override this function in derived class to implement specific data 
    // destructor(structures as example)
    virtual tBOOL Data_Release(tData_Type i_pData)
    {
        if (NULL == i_pData)
        {
            return FALSE;
        }

        i_pData->Release();
        return TRUE;
    }//CAList::Data_Release
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CDllList
class CDllList
    : public CBList<CPSharedLib*>
{
protected:
    ////////////////////////////////////////////////////////////////////////////
    //CAList::Data_Release
    // override this function in derived class to implement specific data 
    // destructor(structures as example)
    virtual tBOOL Data_Release(CPSharedLib *i_pData)
    {
        if (NULL == i_pData)
        {
            return FALSE;
        }

        i_pData->Release();
        return TRUE;
    }//CAList::Data_Release
};


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CEnumerator_Storages
class CEnumerator_Storages
    : public Bk::IPluginsEnumerator
{
    tINT32 volatile    m_lReference;
    CRcList<CStorage*> m_cStorages;
public:
    CEnumerator_Storages(CRcList<CStorage*> *i_pStorages)
        : m_lReference(1)
    {
        pAList_Cell l_pEl = NULL;
        while ((l_pEl = i_pStorages->Get_Next(l_pEl)))
        {
            CStorage *l_pStorage = i_pStorages->Get_Data(l_pEl);
            if (l_pStorage)
            {
                l_pStorage->Add_Ref();
                m_cStorages.Add_After(NULL, l_pStorage);
            }
        }

        m_cStorages[0]; //build indexes
    }

    virtual ~CEnumerator_Storages()
    {
        m_cStorages.Clear(TRUE);
    }

    tINT32 __stdcall Add_Ref()
    {
        return ATOMIC_INC(&m_lReference);
    }

    tINT32 __stdcall Release()
    {
        tINT32 l_lResult = ATOMIC_DEC(&m_lReference);
        if ( 0 >= l_lResult )
        {
            delete this;
        }

        return l_lResult;
    }

    size_t __stdcall Get_Count()
    {
        return m_cStorages.Count();
    }

    Bk::IPlugin* __stdcall Get_Plugin(size_t i_szIndex)
    {
        return dynamic_cast<Bk::IPlugin*>(m_cStorages[(tUINT32)i_szIndex]);
    }
};


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CRawStream
class CRawStream
{
public:
    Bk::IStreamEx      *m_pExtra;
    Bk::IStorageReader *m_pReader;
public:
    CRawStream(Bk::IStreamEx *i_pExtra, Bk::IStorageReader *i_pReader)
        : m_pExtra(i_pExtra)
        , m_pReader(i_pReader)
    {
        if (m_pExtra)
        {
            m_pExtra->Add_Ref();
        }
        if (m_pReader)
        {
            m_pReader->Add_Ref();
        }
    }

    virtual ~CRawStream()
    {
        if (m_pExtra)
        {
            m_pExtra->Release();
            m_pExtra = NULL;
        }
        if (m_pReader)
        {
            m_pReader->Release();
            m_pReader = NULL;
        }
    }
};


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CBaical
class CBaical
    : public Bk::ICore
    , public COptions
    , public ISubscriberOwner
{                             
public:
    enum eError
    {
        eErrorNone,
        eErrorCfg,
        eErrorInternal
    };

    enum eMode
    {
        eModeGUI,
        eModeCLI
    };

protected:
    tINT32 volatile        m_lReference;
    CRcList<CStreams*>     m_cSubscribers;

    tBOOL                  m_bInitialized;
    eError                 m_eError;
    CRcList<CProvider*>   *m_pProviders;
    CRcList<CStorage*>    *m_pStorages;
    CRcList<CViewer*>     *m_pViewers;
    CRcList<CDispatcher*> *m_pDispatchers;
    CRcList<CProcessor*>  *m_pProcessors;
    CDllList               m_cPluginsDll;
                          
    CLock                  m_cLock_Subscribers;
                          
    IBDoc                 *m_iBDoc; 
    CWString               m_cExe;
    CWString               m_cDir;
                          
    tBOOL                  m_bP7_Baical;
    IP7_Client            *m_iP7;
    IP7_Trace             *m_iP7_Trace;
    IP7_Trace::hModule     m_hP7_TraceModule;
    IP7_Telemetry         *m_iP7_Tel;
                          
    CProperty             *m_pProperties;

    eMode                  m_eMode;
public:                         
    CBaical(const tXCHAR *i_pConfigPath, const tXCHAR *i_pCrashesPath, CBaical::eMode i_eMode);
    virtual ~CBaical();

    tBOOL        Get_Initialized(CBaical::eError &o_rError);

    tUINT32      Get_Plugins_Count(Bk::ePluginType i_eType);
    tBOOL        Get_Plugin_Info(Bk::ePluginType i_eType, tUINT32 i_dwIDX, Bk::stPluginInfo *o_pInfo);

    Bk::IBNode  *Get_Node(GUID *i_pGUID, const tXCHAR *i_pName);
    Bk::IViewer *Create_Viewer(WND_HANDLE              i_hParent, 
                               GUID                   *i_pStream_GUID, 
                               Bk::IStorageReader     *i_iReader, 
                               Bk::IStreamEx          *i_iExtra,
                               Bk::IViewersEnumerator *i_pEnum
                              );
    Bk::eResult  Open_Storage(WND_HANDLE i_hParent, Bk::IStorageReader **o_pReader, const tXCHAR *i_pFile);
    Bk::eResult  Import(const tXCHAR *i_pFile);

    void         BreakdownNotify(eCrashCode i_eCode, const void *i_pContext);

    CProperty*   Get_Properties();

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //Bk::ICore
    Bk::eResult __stdcall Create_Storage(Bk::stStreamInfo *i_pInfo, Bk::IStorage *&o_rStorage);
    Bk::eResult __stdcall Register_New_Stream(const void         *i_pStreamId,
                                              Bk::IStorageReader *i_iReader,
                                              Bk::IStreamEx      *i_iEx);
    tINT32      __stdcall Add_Ref();
    tINT32      __stdcall Release();
    Bk::eResult __stdcall Query_Interface(Bk::eInterface i_eId, void *&o_rUnknown);
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //ISubscriberOwner
    void Unregister_Subscriber(Bk::IStreams *i_pStreams);
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

private:
    tBOOL    Load_Properties(Bk::IBNode *i_pNode, CProperty *i_pParent);
    tBOOL    Save_Properties(CProperty *i_pProp);

    void     P7_Release();

    tBOOL    Enum_Plugins();
    void     Sort_Dispatchers();
    tBOOL    Add_Plugin(tXCHAR *i_pPath);
};//CBaical

#endif //BK_ENGINE_H
