/*!
* @file Field.h
* @brief ゲーム中のダンジョンと付随要素のプロトタイプ
* @date 2013/12/11
* @author Deskull
* 2013 Sikabane Works.
*/

#pragma once

#include "stdafx.h"
#include "Deeangband.h"

#include "Dungeon.h"
#include "GameWorld.h"
#include "GameInstance.h"
#include "Square.h"
#include "Door.h"
#include "TrapBase.h"
#include "Trap.h"
#include "Item.h"

namespace Deeangband
{

	/*!
	 * @class Field
	 * @brief フロアのクラス
	 */
	class Field : public GameInstance
	{
	private:
		std::vector<std::vector<boost::shared_ptr<Square>>> squares; //!<フロアマスの配列
		std::vector<boost::shared_ptr<Creature>> creatures; //!<クリーチャーインスタンスの配列
		std::vector<boost::shared_ptr<Door>> doors; //!<ドアインスタンスの配列
		std::vector<boost::shared_ptr<Trap>> traps; //!<トラップインスタンスの配列
		std::vector<boost::shared_ptr<Item>> items; //!<アイテムインスタンスの配列

		MAP_LENGTH width;  //!< フロアの横サイズ
		MAP_LENGTH height; //!< フロアの縦サイズ
		bool generated; //!< フロア生成済み
		TAG dungeonTag; //!< 生成元ダンジョンタグ
		Dungeon *dungeonPtr; //!< ダンジョンポインタ

		friend class boost::serialization::access;

		/*!
		 * @brief クラスのシリアライズを設定する
		 * @param archive アーカイブ化するクラスのアドレス
		 * @param version ファイルバージョン
		 * @return XMLSerializeテンプレート
		 */
		template<class Archive> void serialize(Archive &archive, const unsigned int version) 
		{
			if(version >= 0)
			{
				archive & boost::serialization::make_nvp("Squares", squares);
				archive & boost::serialization::make_nvp("Doors", doors);
				archive & boost::serialization::make_nvp("Traps", traps);
				archive & boost::serialization::make_nvp("Items", items);
				archive & boost::serialization::make_nvp("Doors", doors);
				archive & boost::serialization::make_nvp("Width", width);
				archive & boost::serialization::make_nvp("Height", height);
			}
		}

		/*! 
		 * @brief 矩形の部屋を生成する
		 * @param leftTop 左上座標
		 * @param rightBottom 右下座標
		 * @return なし
		 */
		void Field::createRectRoom(MAP_LENGTH sx, MAP_LENGTH sy,  MAP_LENGTH ex, MAP_LENGTH ey);
		void Field::createRectRoom(Coordinates& leftTop, Coordinates& rightBottom);

	public:

		/*! 
		 * @brief Fieldクラスコンストラクタ(TAG,Dungeonイテレータからの生成)
		 * @param dungeonPtr 生成元ダンジョンイテレータ
		 * @param depth 生成階層
		 * @details 
		 * 本コンストラクタは、ダンジョン情報と生成階を元にフロアを生成する、恐らく最も実用の機会の多いコンストラクタになる。<br>
		 * <h2>処理の流れ</h2>
		 * <ul>
		 * <li>フロアサイズの決定</li>
		 * <li>外壁地形での全フロア充填</li>
		 * </ul>
		 * @todo Dungeon情報を基にしたコンストラクタの生成を実装
		 */
		Field::Field(std::map<TAG, boost::shared_ptr<Dungeon>>::iterator dungeonIt, DEPTH depth);


		/*! 
		 * @brief Fieldクラスコンストラクタ
		 */
		Field::Field();

		/*!
		* @brief Floorクラスコンストラクタ
		*/
		Field::Field(DEPTH depth);

		/*! 
		 * @brief Fieldクラスデストラクタ
		 * @todo フロアを完全消去する際に、同フロアに配置されるクリーチャー、アイテム、ドア、トラップ類を消去し、ユニーク性のあるものなどについて出現状態を調整すること。
		 */
		Field::~Field();

		/*! 
		 * @brief ダミーデータによる初期化
		 * @return なし
		 */
		void Field::WipeData(void);

		/*!
		 * @brief フロアの横サイズを得る
		 * @return フロアの横サイズ
		 */
		MAP_LENGTH Field::GetWidth(void);

		/*!
		 * @brief フロアの縦サイズを得る
		 * @return フロアの縦サイズ
		 */
		MAP_LENGTH Field::GetHeight(void);

		/*!
		 * @brief フロアのサイズを設定する
		 * @param width フロアの横サイズ
		 * @param height フロアの縦サイズ
		 * @return 処理に成功した場合trueを返す
		 * @todo 変更された場合のフロア配列のリサイズを実装
		 */
		bool Field::SetSize(MAP_LENGTH width, MAP_LENGTH height);

		/*!
		 * @brief フロアの該当座標のマスを返す。
		 * @return 該当するマスインスタンスの参照ポインタ
		 */
		Square *Field::GetSquare(MAP_LENGTH x, MAP_LENGTH y);

		Square *Field::GetSquare(Coordinates &coord);

		/*!
		 * @brief フロアの該当座標にトラップを生成する
		 * @param trapBaseTag 配置するトラップ種別タグ
		 * @param position 配置したい座標
		 * @return 生成に成功した場合trueを返す。
		 * @details
		 * GenerateTrap関数はタグで指示されたトラップ種別のトラップをフロアの所定の位置に配置する。<br>
		 * @todo Field::GenerateTrapの実装
		 */
		bool Field::GenerateTrap(std::map<TAG, boost::shared_ptr<TrapBase>>::iterator trapBaseIt, Coordinates *position);

		/*!
		 * @brief 指定地点からの視界を返す
		 * @param coordVec 視点を返すVectorの参照渡し
		 * @param rad 基本半径
		 * @param baseX 視点元X座標
		 * @param baseY 視点元Y座標
		 * @return なし
		 */
		void Field::GetSight(std::vector<bool> &coordVec, MAP_LENGTH size, MAP_LENGTH baseX, MAP_LENGTH baseY);

		/*!
		 * @brief 視界が通っているかの判定を行う
		 * @param bx 基点X座標
		 * @param by 基点Y座標
		 * @param tx 目標X座標
		 * @param ty 目標Y座標
		 * @return 視界が通っている場合trueを返す。
		 */
		bool Field::HaveSight(MAP_LENGTH bx, MAP_LENGTH by, MAP_LENGTH tx, MAP_LENGTH ty);

		/*!
		 * @brief 視界判定基準のための四隅フラグを全て更新する。
		 * @return なし
		 */
		void Field::UpdateSight(void);

		std::vector<bool> SightPass; //!< 四隅視覚通過フラグ
		std::vector<bool> PhysicalPass; //!< 四隅物理通過フラグ

		/*!
		 * @brief 指定地点の視界通過状態を返す。
		 * @param x 指定地点X座標
		 * @param y 指定地点Y座標
		 * @return 通過できるならばTRUE
		 */
		bool Field::GetSightPass(MAP_LENGTH x, MAP_LENGTH y);

		/*!
		 * @brief 指定地点からのばら撒き座標を返す。
		 * @param x 指定地点X座標
		 * @param y 指定地点Y座標
		 * @param distance 限界距離
		 * @return 計算結果の座標、指定不能ならばNULL
		 */
		Coordinates* Field::Scatter(MAP_LENGTH y, MAP_LENGTH x, MAP_LENGTH distance);

		/*!
		 * @brief ランダムに河川状の地形を一つ追加する。
		 * @param floor1_ptr 浅い床情報
		 * @param floor2_ptr 深い床座標
		 * @return 成功したらTRUE
		 */
		bool Field::AddRiver(Floor *floor1_ptr, Floor *floor2_ptr);

	};

}

BOOST_CLASS_VERSION(Deeangband::Field, 10);
