// DecalRes.cpp : Implementation of cDecalRes
#include "stdafx.h"
#include "Decal.h"
#include "DecalRes.h"

/////////////////////////////////////////////////////////////////////////////
// cDecalRes

HRESULT cDecalRes::getLibID( MSXML::IXMLDOMDocumentPtr &pdoc, GUID *pGUID )
{
   _variant_t vlib = pdoc->selectSingleNode( _T( "/*/@lib" ) )->text;
   if( vlib.vt == VT_NULL )
   {
      // lib is a required field
      _ASSERT( FALSE );
      return E_FAIL;
   }

   return ::CLSIDFromString( vlib.bstrVal, pGUID );
}

bool cDecalRes::getTypelibFilename( MSXML::IXMLDOMDocumentPtr &pdoc, BSTR *pbstrFilename )
{
   USES_CONVERSION;

   GUID libid;
   HRESULT hRes = getLibID( pdoc, &libid );

   if( FAILED( hRes ) )
      return SUCCEEDED ( hRes );

   // Look up the path of the typelib in the registry
   hRes = ::QueryPathOfRegTypeLib( libid, 1, 0, 0, pbstrFilename );

   if( SUCCEEDED( hRes ) )
      return true;

   // Otherwise, manufacture a type library filename
   RegKey key;
   key.Open( HKEY_LOCAL_MACHINE, _T( "Software\\Decal\\Agent" ) );

   TCHAR szPath[ MAX_PATH ];
   DWORD dwPath = MAX_PATH;
   key.QueryStringValue (_T("PluginPath"), szPath, &dwPath);

   if( szPath[ ::_tcslen( szPath ) - 1 ] != _T( '\\' ) )
      ::_tcscat( szPath, _T( "\\" ) );

   _variant_t vName = pdoc->selectSingleNode( _T( "/*/@name" ) )->text;

   if( vName.vt == VT_NULL )
      ::_tcscat( szPath, _T( "ErrorUnnamedTypelib.tlb" ) );
   else
   {
      ::_tcscat( szPath, OLE2T( vName.bstrVal ) );
      ::_tcscat( szPath, _T( ".tlb" ) );
   }

   *pbstrFilename = T2BSTR( szPath );

   return false;
}

HRESULT cDecalRes::initTypelib( MSXML::IXMLDOMDocumentPtr &pdoc, BSTR strFilename )
{
   HRESULT hRes = ::CreateTypeLib2( SYS_WIN32, strFilename, &m_pLib );

   if( FAILED( hRes ) )
      return hRes;

   GUID libid;
   hRes = getLibID( pdoc, &libid );
   if( FAILED( hRes ) )
      return hRes;

   m_pLib->SetGuid( libid );

   _variant_t vName = pdoc->selectSingleNode( _T( "/*/@name" ) )->text;

   if( vName.vt == VT_NULL )
   {
      // Name is a required field
      _ASSERT( FALSE );
      return E_FAIL;
   }

   m_pLib->SetName( vName.bstrVal );
   m_pLib->SetVersion( 1, 0 );

   // One initialized typelib
   return S_OK;
}

HRESULT cDecalRes::scanTemplate( MSXML::IXMLDOMElementPtr &ptemp, ITypeInfo **ppCoClass, ITypeInfo **ppSource )
{
   // Get the IDs for the coclass, default interface and default source interface
   _variant_t vIDCoClass = ptemp->getAttribute( _T( "class" ) ),
      vIDEvent = ptemp->getAttribute( _T( "event" ) ),
      vName = ptemp->getAttribute( _T( "name" ) );

   if( vIDCoClass.vt == VT_NULL || vIDEvent.vt == VT_NULL || vName.vt == VT_NULL )
   {
      // Both of these are required
      _ASSERT( FALSE );
      return E_FAIL;
   }

   // Next convert them to GUIDs
   CLSID idClass;
   IID idEvent;
   if( FAILED( ::CLSIDFromString( vIDCoClass.bstrVal, &idClass ) ) ||
      FAILED( ::CLSIDFromString( vIDEvent.bstrVal, &idEvent ) ) )
   {
      // They must be converted to guids
      _ASSERT( FALSE );
      return E_FAIL;
   }

   // Now we make the coclass typeinfo, default source typeinfo, get the default interface typeinfo
   // and slap them all together
   CComPtr< ICreateTypeInfo > pCoClass;

   m_pLib->CreateTypeInfo( vName.bstrVal, TKIND_COCLASS, &pCoClass );
   pCoClass->SetGuid( idClass );
   pCoClass->QueryInterface( ppCoClass );

   CComPtr< ITypeInfo > pDefaultItf;
   GetTypeInfo( 0, 0, &pDefaultItf );

   HREFTYPE hrefDefaultItf;
   pCoClass->AddRefTypeInfo( pDefaultItf, &hrefDefaultItf );
   pCoClass->AddImplType( 0, hrefDefaultItf );
   pCoClass->SetImplTypeFlags( 0, IMPLTYPEFLAG_FDEFAULT );

   CComPtr< ICreateTypeInfo > pSourceItf;
   
   _bstr_t strEvent( _T( "_" ) );
   strEvent += vName.bstrVal;
   strEvent += _T( "Events" );

   m_pLib->CreateTypeInfo( strEvent, TKIND_DISPATCH, &pSourceItf );
   pSourceItf->SetGuid( idEvent );

   HREFTYPE hrefSourceItf;
   pSourceItf->QueryInterface( ppSource );
   pCoClass->AddRefTypeInfo( *ppSource, &hrefSourceItf );
   pCoClass->AddImplType( 1, hrefSourceItf );
   pCoClass->SetImplTypeFlags( 1, IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE );

   // Still incomplete
   return S_OK;
}
