#pragma once
#include "Engine/ISound.h"
#include "Engine/ResourceManager.h"

/*
	Class for storing raw sample data. It should only ever be deleted if not
	needed by anyone - if no instance of this sample is played.
*/
struct SSample
{
	SSample()
		: m_pSample( 0 )
	{}

	SSample( const std::string & key, ALLEGRO_SAMPLE *pSample )
		: m_key( key )
		, m_pSample( pSample )
	{}

	std::string m_key;
	ALLEGRO_SAMPLE *m_pSample;

	operator ALLEGRO_SAMPLE*() { return m_pSample; }
	operator const ALLEGRO_SAMPLE*() const { return m_pSample; }
};

/*
	Stores data about streamed sample (music).
*/
struct SSampleStream
{
	SSampleStream()
		: m_pStream( 0 )
	{}

	SSampleStream( const std::string & key, ALLEGRO_AUDIO_STREAM *pStream )
		: m_key( key )
		, m_pStream( pStream )
	{}

	std::string m_key;
	ALLEGRO_AUDIO_STREAM *m_pStream;

	operator ALLEGRO_AUDIO_STREAM*() { return m_pStream; }
	operator const ALLEGRO_AUDIO_STREAM*() const { return m_pStream; }
};

typedef boost::shared_ptr<SSample> SamplePtr;
typedef boost::shared_ptr<SSampleStream> SampleStreamPtr;

/*
	Implementation for sound effects samples.
	Uses ALLEGRO_SAMPLE_INSTANCE for playback
*/
class AllegroSoundSample5 : public ISample
{
	ALLEGRO_SAMPLE_INSTANCE *m_pInstance;
	float m_volume;

public:
	AllegroSoundSample5()
		: m_pInstance( 0 )
		, m_volume( 1.0f )
	{}

	~AllegroSoundSample5();

	bool Load( const std::string & path );

	bool Play();
	bool Stop();

	void SetVolume( float value );
	float GetVolume() const;

	void SetPan( float value );
	float GetPan() const;

	void SetPitch( float value );
	float GetPitch() const;

	bool IsPlaying() const;

	void SetLoopMode( ELoopMode mode );
	ELoopMode GetLoopMode() const;

	ALLEGRO_SAMPLE_INSTANCE *GetInstance() { return m_pInstance; }
};

/*
	Implementation for sound effects samples.
	Uses ALLEGRO_AUDIO_STREAM for playback,
	because tracker music only works in this mode.
*/
class AllegroMusicSample5 : public ISample
{
	ALLEGRO_AUDIO_STREAM *m_pInstance;
	float m_volume;

public:
	AllegroMusicSample5()
		: m_pInstance( 0 )
		, m_volume( 1.0f )
	{}

	~AllegroMusicSample5();

	bool Load( const std::string & path );

	bool Play();
	bool Stop();

	void SetVolume( float value );
	float GetVolume() const;

	void SetPan( float value );
	float GetPan() const;

	void SetPitch( float value );
	float GetPitch() const;

	bool IsPlaying() const;

	void SetLoopMode( ELoopMode mode );
	ELoopMode GetLoopMode() const;

	ALLEGRO_AUDIO_STREAM *GetInstance() { return m_pInstance; }
};

class AllegroSound5 : public ISound
{
	float m_masterVolume;
	float m_musicVolume;
	float m_soundVolume;

	  // I only use the single voice into which everything else is mixed
	ALLEGRO_VOICE *m_pVoice;
	  // Master mixer for setting Master Sound Volume
	ALLEGRO_MIXER *m_pMasterMixer;
	ALLEGRO_MIXER *m_pMusicMixer;
	ALLEGRO_MIXER *m_pSoundMixer;

	  // Currently active samples (both Music and Sounds)
	typedef std::vector<ISamplePtr> SampleList;
	SampleList m_sampleList;

public:
	AllegroSound5();
	~AllegroSound5();

	bool Init();

	ALLEGRO_MIXER *GetSoundMixer() { return m_pSoundMixer; }
	ALLEGRO_MIXER *GetMusicMixer() { return m_pMusicMixer; }

	void SetMasterVolume( float volume );
	float GetMasterVolume() const;

	void SetVolumeByType( ISample::EType type, float volume );
	float GetVolumeByType( ISample::EType type ) const;


private:
	ISamplePtr CreateSample( const std::string & path, ISample::EType type );
};
