
#ifndef _DMusic_OggLoader_H_
#define _DMusic_OggLoader_H_

#include "STL.h"

#include <windows.h>
#include <dmusici.h>

struct SObjRef;
class COGGFile;
struct SWaveHeader;

///////////////////////////////////////////////////////////////////////////////////////
//

class COggStream : public IStream, public IDirectMusicGetLoader
{
public:
	COggStream();
	~COggStream();

	HRESULT					Attach( LPCTSTR tzFile, IDirectMusicLoader * pLoader );
	void					Detach();

	MUSIC_TIME				GetMusicTime();

	//IUnknown methods
	STDMETHODIMP			QueryInterface( REFIID iid, void ** ppv );
	STDMETHODIMP_(ULONG)	AddRef();
	STDMETHODIMP_(ULONG)	Release();

	//IDirectMusicGetLoader
	STDMETHODIMP			GetLoader( IDirectMusicLoader ** ppLoader );

	//IStream methods
	STDMETHODIMP			Read( void * pv, ULONG cb, ULONG * pcb );
	STDMETHODIMP			Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER * plibNewPosition );
	STDMETHODIMP			Clone( IStream ** ppstm );

	//구현할 필요가 없는 것들...
	STDMETHODIMP			Write( const void *, ULONG, ULONG * )									{ return E_NOTIMPL; }
	STDMETHODIMP			SetSize( ULARGE_INTEGER )												{ return E_NOTIMPL; }
	STDMETHODIMP			CopyTo( IStream *, ULARGE_INTEGER, ULARGE_INTEGER *, ULARGE_INTEGER * )	{ return E_NOTIMPL; }
	STDMETHODIMP			Commit( DWORD )															{ return E_NOTIMPL; }
	STDMETHODIMP			Revert()																{ return E_NOTIMPL; }
	STDMETHODIMP			LockRegion( ULARGE_INTEGER, ULARGE_INTEGER, DWORD )						{ return E_NOTIMPL; }
	STDMETHODIMP			UnlockRegion( ULARGE_INTEGER, ULARGE_INTEGER, DWORD )					{ return E_NOTIMPL; }
	STDMETHODIMP			Stat( STATSTG *, DWORD )												{ return E_NOTIMPL; }

private:
	LONG					m_cRef;				//COM Reference Count
	IDirectMusicLoader *	m_pLoader;			//Owning loader object
	COGGFile *				m_pOggFile;

	SWaveHeader *			m_pWaveHeader;
	DWORD					m_TotalWaveBytes;
	long					m_SeekPos;			//OGG 데이터 앞에 헤더를 붙여서 관리해야 하므로 Seek포인터를 따로 만듬.
	
};

///////////////////////////////////////////////////////////////////////////////////////
//

class CDMusic_OggLoader : public IDirectMusicLoader8
{
public:
	CDMusic_OggLoader();
	~CDMusic_OggLoader();

	HRESULT					Init();
	void					UnInit();

	//IUnknown methods
	STDMETHODIMP			QueryInterface( REFIID iid, void ** ppv );
	STDMETHODIMP_(ULONG)	AddRef();
	STDMETHODIMP_(ULONG)	Release();

	//IDirectMusicLoader methods
	STDMETHODIMP			GetObject( LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID FAR * ppv );
	STDMETHODIMP			SetSearchDirectory( REFGUID rguidClass, WCHAR * pwzPath, BOOL fClear );
	STDMETHODIMP_(void)		CollectGarbage();
	STDMETHODIMP			ReleaseObjectByUnknown( IUnknown * pObject );
	STDMETHODIMP			LoadObjectFromFile( REFGUID, REFIID, WCHAR *, void ** );

	//구현할 필요가 없는 것들...
	STDMETHODIMP			SetObject( LPDMUS_OBJECTDESC )							{ return E_NOTIMPL; }
	STDMETHODIMP			ScanDirectory( REFGUID, WCHAR *, WCHAR * )				{ return E_NOTIMPL; }
	STDMETHODIMP			CacheObject( IDirectMusicObject * )						{ return E_NOTIMPL; }
	STDMETHODIMP			ReleaseObject( IDirectMusicObject * )					{ return E_NOTIMPL; }
	STDMETHODIMP			ClearCache( REFGUID )									{ return E_NOTIMPL; }
	STDMETHODIMP			EnableCache( REFGUID, BOOL )							{ return E_NOTIMPL; }
	STDMETHODIMP			EnumObject( REFGUID, DWORD, LPDMUS_OBJECTDESC )			{ return E_NOTIMPL; }

private:
	typedef list<SObjRef>	LIST_OBJREF;

	LONG					m_cRef;				//COM Reference count
	std::wstring	*		m_pstrSearchPath;
	LIST_OBJREF *			m_pObjList;			//List of already loaded objects (the cache.)

protected:
	SObjRef *				FindCacheObject( LPDMUS_OBJECTDESC pDesc );
	STDMETHODIMP			CreateFromFile( IDirectMusicObject * pObject, WCHAR * wszFileName, MUSIC_TIME * pMusicTime );
	STDMETHODIMP			CreateFromStream( IDirectMusicObject * pObject, IStream * pStream );
	STDMETHODIMP			AddToList( IDirectMusicObject * pObject, LPDMUS_OBJECTDESC pDesc );
};

///////////////////////////////////////////////////////////////////////////////////////

#endif