#ifndef _ABSTRACT_OBJECT_MANAGER_
#define _ABSTRACT_OBJECT_MANAGER_

#include <list>
#include <map>
#include <exception>

#include <windows.h>

#include "E3DCloneManager.h"

#include "E3DObject.h"

namespace HPL {
namespace E3D {
/** オブジェクトの一連の流れを管理するクラス
  *
  */
template<class T>
class AbstractObjectManager {
public:
	//! Sigコピーマネージャ
	E3DCloneManager m_CloneManager;

	//! 逆引きでSigIDからオブジェクトそのものを取得
	std::map<int, T*> m_mapSigIDToObjectMap;

	//! オブジェクトの種類ごとにリストを作成する
	std::map<int, std::list<T*> > m_mapObjectListMap;

	//! 現在VALIDなオブジェクトのみ登録する。参照のみ。、
	std::map<int, std::list<T*> > m_mapValidObjectListMap;

	BOOL m_bPause;
public:
	AbstractObjectManager() {
		this->m_bPause = FALSE;
	}
	~AbstractObjectManager() {
		for( std::map<int, std::list<T*> >::iterator mit = m_mapObjectListMap.begin();
			mit != m_mapObjectListMap.end();
			mit ++ )
		{
			for( std::list<T*>::iterator it = mit->second.begin();
				it != mit->second.end(); it ++ ) 
			{
				delete *it;
			}
			mit->second.clear();
		}
		this->m_mapObjectListMap.clear();

		this->m_mapSigIDToObjectMap.clear();
	}

	/** 一連の処理。
	  * BeginScene/EndSceneの中で呼ぶ事
	  * 影付き処理をさせる場合はその処理の前に実行する
	  *
	  */
	int process() {
		for( std::map<int, std::list<T*> >::iterator mit = this->m_mapObjectListMap.begin();
			mit != this->m_mapObjectListMap.end(); mit ++ )
		{
			//for( std::list<T*>::iterator it = mit->second.begin();
			//	it != mit->second.end(); )
			for( std::list<T*>::iterator it = this->m_mapValidObjectListMap[mit->first].begin();
				it != this->m_mapValidObjectListMap[mit->first].end(); )
			{
				T* obj = *it;

				if( this->is_Skip( obj ) == TRUE ) {
					// skip
					it ++;
					continue;
				}

				int ret = 0;

				// check in
				ret = this->checkInView( obj );

				if( this->m_bPause == FALSE ) {
					// move
					ret = this->move( obj );
					
					// check hit on grund
					ret = this->checkHitToGround( obj );

					// check hit to bill board ( shot )
					ret = this->checkHitToBillBoard( obj );

					// check hit to player
					ret = this->checkHitToPlayer( obj );
				}

				ret = this->render( obj );

				//ret = this->next( obj, it , (*mit ));

				BOOL bIsValid = TRUE;
				try {
					bIsValid = ((HPL::E3D::E3DObject*)obj)->is_Valid();
				} catch( std::exception* e ) {
					e;
				}

				if( bIsValid == FALSE ) {
					it = this->m_mapValidObjectListMap[mit->first].erase(it);
				} else {
					it ++;
				}
			}
		}
		return 0;
	}
	/** リストに対するリセット処理を記述
	  * @retval 0		問題なし
	  *	@retval	1		問題あり
	  */
	int reset() {
		int ret = 0;

		for( std::map<int, std::list<T*> >::iterator mit = 
			this->m_mapObjectListMap.begin();
			mit != this->m_mapObjectListMap.end();
		mit ++ )
		{
			// 有効になってるオブジェクト一覧をクリア
			this->m_mapValidObjectListMap[mit->first].clear();

			// 実体のValidをOFFにする
			for(std::list<T*>::iterator it = mit->second.begin();
				it != mit->second.end();
				it ++ )
			{
				HPL::E3D::E3DObject* obj = (HPL::E3D::E3DObject*)*it;

				if( obj->is_Valid() ) {
					// モデルを隠す
					ret = E3DSetValidFlag( obj->m_nSigID, -1, FALSE );
				}
				obj->set_Valid( FALSE );
			}
		}
		return 0;
	}
	
	/** このオブジェクトの処理をスキップするのかどうか
	  *
	  */
	virtual BOOL is_Skip( T* obj ) = 0;

	/** Viewにチェックインさせる
	  *
	  */
	virtual int checkInView( T* obj ) = 0;

	/** 行動させる
	  *
	  */
	virtual int move( T* obj ) = 0;
	
	/** 地面との当り判定をする
	  * ※落下処理もここで行う。
	  *
	  */
	virtual int checkHitToGround( T* obj ) = 0;
	
	/** ビルボードとの当り判定をする
	  *
	  */
	virtual int checkHitToBillBoard( T* obj ) = 0;
	
	/**  プレイヤーとの当り判定をする
	  *
	  */
	virtual int checkHitToPlayer( T* obj ) = 0;
	
	/**  レンダリングする
	  *  影付き処理をする場合は空にする
	  * 
	  */
	virtual int render( T* obj ) = 0;
	
	/** 次の要素へ行くときの処理
	  *
	  */
	//virtual int next( T* obj, std::list<T*>::iterator& it, std::list<T*>& lst ) = 0;

private:
	/** SigID→オブジェクトの逆引きマップに登録
	  *
	  */
	int set_SigIDToObjectMap( int nSigID, T* obj ) {
		this->m_mapSigIDToObjectMap[ nSigID ] = obj;s
	}
protected:
public:
	int get_ValidNum( int nType ) {
		int num = 0;
		for( std::list<T*>::iterator it = this->m_mapObjectListMap[nType].begin();
			it != this->m_mapObjectListMap[nType].end(); it ++ ) {
			E3DObject* obj = ((E3DObject*)*it);
			if( obj->is_Valid()) {
				num ++;
			}
		}
		return num;
	}
	/*std::map<int, std::list<T*> >* get_ObjectListMap() {
		return this->m_mapObjectListMap;
	}
	std::list<T*>* get_ObjectList( int nType ) {
		return &this->m_mapObjectListMap[nType];
	}*/

};
}
}
#endif
