// DatLibrary.cpp : Implementation of cDatLibrary
#include "stdafx.h"
#include "DecalDat.h"
#include "DatLibrary.h"

#include "DatFile.h"
#include "DatService.h"
#include "DatStream.h"

/////////////////////////////////////////////////////////////////////////////
// cDatLibrary

void cDatLibrary::load( cDatService *pService, BSTR strFilename, int nFileType, long nSectorSize )
{
   USES_CONVERSION;
   
   // Convert the template path into a real path
   m_pService = pService;
   CComBSTR strPath;
   pService->m_pDecal->MapPath( strFilename, &strPath );
   m_nFileType = nFileType;

   try
   {
      m_pFile = new cDatFile( OLE2T( strPath ), nSectorSize );
   }
   catch( ... )
   {
   }
}

HRESULT cDatLibrary::createFile( DWORD dwFile, REFIID iid, void **ppvItf )
{
   CComObject< cDatStream > *pStream;
   CComObject< cDatStream >::CreateInstance( &pStream );
   CComPtr< IUnknown > pUnkStream = pStream;

   try
   {
      pStream->m_pFile = new cDatFile::cFile( m_pFile->getFile( dwFile ) );
   }
   catch( ... )
   {
      delete pStream;

      // File not found
      return E_INVALIDARG;
   }

   return pStream->QueryInterface( iid, ppvItf );
}

STDMETHODIMP cDatLibrary::Lookup( BSTR strName, IUnknown **ppItf )
{
   USES_CONVERSION;
   LPTSTR szName = OLE2T( strName );

   int nProtocol = ::_tcscspn( szName, _T( ":" ) );
   if( szName[ nProtocol ] == _T( '\0' ) )
   {
      // Special case, no protocol creates a raw stream
      DWORD dwFile;
      if( ::_stscanf( szName, _T( "%X" ), &dwFile ) != 1 )
         return E_INVALIDARG;

      return get_Stream( dwFile, ppItf );
   }

   // We have a protocol name
   szName[ nProtocol ] = _T( '\0' );

   // Convert the hew file number
   DWORD dwFile;
   if( ::_stscanf( szName + nProtocol + 1, _T( "%X" ), &dwFile ) != 1 )
   {
      _ASSERT( FALSE );
      return E_INVALIDARG;
   }
   
   return Open( CComBSTR( szName ), dwFile, ppItf );
}

STDMETHODIMP cDatLibrary::get_Stream(DWORD dwFile, LPUNKNOWN *pVal)
{
   return createFile( dwFile, IID_IUnknown, reinterpret_cast< void ** >( pVal ) );
}

STDMETHODIMP cDatLibrary::Open(BSTR Protocol, DWORD File, LPUNKNOWN *pFile)
{
   USES_CONVERSION;
   LPTSTR szName = OLE2T( Protocol );

   ::_tcslwr( szName );

   cDatService::cFileFilter *pFilter = m_pService->getFilter( szName, ::_tcslen( szName ) );
   if( pFilter == NULL )
   {
      _ASSERT( FALSE );
      return E_INVALIDARG;
   }

   if( pFilter->m_bCache )
   {
      // Check the file cache for an existing verison
      for( cDatService::cFileCacheList::iterator i = m_pService->m_cache.begin(); i != m_pService->m_cache.end(); ++ i )
      {
         if( i->m_dwFile == File &&
            static_cast< int >( i->m_library ) == m_nFileType &&
            i->m_pFilter == pFilter )
         {
            // Found our file, return victorious
            return i->m_pFile->QueryInterface( pFile );
         }
      }
   }

   // No cache or not found in the cache, create the stream
   CComPtr< IDatStream > pStream;
   HRESULT hRes = createFile( File, IID_IDatStream, reinterpret_cast< void ** >( &pStream ) );
   if( FAILED( hRes ) )
   {
      _ASSERT( FALSE );
      return hRes;
   }

   // Lookin' good, create the filter
   CComPtr< IFileFilter > pFileFilter;
   hRes = m_pService->createFilter( pFilter, IID_IFileFilter, reinterpret_cast< void ** >( &pFileFilter ) );

   if( FAILED( hRes ) )
   {
      _ASSERT( FALSE );
      return hRes;
   }

   hRes = pFileFilter->Initialize( pStream );

   if( FAILED( hRes ) )
   {
      _ASSERT( FALSE );
      return hRes;
   }

   if( pFilter->m_bCache )
   {
      // Make a cache entry
      cDatService::cFileCache fc;

      fc.m_dwFile = File;
      fc.m_library = static_cast< cDatService::eLibrary >( m_nFileType );
      fc.m_pFilter = pFilter;
      fc.m_pFile = pFileFilter;

      m_pService->m_cache.push_back( fc );
   }

   return pFileFilter->QueryInterface( IID_IUnknown, reinterpret_cast< void ** >( pFile ) );
}
