//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser 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
//------------------------------------------------------------------------------

/** @file
 * サウンドマネージャヘッダ
 * @author Junpee
 */

#ifndef SOUND_MANAGER_H_
#define SOUND_MANAGER_H_

#include <Core/Container/Deque.h>
#include <Core/InputOutput/FilePath.h>
#include <Sound/System/Sound.h>
#include <Sound/System/SoundDefinition.h>

namespace Lamp{

class SoundReader;

//------------------------------------------------------------------------------
/**
 * サウンドマネージャ
 */
class SoundManager{
friend class LampSound;
friend class SoundBuffer;
friend class StaticSound;
friend class StaticSound3D;
public:
	//--------------------------------------------------------------------------
	/// 3Dサウンドアルゴリズム
	enum Algorithm{
		/// 通常の3Dサウンドアルゴリズム
		algorithmNormal,
		/// 軽量HRTF3Dサウンドアルゴリズム
		algorithmLightHRTF,
		/// フルHRTF3Dサウンドアルゴリズム
		algorithmFullHRTF,
	};

	//--------------------------------------------------------------------------
	// サウンド操作
	//--------------------------------------------------------------------------
	/**
	 * サウンドの破棄
	 * @param sound 破棄するサウンド
	 */
	virtual void destroy(Sound* sound);

	/**
	 * 全サウンドの破棄
	 */
	virtual void destroyAll();

	/**
	 * サウンド数の取得
	 * @return サウンド数
	 */
	virtual int getCount() const{ return sounds_.getCount(); }

	/**
	 * サウンドの取得
	 * @param index サウンドのインデックス
	 * @return サウンド
	 */
	virtual Sound* getSound(int index){ return sounds_[index]; }

	//--------------------------------------------------------------------------
	/**
	 * 3Dアルゴリズムの設定
	 *
	 * 設定後に生成した3Dサウンドに対してアルゴリズムが適用されます。
	 * @param algorithm 3Dアルゴリズム
	 */
	virtual void set3DAlgorithm(Algorithm algorithm){ algorithm_ = algorithm; }

	/**
	 * 3Dアルゴリズムの取得
	 * @return 3Dアルゴリズム
	 */
	virtual Algorithm get3DAlgorithm() const{ return algorithm_; }

	//--------------------------------------------------------------------------
	// 静的サウンド
	//--------------------------------------------------------------------------
	/**
	 * 静的サウンドの作成
	 * @param size バッファサイズ
	 * @param sample サンプル数
	 * @param channel チャンネル数
	 * @param bit ビット数
	 * @param focus フォーカス
	 * @return 静的サウンド
	 */
	virtual StaticSound* createStaticSound(
		u_int size, int sample, int channel, int bit,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	/**
	 * 静的サウンドの作成
	 * @param fileName ファイル名
	 * @param focus フォーカス
	 * @return 静的サウンド。失敗したらNULLを返す。
	 */
	virtual StaticSound* createStaticSound(const String& fileName,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	//--------------------------------------------------------------------------
	// ストリームサウンド
	//--------------------------------------------------------------------------
	/**
	 * ストリームサウンドの作成
	 * @param size バッファサイズ
	 * @param sample サンプル数
	 * @param channel チャンネル数
	 * @param bit ビット数
	 * @param focus フォーカス
	 * @return ストリームサウンド
	 */
	virtual StreamSound* createStreamSound(
		u_int size, int sample, int channel, int bit,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	/**
	 * ストリームサウンドの作成
	 * @param fileName ファイル名
	 * @param focus フォーカス
	 * @return ストリームサウンド。失敗したらNULLを返す。
	 */
	virtual StreamSound* createStreamSound(const String& fileName,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	//--------------------------------------------------------------------------
	// 静的3Dサウンド
	//--------------------------------------------------------------------------
	/**
	 * 静的3Dサウンドの作成
	 * @param size バッファサイズ
	 * @param sample サンプル数
	 * @param channel チャンネル数
	 * @param bit ビット数
	 * @param focus フォーカス
	 * @return 静的3Dサウンド
	 */
	virtual StaticSound3D* createStaticSound3D(
		u_int size, int sample, int channel, int bit,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	/**
	 * 静的3Dサウンドの作成
	 * @param fileName ファイル名
	 * @param focus フォーカス
	 * @return 静的3Dサウンド。失敗したらNULLを返す。
	 */
	virtual StaticSound3D* createStaticSound3D(const String& fileName,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	//--------------------------------------------------------------------------
	// ストリーム3Dサウンド
	//--------------------------------------------------------------------------
	/**
	 * ストリーム3Dサウンドの作成
	 * @param size バッファサイズ
	 * @param sample サンプル数
	 * @param channel チャンネル数
	 * @param bit ビット数
	 * @param focus フォーカス
	 * @return ストリーム3Dサウンド
	 */
	virtual StreamSound3D* createStreamSound3D(
		u_int size, int sample, int channel, int bit,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	/**
	 * ストリーム3Dサウンドの作成
	 * @param fileName ファイル名
	 * @param focus フォーカス
	 * @return ストリーム3Dサウンド。失敗したらNULLを返す。
	 */
	virtual StreamSound3D* createStreamSound3D(const String& fileName,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

private:
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 * @param directSound DirectSound
	 */
	SoundManager(DirectSound* directSound);

	/**
	 * デストラクタ
	 */
	virtual ~SoundManager();

	//--------------------------------------------------------------------------
	// 静的サウンド
	//--------------------------------------------------------------------------
	/**
	 * 静的サウンドの作成
	 * @param soundReader サウンドリーダ
	 * @param name 名前
	 * @param focus フォーカス
	 * @return 静的サウンド。失敗したらNULLを返す。
	 */
	virtual StaticSound* createStaticSound(
		SoundReader* soundReader, const String& name,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	/**
	 * 静的サウンドの複製
	 * @param staticSound 静的サウンド
	 * @return 静的サウンド
	 */
	virtual StaticSound* cloneStaticSound(StaticSound* staticSound);

	//--------------------------------------------------------------------------
	// ストリームサウンド
	//--------------------------------------------------------------------------
	/**
	 * ストリームサウンドの作成
	 * @param soundReader サウンドリーダ、ストリームサウンドによりdeleteされます。
	 * @param name 名前
	 * @param focus フォーカス
	 * @return ストリームサウンド。失敗したらNULLを返す。
	 */
	virtual StreamSound* createStreamSound(
		SoundReader* soundReader, const String& name,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	//--------------------------------------------------------------------------
	// 静的3Dサウンド
	//--------------------------------------------------------------------------
	/**
	 * 静的3Dサウンドの作成
	 * @param soundReader サウンドリーダ
	 * @param name 名前
	 * @param focus フォーカス
	 * @return 静的3Dサウンド。失敗したらNULLを返す。
	 */
	virtual StaticSound3D* createStaticSound3D(
		SoundReader* soundReader, const String& name,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	/**
	 * 静的3Dサウンドの複製
	 * @param staticSound3D 静的3Dサウンド
	 * @return 静的3Dサウンド
	 */
	virtual StaticSound3D* cloneStaticSound3D(StaticSound3D* staticSound3D);

	//--------------------------------------------------------------------------
	// ストリーム3Dサウンド
	//--------------------------------------------------------------------------
	/**
	 * ストリーム3Dサウンドの作成
	 * @param soundReader サウンドリーダ、ストリーム3Dサウンドによりdeleteされます。
	 * @param name 名前
	 * @param focus フォーカス
	 * @return ストリーム3Dサウンド。失敗したらNULLを返す。
	 */
	virtual StreamSound3D* createStreamSound3D(
		SoundReader* soundReader, const String& name,
		Sound::Focus focus = (Sound::Focus)SoundDefinition::defaultFocus);

	//--------------------------------------------------------------------------
	// サウンドバッファ
	//--------------------------------------------------------------------------
	/**
	 * ウェーブフォーマットの構築
	 * @param waveFormat ウェーブフォーマットへのポインタ
	 * @param samples サンプル数
	 * @param channels チャンネル数
	 * @param bit ビット数
	 */
	virtual void buildWaveFormat(
		WAVEFORMATEX* waveFormat, int sample, int channel, int bit);

	/**
	 * バッファ記述の構築
	 * @param description バッファ記述
	 * @param waveFormat ウェーブフォーマットへのポインタ
	 * @param size バッファサイズ
	 * @param focus フォーカス
	 */
	virtual void buildBufferDescription(DSBUFFERDESC* description,
		WAVEFORMATEX* waveFormat, int size, Sound::Focus focus);

	/**
	 * サウンドバッファの構築
	 * @param description バッファ記述
	 * @return サウンドバッファ
	 */
	virtual DirectSoundBuffer* buildSoundBuffer(DSBUFFERDESC* description);

	/**
	 * サウンドリーダの作成
	 * @param filePath ファイルパス
	 * @return サウンドリーダ
	 */
	virtual SoundReader* createSoundReader(const FilePath& filePath);

	/**
	 * サウンドバッファの読み込み
	 * @param soundBuffer サウンドバッファ
	 * @param soundReader サウンドリーダ
	 * @return 成功すればtrue
	 */
	virtual bool readSoundBuffer(SoundBuffer* sound, SoundReader* soundReader);

	/**
	 * サウンドバッファの複製
	 * @param soundBuffer 複製元サウンドバッファ
	 * @return 複製されたサウンドバッファ
	 */
	virtual DirectSoundBuffer* duplicateSoundBuffer(
		DirectSoundBuffer* soundBuffer);

	//--------------------------------------------------------------------------
	// アップデート
	//--------------------------------------------------------------------------
	/**
	 * アップデート
	 */
	virtual void update();

	/**
	 * アップデートサウンドの追加
	 * @param sound 追加するアップデートサウンド
	 */
	virtual void addUpdateSound(Sound* sound);

	/**
	 * アップデートサウンドの削除
	 * @param sound 削除するアップデートサウンド
	 */
	virtual void removeUpdateSound(Sound* sound);

	//--------------------------------------------------------------------------
	// コピーコンストラクタの隠蔽
	SoundManager(const SoundManager& copy);

	// 代入コピーの隠蔽
	void operator =(const SoundManager& copy);

	//--------------------------------------------------------------------------
	// DirectSound
	DirectSound* directSound_;
	// サウンド配列
	Deque<Sound*> sounds_;
	// アップデートサウンド配列
	Deque<Sound*> updateSounds_;
	// 3Dアルゴリズム
	Algorithm algorithm_;

};

//------------------------------------------------------------------------------
} // End of namespace Lamp
#endif // End of SOUND_MANAGER_H_
//------------------------------------------------------------------------------
