module yamalib.draw.floatingrectdraw;

private import y4d;
private import yamalib.counterfsp;
private import yamalib.apartregion;

/**
　矩形分割し、浮遊状態から
　復元する
*/
class FloatingRectDraw {
	
	/// 対象テクスチャをセットします
	void setTexture(Texture tex_) {
		// セットするテクスチャがnullっておかしいやん
		assert( !(tex_ is null) );
		
		texture = tex_;
	}
	
	/// 描画位置の設定
	void setXY(int x_, int y_ ) {
		posx = x_;
		posy = y_;
	}
	
	/// 描画位置の取得
	void getXY(out int x_, out int y_) {
		x_ = posx;
		y_ = posy;
	}
	
	/// 移動角度を設定しする
	void setRad(int rad_) {
		rad = rad_ % 512;
	}
	
	/// 開始拡大率の設定
	void setStartRate(float rate) {
		startRate = rate;
	}
	
	/// 設定されたテクスチャを元に divX, divY のサイズに分解します
	void divide(int divX, int divY) {
		// テクスチャ設定されてないやん
		if (texture is null) return;
		
		int tx = cast(int) texture.getWidth();
		int ty = cast(int) texture.getHeight();
		
		int sx = tx / divX;
		int sy = ty / divY;

		// サンプルとする矩形二次元配列を作る
		Rect[][] rcSample = new Rect[][sy];
		foreach (inout Rect[] rcs; rcSample[]) {
			rcs = new Rect[sx];
		}
		
		// サンプリング枠となる矩形データを作る
		for (int i = 0; i < sy; ++i) {
			for (int j = 0; j < sx; ++j) {
				rcSample[i][j].left = j * divX;
				rcSample[i][j].right = rcSample[i][j].left + divX;
				rcSample[i][j].top = i * divY;
				rcSample[i][j].bottom = rcSample[i][j].top + divY;
			}
		}
		
		// FloatingRect オブジェクトの生成
		foreach (Rect[] rectLine; rcSample) {
			foreach( Rect rc; rectLine) {
				FloatingRect obj = new FloatingRect();
				obj.setTexture(texture, rc);
				generateFloatingRect(obj, 100, 10, 10, 10);
				// 追加
				drawObj.push_back( obj );
			}
		}	
	}
	
	/// 毎回呼び出すなり
	void onMove(Screen screen) {
		foreach ( inout FloatingRect obj; drawObj ) {
			obj.onMove(screen);
		}
	}
	
	///  毎回呼び出すなり
	void onDraw(Screen screen) {
		foreach (inout FloatingRect obj; drawObj) {
			obj.onDraw(screen);
		}		
	}
	
	/// 描画処理が終了したか
	bool isFinish() {
		if (drawObj is null) return false;
		
		foreach (inout FloatingRect obj; drawObj) {
			if ( !obj.isFinish() ) {
				return false;
			}
		}
		return true;
	}
	
	/// コンストラクタ
	this() {
		rad = -1;	// ランダム拡散をデフォルトにする
	}
	
	/// 静的コンストラクタ
	static this() {
		rand = new Rand();
		rand.randomize();
		sin = SinTable.get();
	}
	
	/**
		一つの矩形を表すクラス
	*/
	class FloatingRect {
	public :
		/// 毎回呼び出すなり
		void onMove(Screen screen) {
			if (finish) return;
			
			// 動作
			dx++;
			dy++;
			rateCounter++;
			
			// 処理おわったんか？
			if (dx.isEnd() && dy.isEnd() && rateCounter.isEnd()) {
				finish = true;
			}
		}
		
		/// 毎回呼び出すなり
		void onDraw(Screen screen) {
			if (texture is null) return;
			
			float rate = cast(float) rateCounter.get();
			// スケーリング戻し
			rate /= SCALING_NUM;
			
			// 描画
			screen.bltRotate( texture,
				posx + dx.get(),
				posy + dy.get(),
				&srcRc,
				0,
				rate,
				cast(int) (srcRc.getWidth()/2),
				cast(int) (srcRc.getHeight()/2)
			);
		}
		
		/// 全体テクスチャの設定とその描画範囲設定
		void setTexture(Texture tex_, Rect rc) {
			assert( !(tex_ is null) );
			texture = tex_;
			srcRc = rc;
		}
		
		/// 基準位置（最終描画位置）の設定
		void setXY(int x_, int y_) {
			posx = x_;
			posy = y_;
		} 
		
		/// x移動カウンタの取得
		InteriorCounter getDxCounter() {
			return dx;
		}
		
		/// y移動カウンタの取得
		InteriorCounter getDyCounter() {
			return dy;
		}
		
		/// 拡大レートカウンタの取得
		InteriorCounter getRateCounter() {
			return rateCounter;
		}
		
		/// 基準位置の取得
		void getXY(out int x_, out int y_) {
			x_ = posx;
			y_ = posy;
		}
		
		/// 処理終了したんか？
		bool isFinish() {
			return finish;
		}
		
		/// コンストラクタ
		this() {
			dx = new InteriorCounter();
			dy = new InteriorCounter();
			rateCounter = new InteriorCounter();
		}
		
	private :
		static const int SCALING_NUM = 256;	//!< スケーリング数
	
		Texture texture;
		int posx;	//!< 基準点x
		int posy;	//!< 基準点y
		Rect srcRc; //!< 描画範囲矩形
		InteriorCounter dx;	//!< 開始点から終点
		InteriorCounter dy; //!< 開始点から終点
		InteriorCounter rateCounter;	//!< 拡大率
		bool finish;
	} // FloatingRect

private:

	/// FlotingRectの構築処理
	void generateFloatingRect(inout FloatingRect fr, int distance, int rndRangeX, int rndRangeY, float rndRangeRate) {
		assert ( !(fr is null) );
		
		const int step = 100;
		
		// 移動開始点を求める
		int x = sin.cos(rad, distance) + (rand.get(rndRangeX) - (rndRangeX/2));
		int y = sin.sin(rad, distance) + (rand.get(rndRangeY) - (rndRangeY/2));
		int startRateScal = cast(int) ( (startRate+rndRangeRate) * SCALING_NUM );
		
		fr.setXY(posx, posy);
		
		// x,y,rate
		fr.getDxCounter().set( x + posx, posx, step );
		fr.getDyCounter().set( y + posy, posy, step );
		fr.getRateCounter().set( startRateScal, SCALING_NUM, step);
	}
	
private:
	static const int SCALING_NUM = 256;	//!< スケーリング数
	static Rand rand;	//!< 汎用乱数生成クラス
	static SinTable sin;
	
	int rad;	//!< 角度
	int posx;	//!< テクスチャの描画位置
	int posy;
	float startRate = 0.0f;	//!< 開始拡大率
	bool finish;	//!< 描画処理が終了したか
	vector!(FloatingRect) drawObj;	//!< 表示する矩形のリスト
	Texture texture;	//!< 対象テクスチャ
		
}
