//------------------------------------------------------------------------------
// 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_CACHE_H_
#define SOUND_CACHE_H_

#include <Core/Container/ArrayList.h>
#include <Core/Container/HashMap.h>
#include <Sound/System/Sound.h>

namespace Lamp{

class TextReader;

//------------------------------------------------------------------------------
/**
 * サウンドキャッシュ
 *
 * 静的サウンドをキャッシングするためのクラス。ストリームは恩恵が無いので
 * 現在非対応。ストリームに対するclone()が上手くいくようになれば対応を考える。
 * SoundCache.cppのrev1.5あたりにストリームキャッシュの実装有り。
 */
class SoundCache{
public:
	//--------------------------------------------------------------------------
	// 生成、破棄
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 * @param basePath ベースパス
	 * @param extension 「.」付き拡張子（例 : ".wav" ".ogg"）
	 * @param focus フォーカス
	 * @param defaultMaxMixingCount デフォルト最大ミキシング数
	 */
	SoundCache(const String& basePath = "", const String& extension = "",
		Sound::Focus focus = Sound::focusNormal,
		int defaultMaxMixingCount = 16);

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

	//--------------------------------------------------------------------------
	// サウンドのロード
	//--------------------------------------------------------------------------
	/**
	 * 静的サウンドのロード
	 * @param name サウンド名
	 * @param loop ループするならtrue
	 * @param priority 優先度を32767〜-32768の間で指定
	 * @param maxMixingCount 最大ミキシング数、0ならデフォルトを使用する
	 * @return 成功すればtrueを返す
	 */
	virtual bool loadStaticSound(const String& name, bool loop = false,
		int priority = Sound::priorityDefault, int maxMixingCount = 0);

	/**
	 * 静的3Dサウンドのロード
	 * @param name サウンド名
	 * @param minimumDistance 最小距離
	 * @param maximumDistance 最大距離
	 * @param loop ループするならtrue
	 * @param priority 優先度を32767〜-32768の間で指定
	 * @param maxMixingCount 最大ミキシング数、0ならデフォルトを使用する
	 * @return 成功すればtrueを返す
	 */
	virtual bool loadStaticSound3D(const String& name, bool loop = false,
		int priority = Sound::priorityDefault,
		float minimumDistance = DS3D_DEFAULTMINDISTANCE,
		float maximumDistance = DS3D_DEFAULTMAXDISTANCE,
		int maxMixingCount = 0);

	/**
	 * サウンドのアンロード
	 * @param name サウンド名
	 * @return 成功すればtrueを返す
	 */
	virtual bool unloadSound(const String& name);

	/**
	 * 全サウンドのアンロード
	 */
	virtual void unloadAll();

	//--------------------------------------------------------------------------
	// サウンドリスト
	//--------------------------------------------------------------------------
	/**
	 * サウンドリストのロード
	 * @param filePath ベースパスからの相対ファイルパス
	 * @return 成功すればtrue
	 */
	virtual bool loadSoundList(const String& filePath);

	/**
	 * サウンドリストのロード
	 * @param textReader テキストリーダ
	 * @return 成功すればtrue
	 */
	virtual bool loadSoundList(TextReader* textReader);

	//--------------------------------------------------------------------------
	// サウンドの再生
	//--------------------------------------------------------------------------
	/**
	 * サウンドの再生
	 *
	 * ループサウンドの場合は返り値のポインタを保存して自前でstop()を呼んでください。
	 * ループサウンドで無い場合は返り値のポインタへのアクセスは、呼び出した時点で
	 * のみ行い、その後は使用しないで下さい。もし、ループしていないサウンドに対して
	 * 再生終了までのアクセスが必要なのであれば、getSound(),releaseSound()を
	 * 使用してください。
	 * @param name 名前
	 * @param volume ボリュームを1.fから0.fの間で指定する
	 * @param frequency 周波数を100から100000の間で指定する、0ならオリジナル周波数
	 * @return 再生したサウンド、失敗ならNULL。
	 */
	virtual Sound* playSound(const String& name, float volume = 1.f,
		int frequency = 0);

	/**
	 * ステレオサウンドの再生
	 *
	 * ループサウンドの場合は返り値のポインタを保存して自前でstop()を呼んでください。
	 * ループサウンドで無い場合は返り値のポインタへのアクセスは、呼び出した時点で
	 * のみ行い、その後は使用しないで下さい。もし、ループしていないサウンドに対して
	 * 再生終了までのアクセスが必要なのであれば、getSound(),releaseSound()を
	 * 使用してください。
	 * @param name 名前
	 * @param volume ボリュームを1.fから0.fの間で指定する
	 * @param frequency 周波数を100から100000の間で指定する、0ならオリジナル周波数
	 * @param pan パンを-1.f(左)から1.f(右)の間で指定する
	 * @return 再生したサウンド、失敗ならNULL。
	 */
	virtual StereoSound* playStereoSound(const String& name, float volume = 1.f,
		int frequency = 0, float pan = 0.f);

	/**
	 * 3Dサウンドの再生
	 *
	 * ループサウンドの場合は返り値のポインタを保存して自前でstop()を呼んでください。
	 * ループサウンドで無い場合は返り値のポインタへのアクセスは、呼び出した時点で
	 * のみ行い、その後は使用しないで下さい。もし、ループしていないサウンドに対して
	 * 再生終了までのアクセスが必要なのであれば、getSound(),releaseSound()を
	 * 使用してください。
	 * @param name 名前
	 * @param volume ボリュームを1.fから0.fの間で指定する
	 * @param frequency 周波数を100から100000の間で指定する、0ならオリジナル周波数
	 * @param position 再生位置を指定する
	 * @return 再生したサウンド、失敗ならNULL。
	 */
	virtual Sound3D* playSound3D(const String& name, float volume = 1.f,
		int frequency = 0, const Vector3& position = Vector3::zero);

	//--------------------------------------------------------------------------
	// サウンドの取得、解放
	//--------------------------------------------------------------------------
	/**
	 * サウンドの取得
	 *
	 * サウンドの所有権を得る。所有権を得ている間、サウンドは再利用されない。
	 * 使用後はreleaseSound()で返却する必要がある。
	 * @param name 名前
	 * @param resetFlag リセットフラグ
	 * @return 取得したサウンド、失敗ならNULL。
	 */
	virtual Sound* getSound(const String& name,
		Sound::Reset resetFlag = Sound::resetRuntime);

	/**
	 * ステレオサウンドの取得
	 *
	 * サウンドの所有権を得る。所有権を得ている間、サウンドは再利用されない。
	 * 使用後はreleaseSound()で返却する必要がある。
	 * @param name 名前
	 * @param resetFlag リセットフラグ
	 * @return 取得したサウンド、失敗ならNULL。
	 */
	virtual StereoSound* getStereoSound(const String& name,
		Sound::Reset resetFlag = Sound::resetRuntime);

	/**
	 * 3Dサウンドの取得
	 *
	 * サウンドの所有権を得る。所有権を得ている間、サウンドは再利用されない。
	 * 使用後はreleaseSound()で返却する必要がある。
	 * @param name 名前
	 * @param resetFlag リセットフラグ
	 * @return 取得したサウンド、失敗ならNULL。
	 */
	virtual Sound3D* getSound3D(const String& name,
		Sound::Reset resetFlag = Sound::resetRuntime);

	/**
	 * サウンドの解放
	 *
	 * getSound()で所有権を得たサウンドを解放する。
	 * @param sound 解放するサウンド
	 */
	virtual void releaseSound(Sound* sound);

	//--------------------------------------------------------------------------
	// その他
	//--------------------------------------------------------------------------
	/**
	 * 全サウンドの再生を一時停止する
	 */
	virtual void suspendAll();

	/**
	 * 全サウンドの再生を再開する
	 */
	virtual void resumeAll();

	//--------------------------------------------------------------------------
	/**
	 * 文字列への変換
	 * @return 文字列
	 */
	virtual String toString() const;

protected:
	//--------------------------------------------------------------------------
	/**
	 * キャッシュ作成
	 * @param name 名前
	 * @param sound キャッシュを作成するサウンド
	 * @param maxMixingCount 最大ミキシング数
	 */
	virtual void createCache(
		const String& name, Sound* sound, int maxMixingCount);

	//--------------------------------------------------------------------------
	// サウンド配列
	//--------------------------------------------------------------------------
	/**
	 * サウンド配列
	 */
	class SoundArray{
	public:
		/**
		 * コンストラクタ
		 * @param sound 初期化サウンド
		 * @param maxMixingCount 最大ミキシング数
		 */
		SoundArray(Sound* sound, int maxMixingCount);

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

		/**
		 * フリーサウンド取得
		 * @return フリーサウンド、無ければNULLを返す
		 */
		Sound* getFreeSound();

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

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

		/**
		 * 文字列への変換
		 * @return 文字列
		 */
		virtual String toString() const;

	protected:
		/// サウンド配列
		ArrayList<Sound*> sounds_;
		/// 最大ミキシング数
		int maxMixingCount_;

	};

	//--------------------------------------------------------------------------
	// メンバ変数
	//--------------------------------------------------------------------------
	/// キャッシュ
	HashMap<String, SoundArray*> cache_;
	/// リスト
	ArrayList<SoundArray*> list_;
	/// ベースパス
	String basePath_;
	/// 拡張子
	String extension_;
	/// フォーカス
	Sound::Focus focus_;
	/// デフォルト最大ミキシング数
	int defaultMaxMixingCount_;

private:
	// コピーコンストラクタの隠蔽
	SoundCache(const SoundCache& copy);

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

};

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