/*
 * Implementation of IEnumUnknown (for internal use).
 *
 * hidenori@a2.ctktv.ne.jp
 */

#include "config.h"

#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/obj_base.h"
#include "wine/obj_misc.h"

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

#include "quartz_private.h"
#include "enumunk.h"
#include "iunk.h"



typedef struct IEnumUnknownImpl
{
	ICOM_VFIELD(IEnumUnknown);
} IEnumUnknownImpl;

typedef struct
{
	QUARTZ_IUnkImpl	unk;
	IEnumUnknownImpl	enumunk;
	struct QUARTZ_IFEntry	IFEntries[1];
	QUARTZ_CompList*	pCompList;
	QUARTZ_CompListItem*	pItemCur;
} CEnumUnknown;

#define	CEnumUnknown_THIS(iface,member)		CEnumUnknown*	This = ((CEnumUnknown*)(((char*)iface)-offsetof(CEnumUnknown,member)))




static HRESULT WINAPI
IEnumUnknown_fnQueryInterface(IEnumUnknown* iface,REFIID riid,void** ppobj)
{
	CEnumUnknown_THIS(iface,enumunk);

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

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

static ULONG WINAPI
IEnumUnknown_fnAddRef(IEnumUnknown* iface)
{
	CEnumUnknown_THIS(iface,enumunk);

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

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

static ULONG WINAPI
IEnumUnknown_fnRelease(IEnumUnknown* iface)
{
	CEnumUnknown_THIS(iface,enumunk);

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

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

static HRESULT WINAPI
IEnumUnknown_fnNext(IEnumUnknown* iface,ULONG cReq,IUnknown** ppunk,ULONG* pcFetched)
{
	CEnumUnknown_THIS(iface,enumunk);
	HRESULT	hr;
	ULONG	cFetched;

	TRACE("(%p)->(%lu,%p,%p)\n",This,cReq,ppunk,pcFetched);

	if ( pcFetched == NULL && cReq > 1 )
		return E_INVALIDARG;
	if ( ppunk == NULL )
		return E_POINTER;

	QUARTZ_CompList_Lock( This->pCompList );

	hr = NOERROR;
	cFetched = 0;
	while ( cReq > 0 )
	{
		if ( This->pItemCur == NULL )
		{
			hr = S_FALSE;
			break;
		}
		ppunk[ cFetched ++ ] = QUARTZ_CompList_GetItemPtr( This->pItemCur );
		IUnknown_AddRef( *ppunk );

		This->pItemCur =
			QUARTZ_CompList_GetNext( This->pCompList, This->pItemCur );
		cReq --;
	}

	QUARTZ_CompList_Unlock( This->pCompList );

	if ( pcFetched != NULL )
		*pcFetched = cFetched;

	return hr;
}

static HRESULT WINAPI
IEnumUnknown_fnSkip(IEnumUnknown* iface,ULONG cSkip)
{
	CEnumUnknown_THIS(iface,enumunk);
	HRESULT	hr;

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

	QUARTZ_CompList_Lock( This->pCompList );

	hr = NOERROR;
	while ( cSkip > 0 )
	{
		if ( This->pItemCur == NULL )
		{
			hr = S_FALSE;
			break;
		}
		This->pItemCur =
			QUARTZ_CompList_GetNext( This->pCompList, This->pItemCur );
		cSkip --;
	}

	QUARTZ_CompList_Unlock( This->pCompList );

	return hr;
}

static HRESULT WINAPI
IEnumUnknown_fnReset(IEnumUnknown* iface)
{
	CEnumUnknown_THIS(iface,enumunk);

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

	QUARTZ_CompList_Lock( This->pCompList );

	This->pItemCur = QUARTZ_CompList_GetFirst( This->pCompList );

	QUARTZ_CompList_Unlock( This->pCompList );

	return NOERROR;
}

static HRESULT WINAPI
IEnumUnknown_fnClone(IEnumUnknown* iface,IEnumUnknown** ppunk)
{
	CEnumUnknown_THIS(iface,enumunk);
	HRESULT	hr;

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

	if ( ppunk == NULL )
		return E_POINTER;

	QUARTZ_CompList_Lock( This->pCompList );

	hr = QUARTZ_CreateEnumUnknown(
		This->IFEntries[0].piid,
		(void**)ppunk,
		This->pCompList );
	FIXME( "current pointer must be seeked correctly\n" );

	QUARTZ_CompList_Unlock( This->pCompList );

	return hr;
}


static ICOM_VTABLE(IEnumUnknown) ienumunk =
{
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	/* IUnknown fields */
	IEnumUnknown_fnQueryInterface,
	IEnumUnknown_fnAddRef,
	IEnumUnknown_fnRelease,
	/* IEnumUnknown fields */
	IEnumUnknown_fnNext,
	IEnumUnknown_fnSkip,
	IEnumUnknown_fnReset,
	IEnumUnknown_fnClone,
};

void QUARTZ_DestroyEnumUnknown(IUnknown* punk)
{
	CEnumUnknown_THIS(punk,unk);

	if ( This->pCompList != NULL )
		QUARTZ_CompList_Free( This->pCompList );
}

HRESULT QUARTZ_CreateEnumUnknown(
	REFIID riidEnum, void** ppobj, const QUARTZ_CompList* pCompList )
{
	CEnumUnknown*	penum;
	QUARTZ_CompList*	pCompListDup;

	TRACE("(%s,%p,%p)\n",debugstr_guid(riidEnum),ppobj,pCompList);

	pCompListDup = QUARTZ_CompList_Dup( pCompList, FALSE );
	if ( pCompListDup == NULL )
		return E_OUTOFMEMORY;

	penum = (CEnumUnknown*)QUARTZ_AllocObj( sizeof(CEnumUnknown) );
	if ( penum == NULL )
	{
		QUARTZ_CompList_Free( pCompListDup );
		return E_OUTOFMEMORY;
	}

	QUARTZ_IUnkInit( &penum->unk, NULL );
	ICOM_VTBL(&penum->enumunk) = &ienumunk;

	penum->IFEntries[0].piid = riidEnum;
	penum->IFEntries[0].ofsVTPtr =
		offsetof(CEnumUnknown,enumunk)-offsetof(CEnumUnknown,unk);
	penum->pCompList = pCompListDup;
	penum->pItemCur = QUARTZ_CompList_GetFirst( pCompListDup );

	penum->unk.pEntries = penum->IFEntries;
	penum->unk.dwEntries = 1;
	penum->unk.pOnFinalRelease = QUARTZ_DestroyEnumUnknown;

	*ppobj = (void*)(&penum->enumunk);

	return S_OK;
}

