/*
 * Copyright (c) 2009, The MilkyTracker Team.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - Neither the name of the <ORGANIZATION> nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "AudioDriverManager.h"
#include "AudioDriverBase.h"
#include "MilkyPlayCommon.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define ALLOC_DRIVERLIST(NUMDRIVERS) \
	enumerationIndex = -1; \
	numDrivers = (NUMDRIVERS); \
	driverList = new AudioDriverInterface*[numDrivers]; \
	memset(driverList, 0, numDrivers*sizeof(AudioDriverInterface*));

#define CLEANUP_DRIVERLIST \
	for (mp_sint32 i = 0; i < numDrivers; i++) \
		delete driverList[i]; \
	delete[] driverList;

#if defined(DRIVER_WIN32)
//////////////////////////////////////////////////////////////////
//					 Windows implementation
//////////////////////////////////////////////////////////////////
#include "AudioDriver_MMSYSTEM.h"

#if !defined(_WIN32_WCE) && !defined(__SKIPRTAUDIO__)
#include "AudioDriver_RTAUDIO.h"
#endif
#if !defined(_WIN32_WCE) && defined(__WASAPI__)
#include "AudioDriver_PORTAUDIO.h"
#endif

AudioDriverManager::AudioDriverManager() :
	defaultDriverIndex(0)
{
	mp_sint32 driverListSize = 2;
#if !defined(_WIN32_WCE) && !defined(__SKIPRTAUDIO__)
	driverListSize+=3;
#endif
#if !defined(_WIN32_WCE) && defined(__WASAPI__)
	driverListSize++;
#endif

	mp_sint32 i = 0;
	ALLOC_DRIVERLIST(driverListSize);
	driverList[i++] = new AudioDriver_MMSYSTEM();
	driverList[i++] = new AudioDriver_MMSYSTEM(true);
#if !defined(_WIN32_WCE) && !defined(__SKIPRTAUDIO__)
	driverList[i++] = new AudioDriver_RTAUDIO();
	driverList[i++] = new AudioDriver_RTAUDIO(AudioDriver_RTAUDIO::WINDOWS_ASIO);
	driverList[i++] = new AudioDriver_RTAUDIO(AudioDriver_RTAUDIO::WINDOWS_DS);

	// On windows vista we set the DS driver to the default
#ifndef _WIN32_WCE
	OSVERSIONINFOEX osVersion;
	ZeroMemory(&osVersion, sizeof(osVersion));
	osVersion.dwOSVersionInfoSize = sizeof(osVersion);
	if (GetVersionEx((LPOSVERSIONINFO)&osVersion))
	{
		if (osVersion.dwMajorVersion > 5)
			defaultDriverIndex = i-1;
	}
#endif	
	
#endif
#if !defined(_WIN32_WCE) && defined(__WASAPI__)
	driverList[i++] = new AudioDriver_PORTAUDIO();
#endif
}

#elif defined(DRIVER_OSX)
//////////////////////////////////////////////////////////////////
//					 Mac OS X implementation
//////////////////////////////////////////////////////////////////
#include "AudioDriver_COREAUDIO.h"

#ifdef __MACOSX_CORE__
#include "AudioDriver_RTAUDIO.h"
#endif

AudioDriverManager::AudioDriverManager() :
	defaultDriverIndex(0)
{
#ifdef __MACOSX_CORE__
	ALLOC_DRIVERLIST(3);

	driverList[0] = new AudioDriver_COREAUDIO();
	driverList[1] = new AudioDriver_RTAUDIO();
	driverList[2] = new AudioDriver_RTAUDIO(AudioDriver_RTAUDIO::MACOSX_CORE);
#else
	ALLOC_DRIVERLIST(1);
	driverList[0] = new AudioDriver_COREAUDIO();
#endif
}

#elif defined(DRIVER_UNIX)
//////////////////////////////////////////////////////////////////
//					  UNIX implementation
//////////////////////////////////////////////////////////////////
#include "AudioDriver_SDL.h"
// #include "AudioDriver_RTAUDIO.h"
#ifdef HAVE_LIBASOUND
#include "drivers/alsa/AudioDriver_ALSA.h"
#endif
#ifdef HAVE_JACK_JACK_H
#include "AudioDriver_JACK.h"
#endif

AudioDriverManager::AudioDriverManager() :
	defaultDriverIndex(0)
{
	int count = 1;
#ifdef HAVE_LIBASOUND
	count++;
#endif
#ifdef HAVE_JACK_JACK_H
	count++;
#endif
	ALLOC_DRIVERLIST(count);
	count = 0;
	driverList[count++] = new AudioDriver_SDL();
#ifdef HAVE_LIBASOUND
	driverList[count++] = new AudioDriver_ALSA();
#endif
#if HAVE_JACK_JACK_H
	driverList[count++] = new AudioDriver_JACK();
#endif
}

#elif defined(DRIVER_SDL)
//////////////////////////////////////////////////////////////////
//					 	SDL implementation
//////////////////////////////////////////////////////////////////
#include "AudioDriver_SDL.h"

AudioDriverManager::AudioDriverManager() :
	defaultDriverIndex(0)
{
	ALLOC_DRIVERLIST(1);
	driverList[0] = new AudioDriver_SDL();
}

#elif defined(DRIVER_PSP)
//////////////////////////////////////////////////////////////////
//					 	PSP implementation
//////////////////////////////////////////////////////////////////
#include "AudioDriver_PSP.h"

AudioDriverManager::AudioDriverManager() :
	defaultDriverIndex(0)
{
	ALLOC_DRIVERLIST(1);
	driverList[0] = new AudioDriver_PSP();
}

#elif defined(DRIVER_HAIKU)
//////////////////////////////////////////////////////////////////
//					   Haiku implementation
//////////////////////////////////////////////////////////////////
#include "AudioDriver_Haiku.h"

AudioDriverManager::AudioDriverManager() :
	defaultDriverIndex(0)
{
	ALLOC_DRIVERLIST(1);
	driverList[0] = new AudioDriver_Haiku();
}

#endif

AudioDriverInterface* AudioDriverManager::getPreferredAudioDriver()
{
	return driverList[defaultDriverIndex];
}

AudioDriverManager::~AudioDriverManager()
{
	CLEANUP_DRIVERLIST;
}

AudioDriverInterface* AudioDriverManager::getAudioDriverByName(const char* name)
{
	if (name == NULL)
		return NULL;

	for (mp_sint32 i = 0; i < numDrivers; i++)
	{
		if (strcmp(driverList[i]->getDriverID(), name) == 0)
			return driverList[i];
	}

	return NULL;
}

const char* AudioDriverManager::getFirstDriverName() const
{
	enumerationIndex = 0;
	if (enumerationIndex < numDrivers)
		return driverList[enumerationIndex]->getDriverID();
	else
		return NULL;
}

const char* AudioDriverManager::getNextDriverName() const
{
	enumerationIndex++;
	if (enumerationIndex >= numDrivers)
	{
		enumerationIndex = -1;
		return NULL;
	}

	return driverList[enumerationIndex]->getDriverID();
}

mp_sint32 AudioDriverManager::getPreferredAudioDriverSampleRate() const
{
	return driverList[defaultDriverIndex]->getPreferredSampleRate();
}

mp_sint32 AudioDriverManager::getPreferredAudioDriverBufferSize() const
{
	return driverList[defaultDriverIndex]->getPreferredBufferSize();
}
