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

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

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * シーンオブジェクトマネージャテンプレート
 */
template <typename Type>
class SceneObjectManagerTemplate : public Renamer::Database{
friend class Scene;
public:
	/**
	 * オブジェクトの破棄
	 * @param object 破棄するオブジェクト
	 * @return 破棄するオブジェクトのリファレンスカウンタ。0なら破棄されている
	 */
	virtual int destroy(Type* object){
		// 参照が残っていれば削除しない
		int referenceCount = object->getReferenceCount();
		Assert(referenceCount >= 0);
		if(referenceCount != 0){ return referenceCount; }
		// データベースから検索して削除
		if(array_.removeByValue(object) == -1){
			ErrorOut("SceneObjectManagerTemplate::destroy() "
				"Not found object in array");
		}
		if(database_.remove(object->getName()) == NULL){
			ErrorOut("SceneObjectManagerTemplate::destroy() "
				"Not found object in hashmap");
		}
		delete object;
		return 0;
	}

	//--------------------------------------------------------------------------
	/**
	 * シーンの取得
	 * @return シーン
	 */
	virtual Scene* getScene() const{ return scene_; }

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

	/**
	 * オブジェクトの取得
	 * @param index オブジェクトのインデクス
	 * @return オブジェクト
	 */
	virtual Type* get(int index){ return array_.get(index); }

	/**
	 * オブジェクトの検索
	 * @param name 検索するオブジェクト名
	 * @return オブジェクト
	 */
	virtual Type* search(const String& name){ return database_.get(name); }

	//--------------------------------------------------------------------------
	// リネーム関係
	//--------------------------------------------------------------------------
	/**
	 * 名前が存在するかどうか
	 * @param name 存在するかどうか調べる名前
	 * @return 名前が存在すればtrue
	 */
	virtual bool existName(const String& name){ return (search(name) != NULL); }

	/**
	 * リネーム
	 * @param sourceName 元となる名前
	 * @return 重複していない名前
	 */
	virtual String rename(const String& sourceName){
		return scene_->getRenamer()->rename(this, sourceName);
	}

	//--------------------------------------------------------------------------
protected:
	/**
	 * コンストラクタ
	 * @param scene シーン
	 */
	SceneObjectManagerTemplate(Scene* scene) :
		 database_(256, 0.75f), array_(256), scene_(scene){
	}

	/**
	 * デストラクタ
	 */
	virtual ~SceneObjectManagerTemplate(){
		Assert(database_.getCount() == 0);
		Assert(array_.getCount() == 0);
		if(getCount() != 0){ clear(); }
	}

	/**
	 * 名前のチェック
	 * @param name チェックする名前
	 * @return 正常な名前ならtrueを返す
	 */
	bool checkName(String name){
		// 名前の長さチェック
		if(name.getSize() == 0){
			ErrorOut("SceneObjectManager::checkName() name.getSize() == 0");
			return false;
		}
		// 名前の重複チェック
		if(existName(name)){
			ErrorOut("SceneObjectManager::checkName() repetition name %s",
				name.getBytes());
			return false;
		}
		return true;
	}

	/**
	 * データベースへの追加
	 * @param name 名前
	 * @param object オブジェクト
	 */
	virtual void addDatabase(const String& name, Type* object){
		database_.put(name, object);
		array_.add(object);
	}

	/**
	 * クリア
	 * @return 削除したオブジェクト数
	 */
	virtual int clear(){
		int result = getCount();
		// 要素の削除
		for(int i = 0; i < result; i++){ delete array_.get(i); }
		array_.clear();
		database_.clear();
		return result;
	}

	//--------------------------------------------------------------------------
	/// データベース
	HashMap<String, Type*> database_;
	/// 配列
	ArrayList<Type*> array_;
	/// シーン
	Scene* scene_;

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

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

};

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