/**
 * OpenAL cross platform audio library
 * Copyright (C) 1999-2000 by authors.
 * This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA  02111-1307, USA.
 * Or go to http://www.gnu.org/copyleft/lgpl.html
 */

#include "include\alMain.h"
#include "al\alc.h"
#include "include\alError.h"
#include "include\alEax.h"
#include "include\alListener.h"
#include "include\eax.h"
#include <objbase.h>

EXTERN_C const GUID DSPROPSETID_EAX20_ListenerProperties = 
	{ 0x306a6a8, 0xb224, 0x11d2, { 0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22 } };

EXTERN_C const GUID DSPROPSETID_EAX20_BufferProperties =
	{ 0x306a6a7, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22 } };

/*
	Test for support of appropriate EAX Version
*/
ALboolean CheckEAXSupport(ALubyte *szEAXName)
{
	ALCcontext		*ALContext;
	ALsource		*ALSource;
	LPKSPROPERTYSET	lpPropertySet;
	GUID			ListenerGuid, BufferGuid;
	ALuint			ListenerProperty, BufferProperty;
	ALuint			i, ulSupport;
	ALuint			property, size;
	ALint			value;
	ALboolean		bSourceGenerated = AL_FALSE;
	ALboolean		bEAXSupported = AL_FALSE;
	ALContext=alcGetCurrentContext();
	alcSuspendContext(ALContext);

	// To test for EAX support we will need a valid Source

	ALSource = ALContext->Source;
	lpPropertySet = NULL;

	// See if one has already been created
	for (i=0;i<ALContext->SourceCount;i++)
	{
		if (alIsSource((ALuint)ALSource))
		{
			if (ALSource->uservalue3)
			{
				lpPropertySet = ALSource->uservalue3;
				break;
			}
		}
		ALSource = ALSource->next;
	}

	// If we didn't find a valid source, create one now
	if (lpPropertySet == NULL)
	{
		alGenSources(1, &((ALuint)(ALSource)));

		if (alGetError() == AL_NO_ERROR)
		{
			bSourceGenerated = AL_TRUE;
			if (ALSource->uservalue3)
			{
				lpPropertySet = ALSource->uservalue3;
			}
		}
	}

	// If Property Set Interface hasn't been obtained, EAX support is not available
	if (lpPropertySet == NULL)
	{
		if (bSourceGenerated)
			alDeleteSources(1, &(ALuint)ALSource);

		alcProcessContext(ALContext);
		return AL_FALSE;
	}

	if ( (strcmp(szEAXName, "EAX") == 0) || (strcmp(szEAXName, "EAX2.0") == 0) )
	{
		ListenerGuid = DSPROPSETID_EAX20_ListenerProperties;
		BufferGuid = DSPROPSETID_EAX20_BufferProperties;
		ListenerProperty = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
		BufferProperty = DSPROPERTY_EAXBUFFER_ALLPARAMETERS;
		property = DSPROPERTY_EAXLISTENER_ROOM;
		size = sizeof(ALint);
		value = -10000;
	}
	else
	{
		// Unknown EAX Name
		if (bSourceGenerated)
			alDeleteSources(1, &((ALuint)ALSource));

		alcProcessContext(ALContext);
		return AL_FALSE;
	}

	if (SUCCEEDED(IKsPropertySet_QuerySupport(lpPropertySet, &ListenerGuid, ListenerProperty, &ulSupport)))
	{
		if ( (ulSupport & KSPROPERTY_SUPPORT_GET) && (ulSupport & KSPROPERTY_SUPPORT_SET))
		{
			if (SUCCEEDED(IKsPropertySet_QuerySupport(lpPropertySet, &BufferGuid, BufferProperty, &ulSupport)))
			{
				if ( (ulSupport & KSPROPERTY_SUPPORT_GET) && (ulSupport & KSPROPERTY_SUPPORT_SET) )
				{
					// Fully supported !
					bEAXSupported = AL_TRUE;
		
					// Set Default Property
					IKsPropertySet_Set(lpPropertySet, &ListenerGuid, property, NULL, 0, &value, 4);
				}
			}
		}
	}

	if (bSourceGenerated)
		alDeleteSources(1, &((ALuint)ALSource));

	alcProcessContext(ALContext);
	return bEAXSupported;
}


ALAPI ALenum ALAPIENTRY EAXGet(const GUID *propertySetID,ALuint property,ALuint source,ALvoid *value,ALuint size)
{
	ALuint i;
	ALsource *ALSource;
	ALCcontext *ALContext;
	ALenum ALErrorCode;
	ALuint ulBytes;

	ALErrorCode = AL_NO_ERROR;

	ALContext = alcGetCurrentContext();

	if (IsEqualGUID(propertySetID, &DSPROPSETID_EAX20_BufferProperties))
	{
		if (alIsSource(source))
		{
			ALSource = (ALsource*)source;
			if (ALSource->uservalue3)
				IKsPropertySet_Get((LPKSPROPERTYSET)ALSource->uservalue3, propertySetID, property, NULL, 0,
					value, size, &ulBytes);
			else
				ALErrorCode = AL_INVALID_OPERATION;
		}
		else
			ALErrorCode = AL_INVALID_NAME;
	}
	else if (IsEqualGUID(propertySetID, &DSPROPSETID_EAX20_ListenerProperties))
	{
		// If source is valid use that, otherwise find a source
		if ( alIsSource(source) && ((ALsource*)(source))->uservalue3 )
		{
			ALSource = (ALsource*)source;
		}
		else
		{
			ALSource = ALContext->Source;
			
			// See if one has already been created
			for (i=0;i<ALContext->SourceCount;i++)
			{
				if (alIsSource((ALuint)ALSource))
				{
					if (ALSource->uservalue3)
						break;
				}
				ALSource = ALSource->next;
			}
		}

		if (ALSource->uservalue3)
		{
			// Get Property
			IKsPropertySet_Get((LPKSPROPERTYSET)ALSource->uservalue3, propertySetID, property, NULL, 0,
					value, size, &ulBytes);
		}
		else
			ALErrorCode = AL_INVALID_OPERATION;
	}

	return ALErrorCode;
}

ALAPI ALenum ALAPIENTRY EAXSet(const GUID *propertySetID,ALuint property,ALuint source,ALvoid *value,ALuint size)
{
	ALsource	*ALSource;
	ALCcontext	*ALContext;
	ALuint		i;
	ALenum		ALErrorCode;
	ALboolean	bGenSource;
	
	ALErrorCode = AL_NO_ERROR;
	bGenSource = AL_FALSE;

	ALContext=alcGetCurrentContext();
	alcSuspendContext(ALContext);

	if (IsEqualGUID(propertySetID, &DSPROPSETID_EAX20_BufferProperties))
	{
		if (alIsSource(source))
		{
			ALSource = (ALsource*)source;
			if (ALSource->uservalue3)
			{
				// Set Property
				IKsPropertySet_Set((LPKSPROPERTYSET)ALSource->uservalue3, propertySetID, property, NULL, 0, value, size);
			}
			else
			{
				// Trying to set an EAX Effect on a 2D buffer, or a software 3D buffer
				ALErrorCode = AL_INVALID_OPERATION;
			}
		}
		else
			ALErrorCode = AL_INVALID_NAME;
	}
	else if (IsEqualGUID(propertySetID, &DSPROPSETID_EAX20_ListenerProperties))
	{
		// If source is valid use that, otherwise find a source
		if (alIsSource(source) && ((ALsource*)(source))->uservalue3)
		{
			ALSource = (ALsource*)source;
		}
		else
		{
			ALSource = ALContext->Source;

			// See if one has already been created
			for (i=0;i<ALContext->SourceCount;i++)
			{
				if (alIsSource((ALuint)ALSource))
				{
					if (ALSource->uservalue3)
						break;
				}
				ALSource = ALSource->next;
			}

			// If an appropriate source wasn't created, generate one now
			if (ALSource == NULL)
			{
				alGenSources(1, &(ALuint)ALSource);
				if (alGetError() == AL_NO_ERROR)
					bGenSource = AL_TRUE;
			}
		}

		if (alIsSource((ALuint)ALSource) && ALSource->uservalue3)
			IKsPropertySet_Set((LPKSPROPERTYSET)ALSource->uservalue3, propertySetID, property, NULL, 0, value, size);
		else
			ALErrorCode = AL_INVALID_OPERATION;
	}

	// If we generated a source to set the EAX Listener property, release it now
	if (bGenSource)
		alDeleteSources(1, &(ALuint)ALSource);
	
	alcProcessContext(ALContext);
	return ALErrorCode;
}

