// RnTemplateView.cpp : Implementation of CRnTemplateView

#include "stdafx.h"
#include "RsTemplateWindow.h"
#include "RnTemplateView.h"
#include "RpViewPackage.h"
#include "RsSelectionHelper.h"   //selections support


// CRnTemplateView
HRESULT CRnTemplateView::FinalConstruct()
{
	// get kernel package
	CComPtr<IRpKernel> spKernelPackage;
	HRESULT hr = CRpViewPackage::GetKernelPackage(&spKernelPackage);
	// and create base node
	if(spKernelPackage == NULL)
		return E_FAIL;
	if(FAILED(hr = spKernelPackage->CreateBaseNode(GetControllingUnknown(), &m_pUnkAgg)))
		return hr;


	// aggregate scanner
	CComPtr<IRsUnknownPackage>  spUnkPackage;
	if(FAILED(hr = spKernelPackage->FindPackage(DEF_GUIDNAME(CRpCommonData), &spUnkPackage)))
		return hr;
	CComQIPtr<IRpCommonData> spCDPck = spUnkPackage;
	if(spCDPck == NULL)
		return E_NOINTERFACE;
	if(FAILED(hr = spCDPck->CreateScanner(GetControllingUnknown(), &m_spScannerAgg)))
		return hr;

	// aggregate base control
	CComPtr<IRsUnknownPackage>  spWmUnkPackage;
	if(FAILED(hr = spKernelPackage->FindPackage(DEF_GUIDNAME(CRpWinMng), &spWmUnkPackage)))
		return hr;
	CComQIPtr<IRpWinMngPck> spWmPck = spWmUnkPackage;
	if(spWmPck == NULL)
		return E_NOINTERFACE;
	return spWmPck->CreateBaseControl(GetControllingUnknown(), &m_spBaseControlUnkAgg);
}

void CRnTemplateView::FinalRelease() 
{
	m_pUnkAgg.Release();
	m_spScannerAgg.Release();
}

// IRsUnknownNode
STDMETHODIMP CRnTemplateView::OnGetValue(CONID con_id, IRsDataCache* pDataCache, VARIANT* pVtData, RtBool* pHandled)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::OnSetValue(CONID con_id, IRsDataCache* pDataCache, VARIANT* pvtData, RtBool* pHandled)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::OnDefaultValue(CONID con_id, VARIANT* pVtData, RtBool* pHandled)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::OnInvalidate(CONID con_id, RtBool* pHandled)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::OnInitialize(void)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::OnLoadDefault(void)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::OnDestroy(void)
{
	// unhook listener
	CComQIPtr<IRsScanner>	spScanner = m_spScannerAgg;
	spScanner->ScanNode(NULL);

	// clean aggregated base control
	CComQIPtr<IRsBaseControl>	spBaseControl = m_spBaseControlUnkAgg;
	spBaseControl->DestroyControl();

	return S_OK;
}


// selection notifications
STDMETHODIMP CRnTemplateView::SelectionNotify(GUID SelectionID, 
										   RtSelectionNotificationType eType, 
										   IRsBaseSelection *pSelection)
{
	if (SelectionID == __uuidof(IRdSelNodeSelection))
	{
		RefreshView();
	}
	return S_OK;
}

STDMETHODIMP CRnTemplateView::OnNotifyEvent(IRsNotifyEvent* pEvent)
{
	HRESULT hr;

	if (m_spGenWindowControl == NULL)
		return S_OK;

	RtNotifyEvent eEvent;
	if (SUCCEEDED(hr = pEvent->Event(&eEvent)))
	{
		switch (eEvent)
		{
		case NEVNT_ADDCONNECTOR:
		case NEVNT_REMOVECONNECTOR:
		case NEVNT_RENAME:
		case NEVNT_OWNERIDCHANGED:
			RefreshView();
			break;
		}
	}
	return S_OK;
}


// IRsViewNode
STDMETHODIMP CRnTemplateView::AttachViewWindowHandle(HWND hWnd)
{
	CComPtr<IRpKernel> spKernelPackage;
	CRpViewPackage::GetKernelPackage(&spKernelPackage);

	// create generic view frame
	CComPtr<IRsUnknownPackage>  spUnkPackage;
	HRESULT hr = spKernelPackage->FindPackage(DEF_GUIDNAME(CRpWinMng), &spUnkPackage);
	if(FAILED(hr))
		return hr;
	CComQIPtr<IRpWinMngPck> spWmPck = spUnkPackage;
	if(spWmPck)
		spWmPck->CreateViewFrame(hWnd, &m_spGenWindowFrame);
	if(m_spGenWindowFrame == NULL)
	{
		ATLASSERT(!"Failed to create window Frame");
		return E_FAIL;
	}

	// create template view (window)

	CComObject<CRsTemplateWindow>* pObj;
	HRESULT hRes = CComObject<CRsTemplateWindow>::CreateInstance(&pObj);
	if (FAILED(hRes))
		return hRes;

	m_spGenWindowControl = pObj;
	if(m_spGenWindowControl == NULL)
	{
		ATLASSERT(!"Failed to create template window control");
		return E_NOINTERFACE;
	}

	// attach view to frame
	m_spGenWindowFrame->AttachView(m_spGenWindowControl);

	// initialize control
	CComQIPtr<IRsNode>			spThisNode = m_pUnkAgg;
	m_spGenWindowControl->InitializeControl(spThisNode);


	// activate scanning node and selection notification
	CComPtr<IRsNode>	spScannedNode;
	GetScannedNode(&spScannedNode);

	RsSelectionHelper::NotifyChange<CRpViewPackage>(__uuidof(IRdSelNodeSelection), this, TRUE);

	return S_OK;

}

STDMETHODIMP CRnTemplateView::Prepare(BSTR bsRootNodeName)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::PostShowUpdate(void)
{
	return RefreshView();
}

STDMETHODIMP CRnTemplateView::OnWndDestroy(void)
{
	// unhook scanner 
	CComQIPtr<IRsScanner>	spScanner = m_spScannerAgg;
	spScanner->ScanNode(NULL);

	// disable scanning of selection notifications
	RsSelectionHelper::NotifyChange<CRpViewPackage>(__uuidof(IRdSelNodeSelection), this, FALSE);

	m_spGenWindowControl.Release();
	m_spGenWindowFrame.Release();

	return S_OK;
}

STDMETHODIMP CRnTemplateView::OnSetRoot(BSTR bsRootNodeName)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::IsValidRoot(IRsNode* pRootNode)
{
	return S_OK;
}

STDMETHODIMP CRnTemplateView::get_Dimension(RtDimension* pVal)
{
	if (pVal)
	{
		*pVal = dim2D;
		return S_OK;
	}
	return E_FAIL;
}

STDMETHODIMP CRnTemplateView::get_ExitControl(RtBool* pVal)
{
	if (pVal)
	{
		*pVal = false;
		return S_OK;
	}
	return E_FAIL;
}


// IRnTemplateView

HRESULT CRnTemplateView::RefreshView(void)
{
	CComQIPtr<IRsBaseControl>	spBaseControl = m_spBaseControlUnkAgg;
	return spBaseControl->InvokeRefresh();
}

STDMETHODIMP CRnTemplateView::GetControl(IRsGenView** pControl)
{
	return m_spGenWindowControl.CopyTo(pControl);
}


STDMETHODIMP CRnTemplateView::OnUpdateControl(void)
{
	HRESULT hRes;

	if(m_spGenWindowControl == NULL)
		return S_OK;  

	// resolve a node that is displayed in the view
	CComPtr<IRsNode>	spScannedNode;
	if(FAILED(hRes = GetScannedNode(&spScannedNode)))
		return hRes;
	
	CComQIPtr<IRsViewRenderData>	spRenderData;
	
	// create and fill render data
	if(spScannedNode)
	{
		if(FAILED(hRes = CreateAndFillRenderData(spScannedNode, &spRenderData)))
			return hRes;
	}

	// pass render data to control
	return m_spGenWindowControl->Update(spRenderData);
}


HRESULT CRnTemplateView::GetScannedNode(IRsNode** ppRootNode)
{
	CComPtr<IRnKernel>	spKernelNode;
	CRpViewPackage::GetKernelNode(&spKernelNode);
	CComQIPtr<IRnEncapsulator> spKernelRoot = spKernelNode;

	// get first selected object

	CComBSTR bszNodeName;
	RsSelectionHelper::GetFirstSelectedNodeName<CRpViewPackage>(&bszNodeName);

	// check if selected node is in graph
	CComQIPtr<IRsNode> spSelNode;

	if(S_OK == spKernelRoot->FindNodeByName(bszNodeName, &spSelNode))
	{
		CComQIPtr<IRsScanner> spScanner = m_spScannerAgg;
		CComPtr<IRsNode> spScannedNode;
		spScanner->GetScannedNode(&spScannedNode);

		if (!spScannedNode.IsEqualObject(spSelNode))
			spScanner->ScanNode(spSelNode);
	}	

	if(spSelNode == NULL)
	{
		// unhook if node is not in the graph ( deleted)
		CComQIPtr<IRsScanner>	spScanner = m_spScannerAgg;
		spScanner->ScanNode(NULL);
	}

	return spSelNode.CopyTo(ppRootNode);
}


HRESULT CRnTemplateView::CreateAndFillRenderData(IRsNode* pNode, IRsViewRenderData** ppRenderData)
{
	ATLASSERT(pNode);

	CComQIPtr<IRsBaseNode>	spBaseNode = pNode;
	if(spBaseNode == NULL)
		return E_NOINTERFACE;

	HRESULT hRes;

	// create render data object 
	CComPtr<CRsTemplateRenderData>	spTemplData;
	CComObject<CRsTemplateRenderData>* pTemplDataObj;
    if(FAILED(hRes = CComObject<CRsTemplateRenderData>::CreateInstance(&pTemplDataObj)))
        return hRes;
    
	// object name, location in the graph

	CComBSTR bszNodeName;
	spBaseNode->GetFullName(NULL, &bszNodeName);
	pTemplDataObj->SetNodeName(bszNodeName);

	// get connector details ( descriptors)

    RtUlong cNumCons;
	spBaseNode->ConnectorsCount(&cNumCons);
    for (RtUlong i = 0; i < cNumCons; i++)
    {
        CComPtr<IRsConnector> spCon;
		spBaseNode->GetConnector(i, &spCon);       
        if (spCon)
		{
			// add connector descriptor 
			CComPtr<IRsConDescriptor>	spConDesc;
			if(SUCCEEDED(spCon->GetDescriptor(&spConDesc)))
				pTemplDataObj->AddConDescriptor(spConDesc);
		}
    }

	// return ptr to newly created render data
	return pTemplDataObj->QueryInterface(ppRenderData);
}