/*
 * Implementation of CLSID_SystemDeviceEnum.
 *
 * FIXME - not tested enough.
 *
 * hidenori@a2.ctktv.ne.jp
 */

#include "config.h"

#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winreg.h"
#include "winerror.h"
#include "strmif.h"

#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(quartz);

#include "quartz_private.h"
#include "devenum.h"
#include "regsvr.h"
#include "enumunk.h"
#include "complist.h"
#include "devmon.h"


/***************************************************************************
 *
 *	new/delete for CLSID_SystemDeviceEnum
 *
 */

/* can I use offsetof safely? - FIXME? */
static QUARTZ_IFEntry IFEntries[] =
{
  { &IID_ICreateDevEnum, offsetof(CSysDevEnum,createdevenum)-offsetof(CSysDevEnum,unk) },
};


static void QUARTZ_DestroySystemDeviceEnum(IUnknown* punk)
{
	CSysDevEnum_THIS(punk,unk);

	CSysDevEnum_UninitICreateDevEnum( This );
}

HRESULT QUARTZ_CreateSystemDeviceEnum(IUnknown* punkOuter,void** ppobj)
{
	CSysDevEnum*	psde;
	HRESULT	hr;

	TRACE("(%p,%p)\n",punkOuter,ppobj);

	psde = (CSysDevEnum*)QUARTZ_AllocObj( sizeof(CSysDevEnum) );
	if ( psde == NULL )
		return E_OUTOFMEMORY;

	QUARTZ_IUnkInit( &psde->unk, punkOuter );

	hr = CSysDevEnum_InitICreateDevEnum( psde );
	if ( FAILED(hr) )
	{
		QUARTZ_FreeObj( psde );
		return hr;
	}

	psde->unk.pEntries = IFEntries;
	psde->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
	psde->unk.pOnFinalRelease = QUARTZ_DestroySystemDeviceEnum;

	*ppobj = (void*)(&psde->unk);

	return S_OK;
}


/***************************************************************************
 *
 *	CSysDevEnum::ICreateDevEnum
 *
 */


static HRESULT WINAPI
ICreateDevEnum_fnQueryInterface(ICreateDevEnum* iface,REFIID riid,void** ppobj)
{
	CSysDevEnum_THIS(iface,createdevenum);

	TRACE("(%p)->()\n",This);

	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
}

static ULONG WINAPI
ICreateDevEnum_fnAddRef(ICreateDevEnum* iface)
{
	CSysDevEnum_THIS(iface,createdevenum);

	TRACE("(%p)->()\n",This);

	return IUnknown_AddRef(This->unk.punkControl);
}

static ULONG WINAPI
ICreateDevEnum_fnRelease(ICreateDevEnum* iface)
{
	CSysDevEnum_THIS(iface,createdevenum);

	TRACE("(%p)->()\n",This);

	return IUnknown_Release(This->unk.punkControl);
}

static HRESULT WINAPI
ICreateDevEnum_fnCreateClassEnumerator(ICreateDevEnum* iface,REFCLSID rclsidDeviceClass,IEnumMoniker** ppobj, DWORD dwFlags)
{
	CSysDevEnum_THIS(iface,createdevenum);
	HRESULT	hr;
	HKEY	hKey;
	QUARTZ_CompList*	pMonList;
	IMoniker*	pMon;
	DWORD	dwIndex;
	LONG	lr;
	WCHAR	wszPath[ 1024 ];
	DWORD	dwLen;
	DWORD	dwNameMax;
	DWORD	cbName;
	FILETIME	ftLastWrite;

	TRACE("(%p)->(%s,%p,%08lx)\n",This,
		debugstr_guid(rclsidDeviceClass),ppobj,dwFlags);
	if ( dwFlags != 0 )
	{
		FIXME("unknown flags %08lx\n",dwFlags);
		return E_NOTIMPL;
	}

	if ( ppobj == NULL )
		return E_POINTER;
	*ppobj = NULL;

	hr = QUARTZ_CreateCLSIDPath(
		wszPath, sizeof(wszPath)/sizeof(wszPath[0]),
		rclsidDeviceClass, QUARTZ_wszInstance );
	if ( FAILED(hr) )
		return hr;

	if ( RegOpenKeyExW( HKEY_CLASSES_ROOT, wszPath,
		0, KEY_READ, &hKey ) != ERROR_SUCCESS )
		return E_FAIL;

	dwLen = lstrlenW(wszPath);
	wszPath[dwLen++] = '\\'; wszPath[dwLen] = 0;
	dwNameMax = sizeof(wszPath)/sizeof(wszPath[0]) - dwLen - 8;

	pMonList = QUARTZ_CompList_Alloc();
	if ( pMonList == NULL )
	{
		hr = E_OUTOFMEMORY;
		goto err;
	}

	/* enumerate all subkeys. */
	dwIndex = 0;
	while ( 1 )
	{
		cbName = dwNameMax;
		lr = RegEnumKeyExW(
			hKey, dwIndex, &wszPath[dwLen], &cbName,
			NULL, NULL, NULL, &ftLastWrite );
		if ( lr == ERROR_NO_MORE_ITEMS )
			break;
		if ( lr != ERROR_SUCCESS )
		{
			hr = E_FAIL;
			goto err;
		}

		hr = QUARTZ_CreateDeviceMoniker(
			HKEY_CLASSES_ROOT, wszPath, &pMon );
		if ( FAILED(hr) )
			goto err;

		hr = QUARTZ_CompList_AddComp(
			pMonList, (IUnknown*)pMon, NULL, 0 );
		IMoniker_Release( pMon );

		if ( FAILED(hr) )
			goto err;

		dwIndex ++;
	}

	/* create an enumerator. */
	hr = QUARTZ_CreateEnumUnknown(
		&IID_IEnumMoniker, (void**)ppobj, pMonList );
	if ( FAILED(hr) )
		goto err;

	hr = S_OK;
err:
	if ( pMonList != NULL )
		QUARTZ_CompList_Free( pMonList );
	RegCloseKey( hKey );

	return hr;
}

static ICOM_VTABLE(ICreateDevEnum) icreatedevenum =
{
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	/* IUnknown fields */
	ICreateDevEnum_fnQueryInterface,
	ICreateDevEnum_fnAddRef,
	ICreateDevEnum_fnRelease,
	/* ICreateDevEnum fields */
	ICreateDevEnum_fnCreateClassEnumerator,
};

HRESULT CSysDevEnum_InitICreateDevEnum( CSysDevEnum* psde )
{
	TRACE("(%p)\n",psde);
	ICOM_VTBL(&psde->createdevenum) = &icreatedevenum;

	return NOERROR;
}

void CSysDevEnum_UninitICreateDevEnum( CSysDevEnum* psde )
{
	TRACE("(%p)\n",psde);
}
