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

#include "Common.h"

#if defined(_WIN32) || defined(_WIN64)
    #pragma warning(disable : 4995)
    #pragma warning(disable : 4996)
    #pragma warning(disable : 4091)
    #include "Shellapi.h"
    #include "Shlobj.h"
#endif


#define THREAD_EXIT_EVENT                                     (MEVENT_SIGNAL_0)


#if defined(_DEBUG)
//    #define ONLINE_LOGGING
#endif


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CPropData
class CPropData
    : public CProperty::IData
{
public:
    Bk::IBNode *m_pXml;
    CPropData(Bk::IBNode *i_pXml)
        : m_pXml(i_pXml)
    {
        if (m_pXml)
        {
            m_pXml->Add_Ref();
        }
    }

    void Release()
    {
        delete this;
    }
protected:
    virtual ~CPropData()
    {
        if (m_pXml)
        {
            m_pXml->Release();
        }
    }
};//CPropData


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CBaical
CBaical::CBaical(const tXCHAR *i_pConfigPath, const tXCHAR *i_pCrashesPath, CBaical::eMode i_eMode)
    : m_lReference(1)
    , m_bInitialized(TRUE)
    , m_eError(eErrorNone)
    , m_pProviders(NULL)
    , m_pStorages(NULL)
    , m_pViewers(NULL)
    , m_pDispatchers(NULL)
    , m_pProcessors(NULL)
    , m_iBDoc(NULL)

    , m_bP7_Baical(FALSE)
    , m_iP7(NULL)
    , m_iP7_Trace(NULL)
    , m_hP7_TraceModule(NULL)
    , m_iP7_Tel(NULL)
    , m_pProperties(NULL)
    , m_eMode(i_eMode)
{
    CWString l_cLogsPath;

    CFSYS::GetUserDirectory(&l_cLogsPath);
    l_cLogsPath.Append(1, TM("/Baical/Logs/"));

    CProperty::Create(NULL, CProperty::eGroup, TM("Root"), m_pProperties);
    if (m_pProperties)
    {
        m_pProperties->Set_Data(new CPropData(NULL));
    }

#if defined(_WIN32) || defined(_WIN64)
    CFSYS::Get_Process_Path(&m_cExe);
    CFSYS::Get_Process_Directory(&m_cDir);
#endif
    
    ////////////////////////////////////////////////////////////////////////////
    //load or create xml file if it isn't exists
    if (m_bInitialized)
    {
        if (CFSYS::File_Exists(i_pConfigPath))
        {
            m_iBDoc = IBDoc_Load(i_pConfigPath);
        }

        if (!m_iBDoc)
        {
            CFSYS::Delete_File(i_pConfigPath);
            m_bInitialized = FALSE;
            m_eError = eErrorCfg;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //read xml parameters
    if (m_bInitialized)
    {
        Bk::IBNode  *l_pRoot = NULL;
        m_iBDoc->GetChildFirst(BNODE_ROOT, &l_pRoot);
        if (l_pRoot)
        {
            Bk::IBNode *l_pCore = NULL;  
            l_pRoot->GetChildFirst(BNODE_CORE, &l_pCore);
            if (l_pCore)
            {
                CProperty *l_pPropCore = NULL;
                if (CProperty::Create(m_pProperties, CProperty::eGroup, TM("Core"), l_pPropCore))
                {
                    l_pPropCore->Set_Desc(TM("Baical core properties"));

                    l_pPropCore->Set_Data(new CPropData(l_pCore));
                    Load_Properties(l_pCore, l_pPropCore);

                    l_pPropCore->Release();
                    l_pPropCore = NULL;
                }

                l_pCore->Release();
                l_pCore = NULL;
            }

            l_pRoot->Release();
            l_pRoot = NULL;
        }


        CProperty *l_pPropLog = NULL;
        tBOOL      l_bLogging = FALSE;

        m_pProperties->Get_SubItem(TM("Core/Logging/Enable"), l_pPropLog);
        if (l_pPropLog)
        {
            const tXCHAR *l_pName   = NULL;
            tINT64         l_llValue = 0ll;
            tINT32         l_iIndex = -1;

            l_pPropLog->Get_Current_Index(l_iIndex);
            if (l_pPropLog->Get_Item(l_iIndex, l_pName, l_llValue))
            {
                l_bLogging = (0 < l_llValue) ? TRUE : FALSE;
            }

            l_pPropLog->Release();
            l_pPropLog = NULL;
        }

#if defined(ONLINE_LOGGING)
        l_bLogging = TRUE;
#endif

        if (l_bLogging)
        {
            const tXCHAR  *l_pValue = NULL;
            eP7Trace_Level l_eVerb  = EP7TRACE_LEVEL_DEBUG;
            CWString       l_cP7Cmd;

            l_cP7Cmd.Set(CLIENT_COMMAND_LINE_BAICAL_ADDRESS      TM("127.0.0.1 ")
                         CLIENT_COMMAND_PACKET_BAICAL_SIZE       TM("1472 ")
                         CLIENT_COMMAND_POOL_SIZE                TM("8192 ")
                         CLIENT_COMMAND_LINE_FILE_ROLLING        TM("100mb ")
                         CLIENT_COMMAND_LINE_FILES_COUNT_MAX     TM("5 ")
                         CLIENT_COMMAND_LINE_BAICAL_EXIT_TIMEOUT TM("0 ")
                        );

            m_pProperties->Get_SubItem(TM("Core/Logging/Path"), l_pPropLog);
            l_pValue = NULL;
            if (l_pPropLog)
            {
                l_pPropLog->Get_Value(l_pValue);
                l_pPropLog->Release();
                l_pPropLog = NULL;
            }

            if (    (l_pValue)
                 && (CFSYS::Directory_Exists(l_pValue))
               )
            {
                l_cP7Cmd.Append(3, CLIENT_COMMAND_LINE_DIR TM("\""),  l_pValue, TM("\" "));
            }
            else
            {
                l_cP7Cmd.Append(3, CLIENT_COMMAND_LINE_DIR TM("\""),  l_cLogsPath.Get(), TM("\" "));
            }

            m_pProperties->Get_SubItem(TM("Core/Logging/Verbosity"), l_pPropLog);
            if (l_pPropLog)
            {
                const tXCHAR *l_pName   = NULL;
                tINT64        l_llValue = 0ll;
                tINT32        l_iIndex = -1;

                l_pPropLog->Get_Current_Index(l_iIndex);
                if (l_pPropLog->Get_Item(l_iIndex, l_pName, l_llValue))
                {
                    l_eVerb = (eP7Trace_Level)l_llValue;
                }

                l_pPropLog->Release();
                l_pPropLog = NULL;
            }


            m_pProperties->Get_SubItem(TM("Core/Logging/Sink"), l_pPropLog);
            l_pValue = NULL;
            if (l_pPropLog)
            {
                const tXCHAR *l_pName   = NULL;
                tINT64        l_llValue = 0ll;
                tINT32        l_iIndex  = -1;

                l_pPropLog->Get_Current_Index(l_iIndex);
                if (l_pPropLog->Get_Item(l_iIndex, l_pName, l_llValue))
                {
                #if defined(ONLINE_LOGGING)
                    l_pValue = TM("Baical");
                #else
                    l_pValue = l_pName;
                #endif
                }

                l_pPropLog->Release();
                l_pPropLog = NULL;
            }

            if (l_pValue)
            {
                l_cP7Cmd.Append(3, CLIENT_COMMAND_LINE_SINK,  l_pValue, TM(" "));

                if (0 == PStrICmp(CLIENT_SINK_BAICAL, l_pValue))
                {
                    m_bP7_Baical = TRUE;
                }
            }
            else
            {
                l_cP7Cmd.Append(1, CLIENT_COMMAND_LINE_SINK CLIENT_SINK_FILE_BIN TM(" "));
            }

            m_iP7 = P7_Create_Client(l_cP7Cmd.Get());
            if (m_iP7)
            {
                m_iP7->Share(BK_SHARED_P7);

                m_iP7_Trace = P7_Create_Trace(m_iP7, TM("Logs"));
                if (m_iP7_Trace)
                {
                    m_iP7_Trace->Share(BK_SHARED_TRACE);
                    m_iP7_Trace->Set_Verbosity(NULL, l_eVerb);
                    m_iP7_Trace->Register_Module(TM("Baical"), &m_hP7_TraceModule);
                    m_iP7_Trace->Register_Thread(TM("Main"), 0);
                }

                m_iP7_Tel = P7_Create_Telemetry(m_iP7, TM("Telemetry"));
                if (m_iP7_Tel)
                {
                    m_iP7_Tel->Share(BK_SHARED_TELEMETRY);
                }
            }
        }//if (l_lLogging)
    }//if (m_bInitialized)

    if (m_bInitialized)
    {
        m_pProviders = new CRcList<CProvider*>;
        if (NULL == m_pProviders)
        {
            m_bInitialized = FALSE;
            m_eError = eErrorInternal;
            LOG_ERROR(TM("Providers list wasn't created !"));
        }
    }

    if (m_bInitialized)
    {
        m_pStorages = new CRcList<CStorage*>;
        if (NULL == m_pStorages)
        {
            m_bInitialized = FALSE;
            m_eError = eErrorInternal;
            LOG_ERROR(TM("Storages list wasn't created !"));
        }
    }

    if (m_bInitialized)
    {
        m_pViewers = new CRcList<CViewer*>;
        if (NULL == m_pViewers)
        {
            m_bInitialized = FALSE;
            m_eError = eErrorInternal;
            LOG_ERROR(TM("Viewer list wasn't created !"));
        }
    }

    if (m_bInitialized)
    {
        m_pDispatchers = new CRcList<CDispatcher*>;
        if (NULL == m_pDispatchers)
        {
            m_bInitialized = FALSE;
            m_eError = eErrorInternal;
            LOG_ERROR(TM("Dispatchers list wasn't created !"));
        }
    }

    if (m_bInitialized)
    {
        m_pProcessors = new CRcList<CProcessor*>;
        if (NULL == m_pProcessors)
        {
            m_bInitialized = FALSE;
            m_eError = eErrorInternal;
            LOG_ERROR(TM("Processors list wasn't created !"));
        }
    }

    if (m_bInitialized)
    {
        COptions::Initialize(m_iBDoc, i_pCrashesPath, l_cLogsPath.Get());

        Enum_Plugins();

        //initialize storage plugins  
        pAList_Cell l_pEl = NULL;
        while ((l_pEl = m_pStorages->Get_Next(l_pEl)))
        {
            CPlugin *l_iStorage = m_pStorages->Get_Data(l_pEl);
            if (l_iStorage)
            {
                Bk::eResult l_ePlugin_Result = l_iStorage->Initialize();
                if (Bk::eOk != l_ePlugin_Result)
                {
                    LOG_ERROR(TM("Can't initialize storage, Error: %d"), l_ePlugin_Result);
                }
            }
        }

        //initialize dispatcher plugins
        l_pEl = NULL;
        while ((l_pEl = m_pDispatchers->Get_Next(l_pEl)))
        {
            CPlugin *l_iDispatcher = m_pDispatchers->Get_Data(l_pEl);
            if (l_iDispatcher)
            {
                Bk::eResult l_ePlugin_Result = l_iDispatcher->Initialize();
                if (Bk::eOk != l_ePlugin_Result)
                {
                    LOG_ERROR(TM("Can't initialize dispatcher, Error: %d"), l_ePlugin_Result);
                }
            }
        }

        //initialize processor plugins
        l_pEl = NULL;
        while ((l_pEl = m_pProcessors->Get_Next(l_pEl)))
        {
            CPlugin *l_iProcessor = m_pProcessors->Get_Data(l_pEl);
            if (l_iProcessor)
            {
                Bk::eResult l_ePlugin_Result = l_iProcessor->Initialize();
                if (Bk::eOk != l_ePlugin_Result)
                {
                    LOG_ERROR(TM("Can't initialize processor, Error: %d"), l_ePlugin_Result);
                }
            }
        }

        //initialize provider plugins
        l_pEl = NULL;
        while ((l_pEl = m_pProviders->Get_Next(l_pEl)))
        {
            CPlugin *l_iProvider = m_pProviders->Get_Data(l_pEl);
            if (l_iProvider)
            {
                Bk::eResult l_ePlugin_Result = l_iProvider->Initialize();
                if (Bk::eOk != l_ePlugin_Result)
                {
                    LOG_ERROR(TM("Can't initialize processor, Error: %d"), l_ePlugin_Result);
                }
            }
        }
    }
} //CBaical


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~CBaical
CBaical::~CBaical()
{
    m_cLock_Subscribers.Lock();
    m_cSubscribers.Clear(TRUE);
    m_cLock_Subscribers.Unlock();

    if (m_pDispatchers)
    {
        m_pDispatchers->Clear(TRUE);
        delete m_pDispatchers;
        m_pDispatchers = NULL;
    }

    if (m_pProcessors)
    {
        m_pProcessors->Clear(TRUE);
        delete m_pProcessors;
        m_pProcessors = NULL;
    }

    if (m_pProviders)
    {
        m_pProviders->Clear(TRUE);
        delete m_pProviders;
        m_pProviders = NULL;
    }

    if (m_pStorages)
    {
        m_pStorages->Clear(TRUE);
        delete m_pStorages;
        m_pStorages = NULL;
    }

    if (m_pViewers)
    {
        m_pViewers->Clear(TRUE);
        delete m_pViewers;
        m_pViewers = NULL;
    }

    if (m_pProperties)
    {
        Save_Properties(m_pProperties);
        m_pProperties->Release();
        m_pProperties = NULL;
    }

    COptions::Uninitialize();

    if (m_iBDoc)
    {
        m_iBDoc->Save();
        m_iBDoc->Release();
        m_iBDoc = NULL;
    }

    P7_Release();

    m_cPluginsDll.Clear(TRUE); //close Dll handles at the end of process 
}//~CBaical


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Initialized
tBOOL CBaical::Get_Initialized(eError &o_rError)
{
    o_rError = m_eError;
    return m_bInitialized;
}//Get_Initialized


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Plugins_Count
tUINT32 CBaical::Get_Plugins_Count(Bk::ePluginType i_eType)
{
    tUINT32 l_dwResult = 0;

    if (Bk::ePluginProvider == i_eType)
    {
        if (m_pProviders)
        {
            l_dwResult = m_pProviders->Count();
        }
    }
    else if (Bk::ePluginStorage == i_eType)
    {
        if (m_pStorages)
        {
            l_dwResult = m_pStorages->Count();
        }
    }
    else if (Bk::ePluginViewerGUI == i_eType)
    {
        if (m_pViewers)
        {
            l_dwResult = m_pViewers->Count();
        }
    }
    else if (Bk::ePluginStreamsDispatcher == i_eType)
    {
        if (m_pDispatchers)
        {
            l_dwResult = m_pDispatchers->Count();
        }
    }
    else if (Bk::ePluginStreamsProcessor == i_eType)
    {
        if (m_pProcessors)
        {
            l_dwResult = m_pProcessors->Count();
        }
    }

    return l_dwResult;
}//Get_Plugins_Count


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Plugin_Info
tBOOL CBaical::Get_Plugin_Info(Bk::ePluginType i_eType, tUINT32 i_dwIDX, Bk::stPluginInfo *o_pInfo)
{

    tBOOL l_bResult = FALSE;
    
    if (NULL == o_pInfo)
    {
        return l_bResult;
    }

    if (Bk::ePluginProvider == i_eType)
    {
        if (m_pProviders)
        {
            CProvider *l_cProvider = (*m_pProviders)[i_dwIDX];
            if (l_cProvider)
            {
                l_cProvider->Get_Info(*o_pInfo);
                l_bResult = TRUE;
            }
        }
    }
    else if (Bk::ePluginStorage == i_eType)
    {
        if (m_pStorages)
        {
            CStorage *l_cStorage = (*m_pStorages)[i_dwIDX];
            if (l_cStorage)
            {
                l_cStorage->Get_Info(*o_pInfo);
                l_bResult = TRUE;
            }
        }
    }
    else if (Bk::ePluginViewerGUI == i_eType)
    {
        if (m_pViewers)
        {
            CViewer *l_cViewer = (*m_pViewers)[i_dwIDX];
            if (l_cViewer)
            {
                l_cViewer->Get_Info(*o_pInfo);
                l_bResult = TRUE;
            }
        }
    }
    else if (Bk::ePluginStreamsDispatcher == i_eType)
    {
        if (m_pDispatchers)
        {
            CDispatcher *l_pDispatcher = (*m_pDispatchers)[i_dwIDX];
            if (l_pDispatcher)
            {
                l_pDispatcher->Get_Info(*o_pInfo);
                l_bResult = TRUE;
            }
        }
    }
    else if (Bk::ePluginStreamsProcessor == i_eType)
    {
        if (m_pProcessors)
        {
            CProcessor *l_pProcessor = (*m_pProcessors)[i_dwIDX];
            if (l_pProcessor)
            {
                l_pProcessor->Get_Info(*o_pInfo);
                l_bResult = TRUE;
            }
        }
    }


    return l_bResult;
}//Get_Plugin_Info



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Node
Bk::IBNode *CBaical::Get_Node(GUID *i_pGUID, const tXCHAR *i_pName)
{
    Bk::IBNode *l_pReturn   = NULL;
    Bk::IBNode *l_pRoot     = NULL;
    Bk::IBNode *l_pElements = NULL;
    GUID        l_sGUID     = {0};

    if (    (NULL == i_pGUID)
         || (NULL == m_iBDoc)
       )
    {
        return l_pReturn;
    }

    m_iBDoc->GetChildFirst(BNODE_ROOT, &l_pRoot);

    if (NULL == l_pRoot)
    {
        goto l_lblExit;
    }
     
    l_pRoot->GetChildFirst(BNODE_ELEMENT, &l_pElements);

    while (l_pElements)
    {
        tXCHAR *l_pText = NULL;
        l_pElements->GetAttrText(BNODE_VAL_ELEMENT_GUID, &l_pText);

        if (    (l_pText)
             && (CWString::ScanGuid(l_pText, l_sGUID))
             && (0 == memcmp(i_pGUID, &l_sGUID, sizeof(GUID)))
           )
        {
            break;
        }
        else
        {
            Bk::IBNode *l_pNext = NULL;
            l_pElements->GetNext(&l_pNext);
            l_pElements->Release();
            l_pElements = l_pNext;
        }
    }

    if (NULL == l_pElements)
    {
        tXCHAR l_pGText[64];
        PSPrint(l_pGText, 
                LENGTH(l_pGText), 
                TM("{%.8X-%.4X-%.4X-%.2X%.2X-%.2X%.2X%.2X%.2X%.2X%.2X}"),
                (tUINT32)i_pGUID->Data1,
                (tUINT32)i_pGUID->Data2,
                (tUINT32)i_pGUID->Data3,
                (tUINT32)i_pGUID->Data4[0],
                (tUINT32)i_pGUID->Data4[1],
                (tUINT32)i_pGUID->Data4[2],
                (tUINT32)i_pGUID->Data4[3],
                (tUINT32)i_pGUID->Data4[4],
                (tUINT32)i_pGUID->Data4[5],
                (tUINT32)i_pGUID->Data4[6],
                (tUINT32)i_pGUID->Data4[7]
                );

        l_pRoot->AddChildEmpty(BNODE_ELEMENT, &l_pElements);
        if (l_pElements)
        {
            l_pElements->SetAttrText(BNODE_VAL_ELEMENT_NAME, i_pName);
            l_pElements->SetAttrText(BNODE_VAL_ELEMENT_GUID, l_pGText);
        }
        else
        {
            LOG_ERROR(TM("AddChildEmpty fails"), 0);
        }
    }

l_lblExit:
    if (l_pRoot)
    {
        l_pRoot->Release();
        l_pRoot = NULL;
    }

    return l_pElements;
}//Get_Node


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Create_Viewer
Bk::IViewer *CBaical::Create_Viewer(WND_HANDLE              i_hParent, 
                                    GUID                   *i_pStream_GUID,
                                    Bk::IStorageReader     *i_iReader,
                                    Bk::IStreamEx          *i_iExtra,
                                    Bk::IViewersEnumerator *i_pEnum
                                   )
{
    Bk::IViewer *l_pReturn = NULL;

    pAList_Cell l_pCell = NULL;
    while ((l_pCell = m_pViewers->Get_Next(l_pCell)))
    {
        CViewer *l_pViewer = m_pViewers->Get_Data(l_pCell);
        if (    (l_pViewer)
             && (Bk::eOk == l_pViewer->Is_Stream_Supported(i_pStream_GUID))
           )
        {
            l_pReturn = l_pViewer->Create_Viewer(i_hParent, i_iReader, i_iExtra, i_pEnum);
            break;
        }
    }
    
    return l_pReturn;
}//Create_Viewer


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Open_Storage
Bk::eResult CBaical::Open_Storage(WND_HANDLE           i_hParent,
                                  Bk::IStorageReader **o_pReader,
                                  const tXCHAR        *i_pFile
                                 )
{
    Bk::eResult l_eReturn = Bk::eErrorWrongInput;

    if (    (NULL == m_pStorages)
         || (NULL == i_pFile)
         || (NULL == o_pReader)
       )
    {
        return l_eReturn;
    }

    *o_pReader = NULL;

    pAList_Cell l_pEl = NULL;
    while ((l_pEl = m_pStorages->Get_Next(l_pEl)))
    {
        CStorage *l_pStorage = m_pStorages->Get_Data(l_pEl);
        if (l_pStorage)
        {
            l_eReturn = l_pStorage->Open_Storage(i_hParent, o_pReader, i_pFile);
        }

        if (Bk::eOk == l_eReturn)
        {
            break;
        }
    }

    return l_eReturn;
}//Open_Storage


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Import
Bk::eResult CBaical::Import(const tXCHAR *i_pFile)
{
    Bk::eResult l_eReturn = Bk::eErrorWrongInput;

    if (    (NULL == m_pProviders)
         || (NULL == i_pFile)
       )
    {
        return l_eReturn;
    }

    pAList_Cell l_pEl = NULL;
    while ((l_pEl = m_pProviders->Get_Next(l_pEl)))
    {
        CProvider *l_pProvider = m_pProviders->Get_Data(l_pEl);
        if (l_pProvider)
        {
            l_eReturn = l_pProvider->Import(i_pFile);

            if (Bk::eOk == l_eReturn)
            {
                break;
            }
        }
    }

    return l_eReturn;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//BreakdownNotify
void CBaical::BreakdownNotify(eCrashCode i_eCode, const void *i_pContext)
{
    UNUSED_ARG(i_eCode);
    UNUSED_ARG(i_pContext);

    CProvider   *l_pProvider      = NULL;
    pAList_Cell  l_pProvider_Cell = NULL;

    while ((l_pProvider_Cell = m_pProviders->Get_Next(l_pProvider_Cell)))
    {
        l_pProvider = m_pProviders->Get_Data(l_pProvider_Cell);

        if (l_pProvider)
        {
            l_pProvider->m_iProvider->Exceptional_Shutdown();
        } 
    } //while (l_pProvider_Cell = m_pProviders->GetNext(l_pProvider_Cell))

    P7_Exceptional_Flush();

#if defined(_WIN32) || defined(_WIN64)
    ShellExecuteW(0, 
                  NULL, 
                  m_cExe.Get(), 
                  CRASH_PROCESS_END_WAIT_FALG, 
                  m_cDir.Get(), 
                  SW_SHOWNORMAL
                 );
#endif
}//BreakdownNotify


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Properties
CProperty* CBaical::Get_Properties()
{
    return m_pProperties;
}//Get_Properties


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Create_Storage
Bk::eResult CBaical::Create_Storage(Bk::stStreamInfo *i_pInfo, Bk::IStorage *&o_rStorage)
{
    Bk::eResult   l_eReturn     = Bk::eOk;
    pAList_Cell   l_pElDisp     = NULL;  
    CStorage     *l_pHoster     = NULL;
    CDispatcher  *l_pDispatcher = NULL;

    while ((l_pElDisp = m_pDispatchers->Get_Next(l_pElDisp)))
    {
        l_pDispatcher = m_pDispatchers->Get_Data(l_pElDisp);
        if (l_pDispatcher)
        {
            Bk::IPlugin *l_pPlugin = l_pDispatcher->Dispatch(*i_pInfo);

            if (l_pPlugin)
            {
                l_pHoster = dynamic_cast<CStorage*>(l_pPlugin);

                if (l_pHoster)
                {
                    o_rStorage = l_pHoster->Create_Storage(i_pInfo);
                    if (o_rStorage)
                    {
                        break;
                    }
                }
            }
        }
    } //while (l_pElDisp = m_pDispatchers->Get_Next(l_pElDisp))


    //make increment l_iStorage->Add_Ref inside 
    if (!o_rStorage)
    {
        l_eReturn = Bk::eErrorNotSupported;
        LOG_ERROR(TM("Storage instance wasn't created !"));
    }

    return l_eReturn;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Register_New_Stream
Bk::eResult CBaical::Register_New_Stream(const void *i_pStreamId, Bk::IStorageReader *i_pReader, Bk::IStreamEx *i_pExtra)
{
    UNUSED_ARG(i_pStreamId);

    if (    (FALSE == m_bInitialized)
         || (NULL  == i_pReader)
       )
    {
        return Bk::eErrorNotActive;
    }

    CLock l_cLock(&m_cLock_Subscribers);

    pAList_Cell l_pEl = NULL;
    while ((l_pEl = m_cSubscribers.Get_Next(l_pEl)))
    {
        CStreams *l_pSubrscriber = m_cSubscribers.Get_Data(l_pEl);
        if (l_pSubrscriber)
        {
            l_pSubrscriber->Push(i_pReader, i_pExtra);
        }
    }

    return Bk::eOk;
}//Register_New_Stream


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Add_Ref
tINT32 CBaical::Add_Ref()
{
    return ATOMIC_INC(&m_lReference);
}//Add_Ref


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Release
tINT32 CBaical::Release()
{
    tINT32 l_lResult = ATOMIC_DEC(&m_lReference);
    if ( 0 >= l_lResult )
    {
        //LOG_ERROR( TM("Plugin destroyed using"));
        delete this;
    }

    return l_lResult;
}//Release


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Query_Interface
Bk::eResult CBaical::Query_Interface(Bk::eInterface i_eId, void *&o_rUnknown)
{
    Bk::eResult  l_eReturn = Bk::eErrorNotImplemented;

    o_rUnknown = NULL;

    if (Bk::eInterfaceCore == i_eId)
    {
        o_rUnknown = dynamic_cast<Bk::ICore*>(this);

        if (o_rUnknown)
        {
            Add_Ref();
            l_eReturn = Bk::eOk;
        }
    }
    else if (Bk::eInterfaceStoragesEnumerator == i_eId)
    {
        o_rUnknown = dynamic_cast<Bk::IPluginsEnumerator*>(new CEnumerator_Storages(m_pStorages));
        l_eReturn  = Bk::eOk;
    }
    else if (Bk::eInterfaceStreams == i_eId)
    {
        CLock l_cLock(&m_cLock_Subscribers);

        CStreams *l_pSubscriber = new CStreams(this);
        l_pSubscriber->Add_Ref();
        m_cSubscribers.Add_After(m_cSubscribers.Get_Last(), l_pSubscriber);
        o_rUnknown = dynamic_cast<Bk::IStreams*>(l_pSubscriber);
        l_eReturn  = Bk::eOk;
    }

    return l_eReturn;
}//Query_Interface


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Unregister_Subscriber
void CBaical::Unregister_Subscriber(Bk::IStreams *i_pStreams)
{
    CLock l_cLock(&m_cLock_Subscribers);
    pAList_Cell l_pEl = NULL;

    while ((l_pEl = m_cSubscribers.Get_Next(l_pEl)))
    {
        if (i_pStreams == m_cSubscribers.Get_Data(l_pEl))
        {
            m_cSubscribers.Del(l_pEl, FALSE);
            break;
        }
    }
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Load_Properties
tBOOL CBaical::Load_Properties(Bk::IBNode *i_pNode, CProperty *i_pParent)
{
    if (    (!i_pNode)
         || (!i_pParent)
       )
    {
        return FALSE;
    }

    Bk::IBNode *l_pChildXml = NULL;

    ////////////////////////////////////////////////////////////////////////////
    //Loading properties groups
    i_pNode->GetChildFirst(BNODE_PROP_GROUP, &l_pChildXml);

    while (l_pChildXml)
    {
        CProperty::eFlags  l_eFlags     = CProperty::eEmpty;
        tXCHAR            *l_pText      = NULL;
        CProperty         *l_pChildProp = NULL;

        l_pChildXml->GetAttrText(BNODE_PROP_GROUP_ATTR_NAME, &l_pText);
        l_pChildXml->GetAttrInt32(BNODE_PROP_GROUP_ATTR_FLAGS, (tINT32*)&l_eFlags);

        if (CProperty::Create(i_pParent, 
                              CProperty::eGroup, 
                              l_pText ? l_pText : TM("Group"), 
                              l_pChildProp
                             )
           )
        {
            l_pChildProp->Set_Data(new CPropData(l_pChildXml));
            l_pChildProp->Set_Flags(l_eFlags);
            Load_Properties(l_pChildXml, l_pChildProp);
            l_pChildProp->Release();
            l_pChildProp = NULL;
        }

        Bk::IBNode *l_pNext = NULL;
        l_pChildXml->GetNext(BNODE_PROP_GROUP, &l_pNext);
        l_pChildXml->Release();
        l_pChildXml = l_pNext;
    }//while (l_pChildXml)

    ////////////////////////////////////////////////////////////////////////////
    //Loading properties groups
    i_pNode->GetChildFirst(BNODE_PROP, &l_pChildXml);
    while (l_pChildXml)
    {
        CProperty        *l_pChildProp = NULL;
        CProperty::eFlags l_eFlags     = CProperty::eEmpty;
        tXCHAR          *l_pType      = NULL;
        tXCHAR          *l_pName      = NULL;
        tXCHAR          *l_pDesc      = NULL;
                  
        l_pChildXml->GetAttrText(BNODE_PROP_ATTR_TYPE,  &l_pType);
        l_pChildXml->GetAttrText(BNODE_PROP_ATTR_NAME,  &l_pName);
        l_pChildXml->GetAttrText(BNODE_PROP_ATTR_DESC,  &l_pDesc);
        l_pChildXml->GetAttrInt32(BNODE_PROP_ATTR_FLAGS, (tINT32*)&l_eFlags);

        if (    (NULL == l_pType)
             || (NULL == l_pName)
           )
        {
            //nothing
        }
        else if (0 == PStrICmp(TM("Int"), l_pType))
        {
            tXCHAR *l_pMin   = NULL;
            tXCHAR *l_pMax   = NULL;
            tXCHAR *l_pValue = NULL;
            tINT64  l_llMin  = 0ll;
            tINT64  l_llMax  = 0ll;
            tINT64  l_llVal  = 0ll;

            l_pChildXml->GetAttrText(BNODE_PROP_ATTR_VALUE, &l_pValue);
            l_pChildXml->GetAttrText(BNODE_PROP_ATTR_MIN, &l_pMin);
            l_pChildXml->GetAttrText(BNODE_PROP_ATTR_MAX, &l_pMax);

            if (    (l_pMin)
                 && (l_pMax)
                 && (l_pValue)
               )
            {
                PStrScan(l_pValue, TM("%lld"), &l_llVal);
                PStrScan(l_pMin,   TM("%lld"), &l_llMin);
                PStrScan(l_pMax,   TM("%lld"), &l_llMax);

                if (CProperty::Create(i_pParent, 
                                      CProperty::eInt, 
                                      l_pName, 
                                      l_pChildProp
                                     )
                   )
                {
                    l_pChildProp->Set_Value(l_llVal);
                    l_pChildProp->Set_Range(l_llMin, l_llMax);
                }
            }
        }
        else if (0 == PStrICmp(TM("Text"), l_pType))
        {
            tXCHAR *l_pValue = NULL;
            l_pChildXml->GetAttrText(BNODE_PROP_ATTR_VALUE, &l_pValue);

            if (CProperty::Create(i_pParent, 
                                  CProperty::eText, 
                                  l_pName, 
                                  l_pChildProp
                                 )
               )
            {
                l_pChildProp->Set_Value(l_pValue);
            }
        }
        else if (0 == PStrICmp(TM("Enum"), l_pType))
        {
            tINT32 l_lIndex = 0;
            l_pChildXml->GetAttrInt32(BNODE_PROP_ATTR_INDEX, &l_lIndex);

            if (CProperty::Create(i_pParent, 
                                  CProperty::eEnum, 
                                  l_pName, 
                                  l_pChildProp
                                 )
               )
            {
                Bk::IBNode *l_pItemXml = NULL;

                l_pChildXml->GetChildFirst(BNODE_PROP_ITEM, &l_pItemXml);
                while (l_pItemXml)
                {
                    tXCHAR *l_pItemText  = NULL;
                    tXCHAR *l_pItemValue = NULL;

                    l_pItemXml->GetAttrText(BNODE_PROP_ITEM_ATTR_TEXT, &l_pItemText);
                    l_pItemXml->GetAttrText(BNODE_PROP_ITEM_ATTR_VALUE, &l_pItemValue);

                    if (    (l_pItemText)
                         && (l_pItemValue)
                       )
                    {
                        tINT64 l_llItemValue = 0;
                        PStrScan(l_pItemValue, TM("%lld"), &l_llItemValue);
                        l_pChildProp->Add_Item(l_pItemText, l_llItemValue);
                    }

                    Bk::IBNode *l_pNext = NULL;
                    l_pItemXml->GetNext(BNODE_PROP_ITEM, &l_pNext);
                    l_pItemXml->Release();
                    l_pItemXml = l_pNext;
                }

                l_pChildProp->Set_Current_Index((tINT32)l_lIndex);
            }
        }

        if (l_pChildProp)
        {
            l_pChildProp->Set_Desc(l_pDesc);
            l_pChildProp->Set_Flags(l_eFlags);
            l_pChildProp->Set_Data(new CPropData(l_pChildXml));
            l_pChildProp->Release();
            l_pChildProp = NULL;


        }

        Bk::IBNode *l_pNext = NULL;
        l_pChildXml->GetNext(BNODE_PROP, &l_pNext);
        l_pChildXml->Release();
        l_pChildXml = l_pNext;
    }

    return TRUE;
}//Load_Properties


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Save_Properties
tBOOL CBaical::Save_Properties(CProperty *i_pProp)
{
    if (NULL == i_pProp)
    {
        return FALSE;
    }

    ////////////////////////////////////////////////////////////////////////////
    //save data to XML
    CPropData *l_pData = static_cast<CPropData*>(i_pProp->Get_Data());
    
    if (l_pData)
    {
        Bk::IBNode *l_pXml = l_pData->m_pXml;

        if (l_pXml)
        {
            if (CProperty::eEnum == i_pProp->Type())
            {
                tINT32 l_dwIndex = 0;

                i_pProp->Get_Current_Index(l_dwIndex);
                l_pXml->SetAttrInt32(BNODE_PROP_ATTR_INDEX, (tINT32)l_dwIndex);
            }
            else if (CProperty::eText == i_pProp->Type())
            {
                const tXCHAR *l_pVal = NULL;
                i_pProp->Get_Value(l_pVal);
                l_pXml->SetAttrText(BNODE_PROP_ATTR_VALUE, l_pVal);
            }
            else if (CProperty::eInt == i_pProp->Type())
            {
                tINT64  l_llVal = 0ll;
                tXCHAR l_pTemp[16];

                i_pProp->Get_Value(l_llVal);
                PSPrint(l_pTemp, LENGTH(l_pTemp), TM("%lld"), l_llVal);
                l_pXml->SetAttrText(BNODE_PROP_ATTR_VALUE, l_pTemp);
            }

            l_pXml->SetAttrInt32(BNODE_PROP_ATTR_FLAGS, (tINT32)i_pProp->Flags());
        }
    }
    else //if XML node isn't created and we want to save it
    {
        CProperty *l_pParent = i_pProp->Get_Parent();
        if (l_pParent)
        {
            l_pData = static_cast<CPropData*>(l_pParent->Get_Data());
            if (    (l_pData)
                 && (l_pData->m_pXml)
               )
            {
                Bk::IBNode *l_pParentXml = l_pData->m_pXml;
                Bk::IBNode *l_pChildXml  = NULL;

                if (CProperty::eGroup == i_pProp->Type())
                {
                    l_pParentXml->AddChildEmpty(BNODE_PROP_GROUP, &l_pChildXml);
                    if (l_pChildXml)
                    {
                        l_pChildXml->SetAttrText(BNODE_PROP_GROUP_ATTR_NAME, i_pProp->Name());
                    }
                }
                else 
                {
                    l_pParentXml->AddChildEmpty(BNODE_PROP, &l_pChildXml);
                    if (l_pChildXml)
                    {
                        l_pChildXml->SetAttrText(BNODE_PROP_ATTR_NAME, i_pProp->Name());
                        l_pChildXml->SetAttrText(BNODE_PROP_ATTR_DESC, i_pProp->Desc());
                        l_pChildXml->SetAttrInt32(BNODE_PROP_ATTR_FLAGS, (tINT32)i_pProp->Flags());

                        if (CProperty::eEnum == i_pProp->Type())
                        {
                            tINT32  l_dwIndex = 0;
                            tUINT32 l_dwCount = 0;

                            l_pChildXml->SetAttrText(BNODE_PROP_ATTR_TYPE, TM("Enum"));

                            i_pProp->Get_Current_Index(l_dwIndex);
                            i_pProp->Get_Items_Count(l_dwCount);
                            l_pChildXml->SetAttrInt32(BNODE_PROP_ATTR_INDEX, (tINT32)l_dwIndex);
                        
                            for (tUINT32 l_dwI = 0; l_dwI < l_dwCount; l_dwI++)
                            {
                                Bk::IBNode *l_pItem = NULL;
                                l_pChildXml->AddChildEmpty(BNODE_PROP_ITEM, &l_pItem);
                                if (l_pItem)
                                {
                                    const tXCHAR *l_pName = NULL;
                                    tINT64        l_llVal = 0ll;
                                    tXCHAR        l_pVal[16];

                                    i_pProp->Get_Item(l_dwI, l_pName, l_llVal);
                                    PSPrint(l_pVal, LENGTH(l_pVal), TM("%lld"), l_llVal);

                                    l_pItem->SetAttrText(BNODE_PROP_ITEM_ATTR_TEXT, l_pName);
                                    l_pItem->SetAttrText(BNODE_PROP_ITEM_ATTR_VALUE, l_pVal);

                                    l_pItem->Release();
                                    l_pItem = NULL;
                                }
                            }
                        }
                        else if (CProperty::eText == i_pProp->Type())
                        {
                            const tXCHAR *l_pVal = NULL;
                            l_pChildXml->SetAttrText(BNODE_PROP_ATTR_TYPE, TM("Text"));

                            i_pProp->Get_Value(l_pVal);
                            l_pChildXml->SetAttrText(BNODE_PROP_ATTR_VALUE, l_pVal);
                        }
                        else if (CProperty::eInt == i_pProp->Type())
                        {
                            tINT64  l_llVal = 0ll;
                            tINT64  l_llMin = 0ll;
                            tINT64  l_llMax = 0ll;
                            tXCHAR l_pTemp[16];
                            l_pChildXml->SetAttrText(BNODE_PROP_ATTR_TYPE, TM("Int"));

                            i_pProp->Get_Value(l_llVal);
                            i_pProp->Get_Range(l_llMin, l_llMax);
                            PSPrint(l_pTemp, LENGTH(l_pTemp), TM("%lld"), l_llVal);
                            l_pChildXml->SetAttrText(BNODE_PROP_ATTR_VALUE, l_pTemp);

                            PSPrint(l_pTemp, LENGTH(l_pTemp), TM("%lld"), l_llMin);
                            l_pChildXml->SetAttrText(BNODE_PROP_ATTR_MIN, l_pTemp);

                            PSPrint(l_pTemp, LENGTH(l_pTemp), TM("%lld"), l_llMax);
                            l_pChildXml->SetAttrText(BNODE_PROP_ATTR_MAX, l_pTemp);
                        }
                    }
                }

                if (l_pChildXml)
                {
                    i_pProp->Set_Data(new CPropData(l_pChildXml));
                    l_pChildXml->Release();
                }
            }

            l_pParent->Release();
            l_pParent = NULL;
        }
    }

    size_t l_szCount = 0;
    i_pProp->Get_SubItems_Count(l_szCount);
    while (l_szCount)
    {
        CProperty *l_pChild = NULL;
        
        i_pProp->Get_SubItem(--l_szCount, l_pChild);
        if (l_pChild)
        {
            Save_Properties(l_pChild);
            l_pChild->Release();
        }
    }

    return TRUE;
}//Save_Properties


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//P7_Release
void CBaical::P7_Release()
{
    if (m_iP7_Trace)
    {
        m_iP7_Trace->Release();
        m_iP7_Trace = NULL;
    }

    if (m_iP7_Tel)
    {
        m_iP7_Tel->Release();
        m_iP7_Tel = NULL;
    }

    if (m_iP7)
    {
        m_iP7->Release();
        m_iP7 = NULL;
    }
}//P7_Release



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Load_Plugins
tBOOL CBaical::Enum_Plugins()
{
    tBOOL             l_bReturn   = TRUE;
    pAList_Cell       l_pDll_Cell = NULL;
    CBList<CWString*> l_cDll_List;
    CWString          l_cDirectory;

    if (FALSE == l_cDirectory.Realloc(4096))
    {
        l_bReturn = FALSE;
        LOG_ERROR(TM("Buffer allocation for directory fails !"));
        goto l_lblCleanUp;
    }

    CProc::Get_Process_Path(l_cDirectory.Get(), l_cDirectory.Max_Length());

    CFSYS::Enumerate_Files(&l_cDll_List, &l_cDirectory, TM("*.") SHARED_EXT);

    while ((l_pDll_Cell = l_cDll_List.Get_Next(l_pDll_Cell)) != NULL)
    {
        CWString *l_pDll_Path = l_cDll_List.Get_Data(l_pDll_Cell);
        if (l_pDll_Path)
        {
            Add_Plugin(l_pDll_Path->Get());
        } //if (l_pDll_Path)
    } //while ((l_pDll_Cell = l_cDll_List.Get_Next(l_pDll_Cell)) != NULL)

    Sort_Dispatchers();

l_lblCleanUp:
    l_cDll_List.Clear(TRUE);

    return l_bReturn;
}//Load_Plugins


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Sort_Dispatchers
void CBaical::Sort_Dispatchers()
{
    pAList_Cell l_pStart   = NULL;

    while ((l_pStart = m_pDispatchers->Get_Next(l_pStart)))
    {
        pAList_Cell l_pMax = l_pStart;
        pAList_Cell l_pCur = l_pStart;

        while ((l_pCur = m_pDispatchers->Get_Next(l_pCur)))
        {
            CDispatcher *l_pDispM = m_pDispatchers->Get_Data(l_pMax);
            CDispatcher *l_pDispI = m_pDispatchers->Get_Data(l_pCur);

            if (l_pDispI->GetPriority() > l_pDispM->GetPriority())
            {
                l_pMax = l_pCur;
            }
        }

        if (l_pMax != l_pStart)
        {
            m_pDispatchers->Extract(l_pMax);
            m_pDispatchers->Put_After(m_pDispatchers->Get_Prev(l_pStart), l_pMax);
            l_pStart = l_pMax;
        }
    } //while (l_pStart = m_pDispatchers->Get_Next(l_pStart))
}//Sort_Dispatchers


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Add_Plugin
tBOOL CBaical::Add_Plugin(tXCHAR *i_pPath)
{
    fnBkGetPluginInfo l_pBPlugin_Get_Info = NULL;
    Bk::stPluginInfo  l_sPlugin_Info      = {0};
    tBOOL             l_bReturn           = TRUE;
    CPSharedLib      *l_hDll              = NULL;
    tBOOL             l_bReleaseDll       = TRUE;
    
    if (NULL == i_pPath)
    {
        return FALSE;
    }

    if (l_bReturn)
    {
        l_hDll = new CPSharedLib(i_pPath);
        if (NULL == l_hDll)
        {
            LOG_WARNING(TM("Failed to load plugin: %s"), i_pPath);
            l_bReturn = FALSE;
        }
    }

    if (l_bReturn)
    {
        *(void **)(&l_pBPlugin_Get_Info) = l_hDll->GetFunction(BK_GET_PLUGIN_INFO);
        if (NULL == l_pBPlugin_Get_Info)
        {
            LOG_WARNING(TM("Function {") TMM(BK_GET_PLUGIN_INFO) TM("} isn't accessible inside {%s}"), i_pPath);
            l_bReturn = FALSE;
        }
    }

    if (l_bReturn)
    {
        if (Bk::eOk != l_pBPlugin_Get_Info(&l_sPlugin_Info))
        {
            LOG_WARNING(TM("Failed to call Plugin_Get_Info"));
            l_bReturn = FALSE;
        }
    }

    if (l_bReturn)
    {
        if (BK_PLUGIN_API_VERSION != l_sPlugin_Info.dwAPI_Version)
        {
            LOG_WARNING(TM("Plugin's API version is wrong %d, we expect = %d"), 
                        (tUINT32)l_sPlugin_Info.dwAPI_Version,
                        (tUINT32)BK_PLUGIN_API_VERSION
                       );

            l_bReturn = FALSE;
        }
    }

    if (l_bReturn)
    {
        CProperty  *l_pProp = NULL;
        Bk::IBNode *l_pNode = Get_Node(&l_sPlugin_Info.sGUID, l_sPlugin_Info.pName);

        if (l_pNode)
        {
            CProperty::Create(m_pProperties, CProperty::eGroup, l_sPlugin_Info.pName, l_pProp);
            if (l_pProp)
            {
                l_pProp->Set_Data(new CPropData(l_pNode));
                Load_Properties(l_pNode, l_pProp);
            }
        }

        if (Bk::ePluginProvider == l_sPlugin_Info.eType)
        {
            CProvider* l_pProvider = new CProvider(dynamic_cast<Bk::IUnknown*>(this),
                                                   l_pNode, 
                                                   l_pProp, 
                                                   m_iP7_Trace,
                                                   l_hDll, 
                                                   &l_sPlugin_Info,
                                                   i_pPath
                                                  );

            if (    (l_pProvider)
                 && (TRUE == l_pProvider->Get_Initialized())
               )
            {
                m_pProviders->Add_After(m_pProviders->Get_Last(), l_pProvider);
                //this mean that this handle is responsibility of provider plugin
                l_bReleaseDll = FALSE;
            }
            else
            {
                if (l_pProvider)
                {
                    delete l_pProvider;
                    l_pProvider = NULL;
                }

                l_bReturn = FALSE;
                LOG_WARNING(TM("Provider plugin creation fail"));

            }
        }
        else if (Bk::ePluginStorage == l_sPlugin_Info.eType)
        {
            CStorage* l_pStorage = new CStorage(dynamic_cast<Bk::IUnknown*>(this),
                                                l_pNode, 
                                                l_pProp, 
                                                m_iP7_Trace,
                                                l_hDll, 
                                                &l_sPlugin_Info,
                                                i_pPath
                                               );

            if (    (l_pStorage)
                 && (TRUE == l_pStorage->Get_Initialized())
               )
            {
                m_pStorages->Add_After(m_pStorages->Get_Last(), l_pStorage);
                //this mean that this handle is responsibility of provider plugin
                l_bReleaseDll = FALSE;
            }
            else
            {
                if (l_pStorage)
                {
                    delete l_pStorage;
                    l_pStorage = NULL;
                }

                l_bReturn = FALSE;
                LOG_WARNING(TM("Storage plugin creation fail"));

            }
        }
        else if (    (    (Bk::ePluginViewerGUI == l_sPlugin_Info.eType)
                       && (CBaical::eModeGUI == m_eMode)
                     )
                  || (    (Bk::ePluginViewerCLI == l_sPlugin_Info.eType)
                       && (CBaical::eModeCLI == m_eMode)
                     )
                )
        {
            CViewer* l_pViewer = new CViewer(dynamic_cast<Bk::IUnknown*>(this),
                                             l_pNode, 
                                             l_pProp, 
                                             m_iP7_Trace,
                                             l_hDll, 
                                             &l_sPlugin_Info,
                                             i_pPath
                                            );

            if (    (l_pViewer)
                 && (TRUE == l_pViewer->Get_Initialized())
               )
            {
                m_pViewers->Add_After(m_pViewers->Get_Last(), l_pViewer);
                //this mean that this handle is responsibility of provider plugin
                l_bReleaseDll = FALSE;
            }
            else
            {
                if (l_pViewer)
                {
                    delete l_pViewer;
                    l_pViewer = NULL;
                }

                l_bReturn = FALSE;
                LOG_WARNING(TM("Viewer plugin creation fail"));

            }
        }
        else if (Bk::ePluginStreamsDispatcher == l_sPlugin_Info.eType)
        {
            CDispatcher* l_pDispatcher = new CDispatcher(dynamic_cast<Bk::IUnknown*>(this),
                                                         l_pNode, 
                                                         l_pProp, 
                                                         m_iP7_Trace,
                                                         l_hDll, 
                                                         &l_sPlugin_Info,
                                                         i_pPath
                                                        );

            if (    (l_pDispatcher)
                 && (TRUE == l_pDispatcher->Get_Initialized())
               )
            {
                m_pDispatchers->Add_After(m_pDispatchers->Get_Last(), l_pDispatcher);
                //this mean that this handle is responsibility of provider plugin
                l_bReleaseDll = FALSE;
            }
            else
            {
                if (l_pDispatcher)
                {
                    delete l_pDispatcher;
                    l_pDispatcher = NULL;
                }

                l_bReturn = FALSE;
                LOG_WARNING(TM("Dispacher plugin creation fail"));

            }
        }
        else if (Bk::ePluginStreamsProcessor == l_sPlugin_Info.eType)
        {
            CProcessor* l_pProcessor = new CProcessor(dynamic_cast<Bk::IUnknown*>(this),
                                                      l_pNode, 
                                                      l_pProp, 
                                                      m_iP7_Trace,
                                                      l_hDll, 
                                                      &l_sPlugin_Info,
                                                      i_pPath
                                                     );

            if (    (l_pProcessor)
                 && (TRUE == l_pProcessor->Get_Initialized())
               )
            {
                m_pProcessors->Add_After(m_pProcessors->Get_Last(), l_pProcessor);
                //this mean that this handle is responsibility of provider plugin
                l_bReleaseDll = FALSE;
            }
            else
            {
                if (l_pProcessor)
                {
                    delete l_pProcessor;
                    l_pProcessor = NULL;
                }

                l_bReturn = FALSE;
                LOG_WARNING(TM("Dispacher plugin creation fail"));
            }
        }
        else
        {
            LOG_WARNING(TM("Plugin's type is unknown = %d"), (tUINT32)l_sPlugin_Info.eType);
            l_bReturn = FALSE;
        }


        if (l_pProp)
        {
            size_t l_szCount = 0;
            l_pProp->Get_SubItems_Count(l_szCount);
            if (0 >= l_szCount)
            {
                m_pProperties->Del_SubItem(l_pProp);
            }

            l_pProp->Release();
            l_pProp = NULL;
        }

        if (l_pNode)
        {
            l_pNode->Release();
            l_pNode = NULL;
        }
    }

    if (l_bReleaseDll)
    {
        l_hDll->Release();
        l_hDll = NULL;
    }
    else
    {
        m_cPluginsDll.Add_After(m_cPluginsDll.Get_Last(), l_hDll);
    }

    return l_bReturn;
}//Add_Plugin

