// Rp3DLoader.cpp : Implementation of CRp3DLoader
// CRp3DLoader represents the plugin. We implement here the
// IRsUnknownPackage interface that is asked during the plugin loading.
// The interface then enable communication with system and all other
// packages.

#include "stdafx.h"

// factories 
#include "RsCmdFactory.h"
#include "RsNodeFactory.h"
#include "RsDoFactory.h"

// CRp3DLoader
CComPtr<IRpKernel>			 CRp3DLoader::m_spKernelPackage = NULL;
CComPtr<IRsSysFactory>		 CRp3DLoader::m_spSysFactory = NULL;
CComPtr<IRsSysCore>			 CRp3DLoader::m_spSysCore = NULL;
CComPtr<IRp3DLoader>   CRp3DLoader::m_spSamplePackage = NULL;

HRESULT CRp3DLoader::GetKernelPackage(IRpKernel** ppPackage)
{
    // if you got assert here, CmdPrompt package is not initialized 
    ATLASSERT(m_spKernelPackage != NULL);
    return m_spKernelPackage.CopyTo(ppPackage);
}

// IRsUnknownPackage Methods
STDMETHODIMP CRp3DLoader::Initialize(IRsUnknownPackage *pParentPackage)
{
    ATLASSERT(pParentPackage != NULL);

    HRESULT hRes = pParentPackage->QueryInterface(DEF_GUIDNAME(IRpKernel), (void**) &m_spKernelPackage );
    if (FAILED(hRes))
        return hRes;

    if (FAILED(hRes = QueryInterface(DEF_GUIDNAME(IRp3DLoader), (void**) &m_spSamplePackage)))
        return hRes;

    // get pointers to useful system resources like resources factories or syscore
    m_spKernelPackage->GetSysFactory(&m_spSysFactory);
    if (m_spSysFactory == NULL)
        return E_FAIL;

    m_spKernelPackage->GetSysCore(&m_spSysCore);
    if (m_spSysCore == NULL)
        return E_FAIL;

    // create factories

    // command factory
    CComObject<CRsCmdFactory>* pCmdObj;
    hRes = CComObject<CRsCmdFactory>::CreateInstance(&pCmdObj);
    if (FAILED(hRes))
        return hRes;
    if (FAILED(hRes = pCmdObj->QueryInterface(&m_spCmdFactory)))
        return hRes;

    // node factory
    CComObject<CRsNodeFactory>* pNodeObj;
    hRes = CComObject<CRsNodeFactory>::CreateInstance(&pNodeObj);
    if (FAILED(hRes))
        return hRes;
    if (FAILED(hRes = pNodeObj->QueryInterface(&m_spNodeFactory)))
        return hRes;

    // data object factory
    CComObject<CRsDoFactory>* pDoObj;
    hRes = CComObject<CRsDoFactory>::CreateInstance(&pDoObj);
    if (FAILED(hRes))
        return hRes;
    if (FAILED(hRes = pDoObj->QueryInterface(&m_spDataObjFactory)))
        return hRes;

    return S_OK;
}

STDMETHODIMP CRp3DLoader::UnInitialize()
{
	m_spKernelPackage.Release();
	m_spSysFactory.Release();
	m_spSysCore.Release();
	m_spSamplePackage.Release();

    return S_OK;
}


// returns NodeFactory interface provided by package
STDMETHODIMP CRp3DLoader::GetNodeFactory(IRsNodeFactory** ppNodeFactory)
{
	return m_spNodeFactory.CopyTo(ppNodeFactory);
}

// returns Command Factory interface provided by package
STDMETHODIMP CRp3DLoader::GetCmdFactory(IRsCmdFactory** ppCmdFactory)
{
	return m_spCmdFactory.CopyTo(ppCmdFactory);
}

// returns Data object Factory interface provided by package
STDMETHODIMP CRp3DLoader::GetDataObjFactory(IRsDataObjFactory** ppDataObjFactory)
{
	return m_spDataObjFactory.CopyTo(ppDataObjFactory);
}

STDMETHODIMP CRp3DLoader::GetModuleInstance(RtInstance* pInstance)
{
	if (pInstance)
	{
		HINSTANCE hInstance = _AtlBaseModule.GetModuleInstance();
		*pInstance = (RtInstance)hInstance;
		return S_OK;
	}
	return E_INVALIDARG;
}

STDMETHODIMP CRp3DLoader::GetResourceInstance(RtInstance* pInstance)
{
	if (pInstance)
	{
		HINSTANCE hInstance = _AtlBaseModule.GetResourceInstance();
		*pInstance = (RtInstance)hInstance;
		return S_OK;
	}
	return E_INVALIDARG;
}

STDMETHODIMP CRp3DLoader::OnSysMessage(MSGID msgId, IRsUnknownMsg* pMsg)
{
	if (msgId == MSG_SYS_REGISTER) {
		// called when plugin has been loaded into rosetta
	}
	else if (msgId == MSG_SYS_UNREGISTER) {
		// Called when plugin has been unloaded from rosetta
	}
	else {
		// Handle other system messages here 
	};
    return S_OK;
}

//////////////////////////////////////////////////////////////////////////
// Some useful static methods:


HRESULT CRp3DLoader::CreateDataObj(const IID* piid, IRsDataObject** ppDataObj)
{
    HRESULT hr;

    if (ppDataObj == NULL)
        return E_INVALIDARG;

    if (m_spKernelPackage == NULL)
        return E_FAIL;

    CComPtr<IRsSysFactory>	spFactory;
    CComPtr<IRsDataObject>  spData;

    if (FAILED(hr = m_spKernelPackage->GetSysFactory(&spFactory)))
        return hr;

    if (FAILED(hr = spFactory->CreateDataObj(piid, &spData)))
        return hr;

    return spData->QueryInterface(ppDataObj);
}

HRESULT CRp3DLoader::CreateCmdObj(const IID *piid, IRsNode **ppCmd)
{
    HRESULT hr;

    if (ppCmd == NULL)
        return E_INVALIDARG;

    if (m_spKernelPackage == NULL)
        return E_FAIL;

    CComPtr<IRsSysFactory>	spFactory;
    if (FAILED(hr = m_spKernelPackage->GetSysFactory(&spFactory)))
        return hr;

    // create command object
    CComPtr<IRsCommand> spCommand;
    if (FAILED(hr = spFactory->CreateCommand(piid, &spCommand)))
        return hr;

    CComQIPtr<IRsNode> spNode = spCommand;
    if (FAILED(hr = spNode->LoadDefault()))
        return hr;

    return spNode.CopyTo(ppCmd);
}

HRESULT CRp3DLoader::CreateNode(const IID *piid, IRsNode **ppNode)
{
    HRESULT hr;

    if (ppNode == NULL)
        return E_INVALIDARG;

    CComPtr<IRsSysFactory> spFactory;
    if (FAILED(hr = m_spKernelPackage->GetSysFactory(&spFactory)))
        return hr;

    CComPtr<IRsNode> spNode;
    if (FAILED(hr = spFactory->CreateNode(piid, &spNode)))
        return hr;

    if (FAILED(hr = spNode->LoadDefault()))
        return hr;

    return spNode.CopyTo(ppNode);
}

HRESULT CRp3DLoader::ExecuteCommand(IRsNode *pCmdNode)
{
    if (pCmdNode == NULL)
        return E_FAIL;
    if (m_spSysCore == NULL) { //destroy command to prevent leaking
        pCmdNode->Destroy();
        return E_FAIL;
    };

    return m_spSysCore->ExecuteCommand(CComQIPtr<IRsCommand>(pCmdNode));
};

HRESULT CRp3DLoader::SendCommand(IRsNode *pCmdNode)
{
    if (pCmdNode == NULL)
        return E_FAIL;
    if (m_spSysCore == NULL) { //destroy command to prevent leaking
        pCmdNode->Destroy();
        return E_FAIL;
    };

    return m_spSysCore->SendCommand(pCmdNode);
};

HRESULT CRp3DLoader::Create3DLoaderFnSet(IRf3DLoader **ppFnSet)
{
    CComObjectStack<CRf3DLoader> fnRf3DLoader;
    CComObject<CRf3DLoader>* pObj = NULL;
    HRESULT hRes = CComObject<CRf3DLoader>::CreateInstance(&pObj);
    if (FAILED(hRes))
        return E_FAIL;

    return pObj->QueryInterface(ppFnSet);
}
