#include "core.h"
#include "log.h"

#define MINIAUDIO_IMPLEMENTATION
#include "soundsystem.h"

SoundSystem g_soundSystem;

SoundSystem::SoundSystem()
{
	memset(&m_engine, 0, sizeof(m_engine));
	memset(&m_sounds, 0, sizeof(m_sounds));

	m_inited = false;
	m_dwSoundsNum = 0;
}

SoundSystem::~SoundSystem()
{
}

void SoundSystem::Init()
{
	ma_result result;

	Msg("Sound initialization\n");

	result = ma_engine_init(NULL, &m_engine);
	if ( result != MA_SUCCESS )
	{
		Msg("Failed to initialize the miniaudio engine. %s\n", ma_result_description(result));
		//DError("Failed to initialize the miniaudio engine. %s\n", ma_result_description(result));
		return;  // Failed to initialize the engine.
	}

	ma_uint32 uiChannels = ma_engine_get_channels(&m_engine);
	Msg("%d channel(s)\n", uiChannels);

	ma_uint32 uiSampleRate = ma_engine_get_sample_rate(&m_engine);
	Msg("Sound sampling rate: %d\n", uiSampleRate);

	// Initialize listener
	SetListenerPosition(0.0f, 0.0f, 0.0f);

	m_inited = true;
}

void SoundSystem::Shutdown()
{
	if ( !m_inited )
		return;

	for ( int i = 0; i < m_dwSoundsNum; i++ )
	{
		ma_sound_uninit(&m_sounds[i]);
	}

	memset(&m_sounds, 0, sizeof(m_sounds));

	ma_engine_uninit(&m_engine);
	memset(&m_engine, 0, sizeof(m_engine));
}

SoundHandle SoundSystem::LoadSound(const char* filename)
{
	if ( !m_inited )
		return -1;

	ma_result result;

	SoundHandle handle = m_dwSoundsNum;

	result = ma_sound_init_from_file(&m_engine, filename, 0, NULL, NULL, &m_sounds[handle]);
	if ( result != MA_SUCCESS )
	{
		Msg("Failed to load sound %s\n", filename);
		return -1;
	}

	m_dwSoundsNum++;
	return handle;
}

void SoundSystem::Play(SoundHandle handle, bool bLoop)
{
	if ( !m_inited )
		return;

	assert(handle <= -1 || handle <= m_dwSoundsNum);

	ma_sound_start(&m_sounds[handle]);
	ma_sound_set_spatialization_enabled(&m_sounds[handle], false);

	if ( bLoop )
		ma_sound_set_looping(&m_sounds[handle], true);
}

void SoundSystem::Play3D(SoundHandle handle, float x, float y, float z, bool bLoop)
{
	if ( !m_inited )
		return;

	Play(handle, bLoop);

	// enable 3d
	ma_sound_set_spatialization_enabled(&m_sounds[handle], true);
	ma_sound_set_position(&m_sounds[handle], x, y, z);
}

void SoundSystem::Stop(SoundHandle handle)
{
	if ( !m_inited )
		return;

	assert(handle <= -1 || handle <= m_dwSoundsNum);
	ma_sound_stop(&m_sounds[handle]);
	ma_sound_seek_to_pcm_frame(&m_sounds[handle], 0); // <-- If you also want to restart from the start.
	ma_sound_reset_stop_time_and_fade(&m_sounds[handle]);
}

bool SoundSystem::IsPlaying(SoundHandle handle)
{
	if ( !m_inited )
		return false;

	assert(handle <= -1 || handle <= m_dwSoundsNum);

	return ma_sound_is_playing(&m_sounds[handle]);
}

void SoundSystem::SetMasterVolume(float volume)
{
	if ( !m_inited )
		return;

	ma_engine_set_volume(&m_engine, volume);
}

float SoundSystem::GetMasterVolume()
{
	return ma_engine_get_volume(&m_engine);
}

void SoundSystem::SetListenerPosition(float _x, float _y, float _z)
{
	if ( !m_inited )
		return;

	ma_engine_listener_set_position(&m_engine, 0, _x, _y, _z);
}

void SoundSystem::SetListenerDirection(float _x, float _y, float _z)
{
	if ( !m_inited )
		return;

	ma_engine_listener_set_direction(&m_engine, 0, _x, _y, _z);
}
