/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program 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 General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifdef _WIN32_WCE

// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL

#include "common/config-manager.h"
#include "backends/platform/wince/wince-sdl.h"
#include "backends/mixer/wincesdl/wincesdl-mixer.h"
#include "common/system.h"
#include "common/textconsole.h"

#ifdef USE_VORBIS
#ifndef USE_TREMOR
#include <vorbis/vorbisfile.h>
#else
#ifdef USE_TREMOLO
#include <tremolo/ivorbisfile.h>
#else
#include <tremor/ivorbisfile.h>
#endif
#endif
#endif

#define SAMPLES_PER_SEC_OLD 11025
#define SAMPLES_PER_SEC_NEW 22050

WINCESdlMixerManager::WINCESdlMixerManager() {

}

WINCESdlMixerManager::~WINCESdlMixerManager() {

}

void WINCESdlMixerManager::init() {
	SDL_AudioSpec desired;
	int thread_priority;

	uint32 sampleRate = compute_sample_rate();
	if (sampleRate == 0)
		warning("OSystem_WINCE3::setupMixer called with sample rate 0 - audio will not work");
	else if (_mixer && _mixer->getOutputRate() == sampleRate) {
		debug(1, "Skipping sound mixer re-init: samplerate is good");
		return;
	}

	memset(&desired, 0, sizeof(desired));
	desired.freq = sampleRate;
	desired.format = AUDIO_S16SYS;
	desired.channels = 2;
	desired.samples = 128;
	desired.callback = private_sound_proc;
	desired.userdata = this;

	// Create the mixer instance
	if (_mixer == 0)
		_mixer = new Audio::MixerImpl(g_system, sampleRate);

	// Add sound thread priority
	if (!ConfMan.hasKey("sound_thread_priority"))
		thread_priority = THREAD_PRIORITY_NORMAL;
	else
		thread_priority = ConfMan.getInt("sound_thread_priority");

	desired.thread_priority = thread_priority;

	SDL_CloseAudio();
	if (SDL_OpenAudio(&desired, NULL) != 0) {
		warning("Could not open audio device: %s", SDL_GetError());
		_mixer->setReady(false);

	} else {
		debug(1, "Sound opened OK, mixing at %d Hz", sampleRate);

		// Re-create mixer to match the output rate
		int vol1 = _mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
		int vol2 = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
		int vol3 = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
		int vol4 = _mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
		delete _mixer;
		_mixer = new Audio::MixerImpl(g_system, sampleRate);
		_mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, vol1);
		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol2);
		_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol3);
		_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, vol4);
		_mixer->setReady(true);
		SDL_PauseAudio(0);
	}
}

void WINCESdlMixerManager::private_sound_proc(void *param, byte *buf, int len) {
	WINCESdlMixerManager *this_ = (WINCESdlMixerManager *)param;
	assert(this_);

	if (this_->_mixer)
		this_->_mixer->mixCallback(buf, len);
	if (!OSystem_WINCE3::_soundMaster)
		memset(buf, 0, len);
}

uint32 WINCESdlMixerManager::compute_sample_rate() {
	uint32 sampleRate;

	// Force at least medium quality FM synthesis for FOTAQ
	Common::String gameid(ConfMan.get("gameid"));
	if (gameid == "queen") {
		if (!((ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) ||
			(ConfMan.hasKey("FM_medium_quality") && ConfMan.getBool("FM_medium_quality")))) {
			ConfMan.setBool("FM_medium_quality", true);
			ConfMan.flushToDisk();
		}
	} else {
		if (!ConfMan.hasKey("FM_high_quality") && !ConfMan.hasKey("FM_medium_quality")) {
			ConfMan.setBool("FM_high_quality", true);
			ConfMan.flushToDisk();
		}
	}
	// See if the output frequency is forced by the game
	if (gameid == "ft" || gameid == "dig" || gameid == "comi" || gameid == "queen" || gameid == "sword" || gameid == "agi")
			sampleRate = SAMPLES_PER_SEC_NEW;
	else {
		if (ConfMan.hasKey("high_sample_rate") && !ConfMan.getBool("high_sample_rate"))
			sampleRate = SAMPLES_PER_SEC_OLD;
		else
			sampleRate = SAMPLES_PER_SEC_NEW;
	}

#ifdef USE_VORBIS
	// Modify the sample rate on the fly if OGG is involved
	if (sampleRate == SAMPLES_PER_SEC_OLD)
		if (checkOggHighSampleRate())
			 sampleRate = SAMPLES_PER_SEC_NEW;
#endif

	return sampleRate;
}

#ifdef USE_VORBIS
bool WINCESdlMixerManager::checkOggHighSampleRate() {
	char trackFile[255];
	FILE *testFile;
	OggVorbis_File *test_ov_file = new OggVorbis_File;

	// FIXME: The following sprintf assumes that "path" is always
	// terminated by a path separator. This is *not* true in general.
	// This code really should check for the path separator, or even
	// better, use the FSNode API.
	sprintf(trackFile, "%sTrack1.ogg", ConfMan.get("path").c_str());
	// Check if we have an OGG audio track
	testFile = fopen(trackFile, "rb");
	if (testFile) {
		if (!ov_open(testFile, test_ov_file, NULL, 0)) {
			bool highSampleRate = (ov_info(test_ov_file, -1)->rate == 22050);
			ov_clear(test_ov_file);
			delete test_ov_file;
			return highSampleRate;
		}
	}

	// Do not test for OGG samples - too big and too slow anyway :)

	delete test_ov_file;
	return false;
}
#endif

#endif