//------------------------------------------------------------------------------
// 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 COLLISION_SCENE_H_
#define COLLISION_SCENE_H_

#include <Core/Renamer/Renamer.h>
#include <Core/Container/HashMap.h>
#include <Core/Container/ArrayList.h>

namespace Lamp{

class IntersectionResult;
class CollisionObject;
class CollisionNode;
class CollisionLeaf;
class StaticSphereCollision;
class StaticDeformedMeshCollision;

//------------------------------------------------------------------------------
/**
 * コリジョンシーン
 */
class CollisionScene{
public:
	//--------------------------------------------------------------------------
	// 生成、破棄
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 */
	CollisionScene();

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

	//--------------------------------------------------------------------------
	// シーン関連
	//--------------------------------------------------------------------------
	/**
	 * 走査
	 */
	virtual void traverse();

	/**
	 * ルートノードの取得
	 * @return ルートノード
	 */
	virtual CollisionNode* getRootNode(){ return rootNode_; }

	//--------------------------------------------------------------------------
	/**
	 * チックの設定
	 * @param tick チック
	 */
	virtual void setTick(int tick){ tick_ = tick; }

	/**
	 * チックの取得
	 * @return チック
	 */
	virtual int getTick() const{ return tick_; }

	//--------------------------------------------------------------------------
	// 交差
	//--------------------------------------------------------------------------
	/**
	 * 球交差
	 * @param result 交差結果
	 * @param sphere 球
	 * @param collisionMask コリジョンマスク
	 */
	virtual void intersection(IntersectionResult* result, const Sphere& sphere,
		u_int collisionMask = 0xffffffff);

	/**
	 * 球コリジョン交差
	 * @param result 交差結果
	 * @param sphere 球コリジョン
	 * @param collisionMask コリジョンマスク
	 */
	virtual void intersection(IntersectionResult* result,
		StaticSphereCollision* sphere, u_int collisionMask = 0xffffffff);

	//--------------------------------------------------------------------------
	// 衝突
	//--------------------------------------------------------------------------

	//--------------------------------------------------------------------------
	// コリジョンノード生成
	//--------------------------------------------------------------------------
	/**
	 * コリジョンノードの作成
	 *
	 * すでに同じ名前のコリジョンオブジェクトが存在するとエラーになります。
	 * 空文字列を名前に指定するとエラーになります。
	 * @param name 名前
	 * @return コリジョンノード
	 */
	CollisionNode* createCollisionNode(const String& name);

	//--------------------------------------------------------------------------
	// 静的コリジョンリーフ生成
	//--------------------------------------------------------------------------
	/**
	 * 静的球コリジョンの作成
	 *
	 * すでに同じ名前のコリジョンオブジェクトが存在するとエラーになります。
	 * 空文字列を名前に指定するとエラーになります。
	 * @param name 名前
	 * @return 静的球コリジョン
	 */
	StaticSphereCollision* createStaticSphereCollision(const String& name);

	//--------------------------------------------------------------------------
	/**
	 * 静的変形メッシュコリジョンの作成
	 *
	 * すでに同じ名前のコリジョンオブジェクトが存在するとエラーになります。
	 * 空文字列を名前に指定するとエラーになります。
	 * @param name 名前
	 * @return 静的変形メッシュコリジョン
	 */
	StaticDeformedMeshCollision* createStaticDeformedMeshCollision(
		const String& name);

	//--------------------------------------------------------------------------
	// コリジョンオブジェクト破棄
	//--------------------------------------------------------------------------
	/**
	 * ノードオブジェクトの破棄
	 * @param node 破棄するノードオブジェクト
	 */
	virtual void destroyNode(CollisionNode* node);

	/**
	 * リーフオブジェクトの破棄
	 * @param leaf 破棄するリーフオブジェクト
	 */
	virtual void destroyLeaf(CollisionLeaf* leaf);

	/**
	 * クリア
	 * @return 削除したコリジョンオブジェクト数
	 */
	virtual int clear();

	//--------------------------------------------------------------------------
	// コリジョンオブジェクトの操作
	//--------------------------------------------------------------------------
	/**
	 * ノードオブジェクト数の取得
	 * @return ノードオブジェクト数
	 */
	virtual int getNodeCount(){ return nodeArray_.getCount(); }

	/**
	 * ノードオブジェクトの取得
	 * @param index ノードオブジェクトのインデクス
	 * @return ノードオブジェクト
	 */
	virtual CollisionNode* getNode(int index){ return nodeArray_.get(index); }

	/**
	 * ノードオブジェクトの検索
	 * @param name 検索するノードオブジェクト名
	 * @return ノードオブジェクト
	 */
	virtual CollisionNode* searchNode(const String& name){
		return nodeDatabase_.get(name);
	}

	/**
	 * ノード名が存在するかどうか
	 * @param name 存在するかどうか調べる名前
	 * @return ノード名が存在すればtrue
	 */
	virtual bool existNodeName(const String& name){
		return (searchNode(name) != NULL);
	}

	//--------------------------------------------------------------------------
	/**
	 * リーフオブジェクト数の取得
	 * @return リーフオブジェクト数
	 */
	virtual int getLeafCount(){ return leafArray_.getCount(); }

	/**
	 * リーフオブジェクトの取得
	 * @param index リーフオブジェクトのインデクス
	 * @return リーフオブジェクト
	 */
	virtual CollisionLeaf* getLeaf(int index){ return leafArray_.get(index); }

	/**
	 * リーフオブジェクトの検索
	 * @param name 検索するリーフオブジェクト名
	 * @return リーフオブジェクト
	 */
	virtual CollisionLeaf* searchLeaf(const String& name){
		return leafDatabase_.get(name);
	}

	/**
	 * リーフ名が存在するかどうか
	 * @param name 存在するかどうか調べる名前
	 * @return リーフ名が存在すればtrue
	 */
	virtual bool existLeafName(const String& name){
		return (searchLeaf(name) != NULL);
	}

	//--------------------------------------------------------------------------
	// リネーム関係
	//--------------------------------------------------------------------------
	/**
	 * ノードのリネーム
	 * @param name 元となる名前
	 * @return 重複していない名前
	 */
	virtual String renameNode(const String& name){
		return nodeRenamer_->rename(&nodeRenamerCallback_, name);
	}

	/**
	 * ノードリネーマの設定
	 * @param renamer 設定するノードリネーマ
	 */
	virtual void setNodeRenamer(Renamer* renamer){
		Assert((renamer != NULL) && (nodeRenamer_ != NULL));
		SafeDelete(nodeRenamer_);
		nodeRenamer_ = renamer;
	}

	//--------------------------------------------------------------------------
	/**
	 * リーフのリネーム
	 * @param name 元となる名前
	 * @return 重複していない名前
	 */
	virtual String renameLeaf(const String& name){
		return leafRenamer_->rename(&leafRenamerCallback_, name);
	}

	/**
	 * リーフリネーマの設定
	 * @param renamer 設定するリーフリネーマ
	 */
	virtual void setLeafRenamer(Renamer* renamer){
		Assert((renamer != NULL) && (leafRenamer_ != NULL));
		SafeDelete(leafRenamer_);
		leafRenamer_ = renamer;
	}

protected:
	//--------------------------------------------------------------------------
	// リネーマ
	//--------------------------------------------------------------------------
	/// ノードリネーマコールバック
	class NodeRenamerCallback : public Renamer::Database{
		friend class CollisionScene;
	private:
		/**
		 * 名前が存在するかどうか
		 * @param name 存在するかどうか調べる名前
		 * @return 名前が存在すればtrue
		 */
		virtual bool existName(const String& name){
			return scene_->existNodeName(name);
		}

		// シーン
		CollisionScene* scene_;
	};

	//--------------------------------------------------------------------------
	/// リーフリネーマコールバック
	class LeafRenamerCallback : public Renamer::Database{
		friend class CollisionScene;
	private:
		/**
		 * 名前が存在するかどうか
		 * @param name 存在するかどうか調べる名前
		 * @return 名前が存在すればtrue
		 */
		virtual bool existName(const String& name){
			return scene_->existLeafName(name);
		}

		// シーン
		CollisionScene* scene_;
	};

	//--------------------------------------------------------------------------
	// ユーティリティ
	//--------------------------------------------------------------------------
	/**
	 * リーフの名前チェック
	 * @param name チェックする名前
	 * @return 正常な名前ならtrueを返す
	 */
	bool checkLeafName(const String& name);

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

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

	//--------------------------------------------------------------------------
	// ノードデータベース
	HashMap<String, CollisionNode*> nodeDatabase_;
	// ノード配列
	ArrayList<CollisionNode*> nodeArray_;
	// ノードリネーマ
	Renamer* nodeRenamer_;
	// ノードリネーマコールバック
	NodeRenamerCallback nodeRenamerCallback_;
	// リーフデータベース
	HashMap<String, CollisionLeaf*> leafDatabase_;
	// リーフ配列
	ArrayList<CollisionLeaf*> leafArray_;
	// リーフリネーマ
	Renamer* leafRenamer_;
	// リーフリネーマコールバック
	LeafRenamerCallback leafRenamerCallback_;
	// ルートノード
	CollisionNode* rootNode_;
	// チック
	int tick_;

};

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