/*		DirectMusic
 *
 * Copyright 2002 TransGaming Technologies Inc. 
 *
 */

#include "config.h"
#include <assert.h>
#include <string.h>

#include "wine/debug.h"
#include "winbase.h"
#include "winerror.h"
#include "windef.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "mmsystem.h"
#include "ole2.h"
#include "strmif.h"
#include "control.h"
#include "uuids.h"
#include "errors.h"
#include "dsound.h"
#include "dmusicc.h"

WINE_DEFAULT_DEBUG_CHANNEL(dmusic);

/*****************************************************************************
 * IDirectMusic implementation structure
 */
typedef struct IDirectMusicImpl IDirectMusicImpl;
struct IDirectMusicImpl
{
    /* IUnknown fields */
    ICOM_VFIELD(IDirectMusic);
    DWORD                      ref;
};

IDirectMusicImpl*	dmusic = NULL;

static HRESULT WINAPI IDirectMusicImpl_QueryInterface(
	LPDIRECTMUSIC iface,REFIID riid,LPVOID *ppobj
) {
	ICOM_THIS(IDirectMusicImpl,iface);

	FIXME("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
	return E_NOINTERFACE;
}

static ULONG WINAPI IDirectMusicImpl_AddRef(LPDIRECTMUSIC iface) {
	ICOM_THIS(IDirectMusicImpl,iface);
	return ++(This->ref);
}

static ULONG WINAPI IDirectMusicImpl_Release(LPDIRECTMUSIC iface) {
	ICOM_THIS(IDirectMusicImpl,iface);
	TRACE("(%p), ref was %ld\n",This,This->ref);
	if (!--(This->ref)) {
		HeapFree(GetProcessHeap(),0,This);
		dmusic = NULL;
		return 0;
	}
	return This->ref;
}

static ICOM_VTABLE(IDirectMusic) dmvt = 
{
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	IDirectMusicImpl_QueryInterface,
	IDirectMusicImpl_AddRef,
	IDirectMusicImpl_Release,
	(void*)0xdeaf1005, /* EnumPort */
	(void*)0xdeaf1006, /* CreateMusicBuffer */
	(void*)0xdeaf1007, /* CreatePort */
	(void*)0xdeaf1008, /* EnumMasterClock */
	(void*)0xdeaf1009, /* GetMasterClock */
	(void*)0xdeaf100a, /* SetMasterClock */
	(void*)0xdeaf100b, /* Activate */
	(void*)0xdeaf100c, /* GetDefaultPort */
	(void*)0xdeaf100d  /* SetDirectSound */
};



/***********************************************************************
 *		DirectMusicCreate 
 */
static HRESULT DirectMusicCreate(REFGUID lpGUID, LPDIRECTMUSIC *ppDM,IUnknown *pUnkOuter )
{
	IDirectMusicImpl** ippDM=(IDirectMusicImpl**)ppDM;

	if (lpGUID)
		TRACE("(%p,%p,%p)\n",lpGUID,ippDM,pUnkOuter);
	else
		TRACE("DirectMusicCreate (%p)\n", ippDM);

	if (ippDM == NULL)
		return E_INVALIDARG;

	if (dmusic) {
		IDirectMusic_AddRef((LPDIRECTMUSIC)dmusic);
		*ippDM = dmusic;
		return DS_OK;
	}

	/* Allocate memory */
	*ippDM = (IDirectMusicImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectMusicImpl));
	if (*ippDM == NULL)
		return E_OUTOFMEMORY;

	ICOM_VTBL(*ippDM)	= &dmvt;
	(*ippDM)->ref		= 1;

	if (!dmusic) {
		dmusic = (*ippDM);
	}
	return DS_OK;
}


/***********************************************************************
 *		DllCanUnloadNow (DMUSIC.@)
 */
HRESULT WINAPI DMUSIC_DllCanUnloadNow(void)
{
    FIXME("(void): stub\n");

    return S_FALSE;
}


/*******************************************************************************
 * DirectMusic ClassFactory
 */
typedef struct
{
    /* IUnknown fields */
    ICOM_VFIELD(IClassFactory);
    DWORD                       ref;
} IClassFactoryImpl;

static HRESULT WINAPI 
DMCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
	ICOM_THIS(IClassFactoryImpl,iface);

	FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
	return E_NOINTERFACE;
}

static ULONG WINAPI
DMCF_AddRef(LPCLASSFACTORY iface) {
	ICOM_THIS(IClassFactoryImpl,iface);
	return ++(This->ref);
}

static ULONG WINAPI DMCF_Release(LPCLASSFACTORY iface) {
	ICOM_THIS(IClassFactoryImpl,iface);
	/* static class, won't be  freed */
	return --(This->ref);
}

static HRESULT WINAPI DMCF_CreateInstance(
	LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
) {
	ICOM_THIS(IClassFactoryImpl,iface);

	TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
	if ( IsEqualGUID( &IID_IDirectMusic, riid ) )	     {
		/* FIXME: reuse already created dmusic if present? */
		return DirectMusicCreate(riid,(LPDIRECTMUSIC*)ppobj,pOuter);
	}
	return E_NOINTERFACE;
}

static HRESULT WINAPI DMCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
	ICOM_THIS(IClassFactoryImpl,iface);
	FIXME("(%p)->(%d),stub!\n",This,dolock);
	return S_OK;
}

static ICOM_VTABLE(IClassFactory) DMCF_Vtbl = {
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	DMCF_QueryInterface,
	DMCF_AddRef,
	DMCF_Release,
	DMCF_CreateInstance,
	DMCF_LockServer
};
static IClassFactoryImpl DMUSIC_CF = {&DMCF_Vtbl, 1 };

/*******************************************************************************
 * DllGetClassObject [DMUSIC.@]
 * Retrieves class object from a DLL object
 *
 * NOTES
 *    Docs say returns STDAPI
 *
 * PARAMS
 *    rclsid [I] CLSID for the class object
 *    riid   [I] Reference to identifier of interface for class object
 *    ppv    [O] Address of variable to receive interface pointer for riid
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
 *             E_UNEXPECTED
 */
DWORD WINAPI DMUSIC_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
{
    TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
    if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
    	*ppv = (LPVOID)&DMUSIC_CF;
        IClassFactory_AddRef((IClassFactory*)*ppv);
        return S_OK;
    }

    FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
    return CLASS_E_CLASSNOTAVAILABLE;
}



/***********************************************************************
 *		DllRegisterServer (DMUSIC.@)
 */
HRESULT WINAPI DMUSIC_DllRegisterServer(void)
{
    FIXME("(void): stub\n");

    return S_OK;
}

/***********************************************************************
 *		DllUnregisterServer (DMUSIC.@)
 */
HRESULT WINAPI DMUSIC_DllUnregisterServer(void)
{
    FIXME("(void): stub\n");

    return S_OK;
}
