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

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CPlugin
CPlugin::CPlugin(Bk::IUnknown     *i_pBaical,
                 CPSharedLib      *i_hDLL,
                 Bk::stPluginInfo *i_pPlugin_Info,
                 IP7_Trace        *i_iTrace,
                 Bk::IBNode       *i_pNode,
                 CProperty        *i_pProp,
                 const tXCHAR     *i_pPath
                )
    : m_lReference(1)
    , m_hDLL(i_hDLL)
    , m_pBaical(i_pBaical)
    , m_iP7_Trace(i_iTrace)
    , m_hP7_TraceModule(NULL)
    , m_pNode(i_pNode)
    , m_pProp(i_pProp)
    , m_pIs_Stream_Supported(NULL)
{
    m_bInitialized = (NULL != m_hDLL) && (NULL != i_pPlugin_Info);

    m_cPath.Set(i_pPath);

    if (i_pPlugin_Info)
    {
        memcpy(&m_sPlugin_Info, i_pPlugin_Info, sizeof(m_sPlugin_Info));
    }
    else
    {
        memset(&m_sPlugin_Info, 0, sizeof(m_sPlugin_Info));
    }

    m_sPlugin_Info.qwVersion = CFSYS::Get_Version(i_pPath);

    if (m_iP7_Trace)
    {
        m_iP7_Trace->Add_Ref();
    }
    
    if (m_pNode)
    {
        m_pNode->Add_Ref();
    }

    if (m_pProp)
    {
        m_pProp->Add_Ref();
    }

    if (m_pBaical)
    {
        m_pBaical->Add_Ref();
    }
}//CPlugin


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Initialized
tBOOL CPlugin::Get_Initialized()
{
    return m_bInitialized;
}//Get_Initialized


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Is_Stream_Supported
Bk::eResult CPlugin::Is_Stream_Supported(const GUID *i_pGUID)
{
    Bk::eResult l_eReturn = Bk::eErrorNotSupported;
    if (m_pIs_Stream_Supported)
    {
        l_eReturn = m_pIs_Stream_Supported(i_pGUID);
    }

    return l_eReturn;
}//Is_Stream_Supported


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Info
Bk::eResult CPlugin::Get_Info(Bk::stPluginInfo &o_rInfo)
{
    memcpy(&o_rInfo, &m_sPlugin_Info, sizeof(m_sPlugin_Info));
    return Bk::eOk;
}//Get_Info


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Node
Bk::eResult CPlugin::Get_Node(Bk::IBNode *&o_rNode)
{
    o_rNode = m_pNode;
    if (m_pNode)
    {
        m_pNode->Add_Ref();
    }
    return Bk::eOk;
}//Get_Node


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Get_Prop
Bk::eResult CPlugin::Get_Prop(CProperty *&o_rProp)
{
    o_rProp = m_pProp;
    if (m_pProp)
    {
        m_pProp->Add_Ref();
    }
    return Bk::eOk;
}//Get_Prop


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


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

    return l_lResult;
}//Release


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~CPlugin
CPlugin::~CPlugin()
{
    if (m_pNode)
    {
        m_pNode->Release();
        m_pNode = NULL;
    }

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

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

    if (m_pBaical)
    {
        m_pBaical->Release();
    }

    m_hDLL = NULL;
    //library releasing will be done using m_cPluginsDll; 
}//~CPlugin




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CProvider
CProvider::CProvider(Bk::IUnknown     *i_pBaical,
                     Bk::IBNode       *i_pNode,
                     CProperty        *i_pProp,
                     IP7_Trace        *i_iTrace,
                     CPSharedLib      *i_hDLL,
                     Bk::stPluginInfo *i_pPlugin_Info,
                     const tXCHAR     *i_pPath
                    )
    : CPlugin(i_pBaical, i_hDLL, i_pPlugin_Info, i_iTrace, i_pNode, i_pProp, i_pPath)
    , m_pCreate_Provider(NULL)
    , m_iProvider(NULL)
{
    if (m_iP7_Trace)
    {
        m_iP7_Trace->Register_Module(TM("Baical"), &m_hP7_TraceModule);
    }


    if (m_bInitialized)
    {
        *(void **)(&m_pCreate_Provider) = m_hDLL->GetFunction(BK_CREATE_PROVIDER);

        if (NULL == m_pCreate_Provider)
        {
            LOG_WARNING(TM("Function {%S} isn't exist"), BK_CREATE_PROVIDER);
            m_bInitialized = FALSE;
        }
    }
}//CProvider


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Import
Bk::eResult CProvider::Import(const tXCHAR *i_pPath)
{
    if (m_iProvider)
    {
        void *l_pToken = NULL;
        return m_iProvider->Add_Source(i_pPath, l_pToken);
    }

    return Bk::eErrorInternal;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Initialize
Bk::eResult CProvider::Initialize()
{
    if (m_bInitialized)
    {
        if (Bk::eOk != m_pCreate_Provider(m_pBaical, m_pNode, m_pProp, &m_iProvider))
        {
            LOG_WARNING(TM("Create provider call is failed"));
            m_bInitialized = FALSE;
        }
    }

    return (m_bInitialized) ? Bk::eOk : Bk::eErrorInternal;
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~CProvider
CProvider::~CProvider()
{
    if (m_iProvider)
    {
        m_iProvider->Release();
        m_iProvider = NULL;
    }
}//~CProvider



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CStorage
CStorage::CStorage(Bk::IUnknown     *i_pBaical,
                   Bk::IBNode       *i_pNode,
                   CProperty        *i_pProp,
                   IP7_Trace        *i_iTrace,
                   CPSharedLib      *i_hDLL,
                   Bk::stPluginInfo *i_pPlugin_Info,
                   const tXCHAR     *i_pPath
                  )
    : CPlugin(i_pBaical, i_hDLL, i_pPlugin_Info, i_iTrace, i_pNode, i_pProp, i_pPath)
    , m_pCreate_Storage(NULL)
    , m_pOpen_Storage(NULL)
{
    if (m_iP7_Trace)
    {
        m_iP7_Trace->Register_Module(TM("Baical"), &m_hP7_TraceModule);
    }

    if (m_bInitialized)
    {
        *(void **)(&m_pIs_Stream_Supported) = m_hDLL->GetFunction(BK_IS_STREAM_SUPPORTED);
        *(void **)(&m_pCreate_Storage)      = m_hDLL->GetFunction(BK_CREATE_STORAGE);
        *(void **)(&m_pOpen_Storage)        = m_hDLL->GetFunction(BK_OPEN_STORAGE);

        if (    (NULL == m_pIs_Stream_Supported)
             || (NULL == m_pCreate_Storage)
             || (NULL == m_pOpen_Storage)
           )
        {
            LOG_ERROR( TM("Load plugin failed {%s}"), i_pPath);
            m_bInitialized = FALSE;
        }
    }
}//CStorage


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Create_Storage
Bk::IStorage *CStorage::Create_Storage(Bk::stStreamInfo  *i_pInfo)
{
    Bk::IStorage *l_pSorage = NULL;

    if (    (NULL  == m_pIs_Stream_Supported)
         || (NULL  == m_pCreate_Storage)
         || (NULL  == i_pInfo)
         || (Bk::eOk != m_pIs_Stream_Supported(&i_pInfo->sType_GUID))
       )
    {
        return l_pSorage;
    }
                                                  
    m_pCreate_Storage(&l_pSorage, i_pInfo, m_pNode, m_pProp);

    return l_pSorage;
}//Create_Storage


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

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

    *o_pReader = NULL;                               
    l_eReturn  = m_pOpen_Storage(o_pReader, m_pNode, m_pProp, i_pFile);

    if (Bk::eOk != l_eReturn)
    {
        if (*o_pReader)
        {
            (*o_pReader)->Release();
            *o_pReader = NULL;
        }
    }

    return l_eReturn;
}//Open_Storage



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~CStorage
CStorage::~CStorage()
{
}//~CStorage




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CViewer
CViewer::CViewer(Bk::IUnknown     *i_pBaical,
                 Bk::IBNode       *i_pNode,
                 CProperty        *i_pProp,
                 IP7_Trace        *i_iTrace,
                 CPSharedLib      *i_hDLL,
                 Bk::stPluginInfo *i_pPlugin_Info,
                 const tXCHAR     *i_pPath
                )
    : CPlugin(i_pBaical, i_hDLL, i_pPlugin_Info, i_iTrace, i_pNode, i_pProp, i_pPath)
    , m_pCreate_Viewer(NULL)
{     
    if (m_iP7_Trace)
    {
        m_iP7_Trace->Register_Module(TM("Baical"), &m_hP7_TraceModule);
    }

    if (m_bInitialized)
    {
        *(void **)(&m_pIs_Stream_Supported) = m_hDLL->GetFunction(BK_IS_STREAM_SUPPORTED);
        *(void **)(&m_pCreate_Viewer)       = m_hDLL->GetFunction(BK_CREATE_VIEWER);

        if (    (NULL == m_pIs_Stream_Supported)
             || (NULL == m_pCreate_Viewer)
           )
        {
            LOG_ERROR(TM("Load plugin failed {%s}"), i_pPath);
            m_bInitialized = FALSE;
        }
    }
}//CViewer


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

    if (    (NULL  == m_pIs_Stream_Supported)
         || (NULL  == m_pCreate_Viewer)
       )
    {
        return l_pReturn;
    }

    m_pCreate_Viewer(&l_pReturn, 
                     i_hParent,
                     m_pNode,
                     i_iReader,
                     i_iExtra,
                     m_pProp,
                     i_pEnum
                    );

    return l_pReturn;
}//Create_Viewer


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~CViewer
CViewer::~CViewer()
{
}//~CViewer




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CDispatcher
CDispatcher::CDispatcher(Bk::IUnknown     *i_pBaical,
                         Bk::IBNode       *i_pNode,
                         CProperty        *i_pProp,
                         IP7_Trace        *i_iTrace,
                         CPSharedLib      *i_hDLL,
                         Bk::stPluginInfo *i_pPlugin_Info,
                         const tXCHAR     *i_pPath
                        )
    : CPlugin(i_pBaical, i_hDLL, i_pPlugin_Info, i_iTrace, i_pNode, i_pProp, i_pPath)
    , m_pDispatcher(NULL)
{     
    if (m_iP7_Trace)
    {
        m_iP7_Trace->Register_Module(TM("Baical"), &m_hP7_TraceModule);
    }

    if (m_bInitialized)
    {
        fnBkCreateDispatcher l_fnCreate = NULL;
        *(void **)(&l_fnCreate) = m_hDLL->GetFunction(BK_CREATE_DISPATCHER);
        if (NULL != l_fnCreate)
        {
            l_fnCreate(m_pBaical, i_pNode, m_pProp, m_pDispatcher);
        }
    }

    if (!m_pDispatcher)
    {
        LOG_ERROR(TM("Load plugin failed {%s}"), i_pPath);
        m_bInitialized = FALSE;
    }
}//CDispatcher


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~CDispatcher
CDispatcher::~CDispatcher()
{
    if (m_pDispatcher)
    {
        m_pDispatcher->Release();
        m_pDispatcher = NULL;
    }
}//~CDispatcher


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Dispatch
Bk::IPlugin* CDispatcher::Dispatch(const Bk::stStreamInfo &i_rStreamInfo)
{
    if (!m_bInitialized)
    {
        return NULL;
    }

    return m_pDispatcher->Dispatch(i_rStreamInfo);
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//GetPriority
tUINT8 CDispatcher::GetPriority()
{
    if (!m_bInitialized)
    {
        return 0;
    }

    return m_pDispatcher->GetPriority();
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Initialize
Bk::eResult CDispatcher::Initialize()
{
    if (!m_bInitialized)
    {
        return Bk::eErrorInternal;
    }

    return m_pDispatcher->Initialize();
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CProcessor
CProcessor::CProcessor(Bk::IUnknown     *i_pBaical,
                       Bk::IBNode       *i_pNode,
                       CProperty        *i_pProp,
                       IP7_Trace        *i_iTrace,
                       CPSharedLib      *i_hDLL,
                       Bk::stPluginInfo *i_pPlugin_Info,
                       const tXCHAR     *i_pPath
                      )
    : CPlugin(i_pBaical, i_hDLL, i_pPlugin_Info, i_iTrace, i_pNode, i_pProp, i_pPath)
    , m_pProcessor(NULL)
{     
    if (m_iP7_Trace)
    {
        m_iP7_Trace->Register_Module(TM("Baical"), &m_hP7_TraceModule);
    }

    if (m_bInitialized)
    {
        fnBkCreateProcessor l_fnCreate = NULL;
        *(void **)(&l_fnCreate) = m_hDLL->GetFunction(BK_CREATE_PROCESSOR);

        if (NULL != l_fnCreate)
        {
            l_fnCreate(m_pBaical, i_pNode, m_pProp, m_pProcessor);
        }
    }

    if (!m_pProcessor)
    {
        LOG_ERROR(TM("Load plugin failed {%s}"), i_pPath);
        m_bInitialized = FALSE;
    }
}//CDispatcher


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~CDispatcher
CProcessor::~CProcessor()
{
    if (m_pProcessor)
    {
        m_pProcessor->Release();
        m_pProcessor = NULL;
    }
}//~CDispatcher


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Initialize
Bk::eResult CProcessor::Initialize()
{
    if (!m_bInitialized)
    {
        return Bk::eErrorInternal;
    }

    return m_pProcessor->Initialize();
}
