/// BulletML を実行する
/**
 * 使い方：
 * BulletMLRunner を継承していくつかの純粋仮想関数を実装する。
 */

#ifndef BULLETRUNNER_H_
#define BULLETRUNNER_H_

#include "bulletmltree.h"
#include "bulletmlcommon.h"

#include <vector>
#include <boost/smart_ptr.hpp>

class BulletMLParser;
class BulletMLNode;
class BulletMLRunnerImpl;

typedef std::vector<double> BulletMLParameter;

/// BulletMLRunner が状態伝達に使用するクラス
class BulletMLState {
public:
	DECLSPEC BulletMLState(BulletMLParser* bulletml,
						   const std::vector<BulletMLNode*>& node,
						   boost::shared_ptr<BulletMLParameter> para)
		: bulletml_(bulletml), node_(node.begin(), node.end()), para_(para) {}

	DECLSPEC BulletMLParser* getBulletML() { return bulletml_; }
	DECLSPEC const std::vector<BulletMLNode*>& getNode() const { return node_; }
	DECLSPEC boost::shared_ptr<BulletMLParameter> getParameter() { return para_; }

private:
	BulletMLParser* bulletml_;
	std::vector<BulletMLNode*> node_;
	boost::shared_ptr<BulletMLParameter> para_;

};

/// BulletML を実行するクラス
/**
 * <pre>
 * 使い方。
 *  1. これを継承して、Bullet を実際に動かせるクラスを作る。
 *  2. 純粋仮想関数を全て実装する。
 *  3. 必要なら、changeDirection などのために必要な仮想関数を実装する。
 *  4. このクラスのオブジェクトに対して、com_->run(); などとする。
 * </pre>
 */

class BulletMLRunner {
public:
	DECLSPEC explicit BulletMLRunner(BulletMLParser* bulletml);
    DECLSPEC explicit BulletMLRunner(BulletMLState* state);
    DECLSPEC virtual ~BulletMLRunner();

	/// 実行する
    DECLSPEC void run();

public:
	/// 実行が終了しているかどうか
	DECLSPEC bool isEnd() const;

public:
	// ----- 絶対実装しなければならない関数群の始まり -----
	//@{
	/// この弾の角度を求める
	/**
	 * @return 角度を度単位で、上方向 0 で時計周りで返す
	 */
	DECLSPEC virtual double getBulletDirection() =0;
	/// この弾から自機を狙う角度を求める
	/**
	 * @return 角度を度単位で、上方向 0 で時計周りで返す
	 */
	DECLSPEC virtual double getAimDirection() =0;
	/// この弾の速度を求める
	DECLSPEC virtual double getBulletSpeed() =0;
	/// デフォルトの速度を求める
	DECLSPEC virtual double getDefaultSpeed() =0;
	/// ランクを求める
	/**
	 * @return 0 から 1 までの実数
	 */
	DECLSPEC virtual double getRank() =0;
	/// action を持たない弾を作る
	DECLSPEC virtual void createSimpleBullet(double direction, double speed) =0;
	/// action を持つ弾を作る
	/**
	 * @param state
	 * 新しい弾の BulletMLRunner のコンストラクタに渡すこと。
	 * もし渡さないのであれば、delete で解放しなければならない。
	 */
	DECLSPEC virtual void createBullet(BulletMLState* state,
									   double direction, double speed) =0;
	/// 弾の基準となるターンの値を返す、通常はフレーム数
	/**
	 * @return
	 * ゲームごとの基準でオーダーは変更して構いませんが、
	 * 負数は許されません。
	 * xml データ上で、wait と term のオーダーが揃っていれば問題ありません。
	 */
	DECLSPEC virtual int getTurn() =0;
	/// 死ぬ
	DECLSPEC virtual void doVanish() =0;
	//@}
	// ----- 絶対実装しなければならない関数群の終わり -----

	// ----- 必要があれば実装する関数群の始まり -----
   	//@{
	/// 弾の方向を指定した方向に変更する
	DECLSPEC virtual void doChangeDirection(double) {}
	/// 弾の速度を指定した値に変更する
	DECLSPEC virtual void doChangeSpeed(double) {}
	/// accel に対するインターフェイス
	/**
	 * @todo
	 * horizontal, vertical の type は未実装です。
	 * どれも absolute になってしまいます。
	 */
	DECLSPEC virtual void doAccelX(double) {}
	/// accel に対するインターフェイス
	/**
	 * @todo
	 * horizontal, vertical の type は未実装です。
	 * どれも absolute になってしまいます。
	 */
	DECLSPEC virtual void doAccelY(double) {}
	/// 弾の速さの X 方向成分を返します
	/**
	 * accel を使う場合はオーバーライドして下さい
 	 */
	DECLSPEC virtual double getBulletSpeedX() { return 0; }
	/// 弾の速さの Y 方向成分を返します
	/**
	 * accel を使う場合はオーバーライドして下さい
 	 */
	DECLSPEC virtual double getBulletSpeedY() { return 0; }
    //@}
	// ----- 必要があれば実装する関数群の終わり -----

	/// 乱数を返す
	/**
	 * 見てのとおり、デフォルトでは std::rand が用いられます。
	 */
	DECLSPEC virtual double getRand() { return (double)rand() / RAND_MAX; }

private:
	/// BulletMLRunnerImpl をオーバーライドする場合、これもオーバーライドする
	DECLSPEC virtual BulletMLRunnerImpl* makeImpl(BulletMLState* state);

protected:
	std::vector<BulletMLRunnerImpl*> impl_;

};

#endif // ! BULLETRUNNER_H_

