module yamalib.draw.scatteredtexture;

private import y4d;
private import std.math;
private import yamalib.counterfsp;
private import yamalib.apartregion;
private import yamalib.log.log;

/**
	テクスチャを分解して、ばらばらに落下していくイメージを
	作ります。
*/
class ScatteredTexture {
	
		/** 
		壊れるオブジェクト
		１クラスで１パーティクル
	  */
	class BreakObject {
		Texture t;
		Rect rect;	//!< 描画範囲
		int posx;	//!< 描画位置
		int posy;	//!< 描画位置
		int maxSize; //!< 自分の最大サイズ（矩形の斜辺長）
		bool death;
		bool enable;	//!< 分解されるオブジェクトであるか

		RootCounter angle;	//!< 回転速度
		RootCounterS dx;	//!< 移動量
		RootCounterS dy;	//!< 移動量
		
		/// このオブジェクトを明示的に殺す
		void kill() {
			death = true;
		}

		/// 単純オブジェクトの動作
		void onMove() {

			if (death) return;

			dx++;
			dy++;
			angle++;
			posx += dx.get();
			posy += dy.get();

			if (posx<-maxSize || posx > 640+maxSize) {
				death = true;
				return;
			}
			if (posy<-maxSize || posy > 480+maxSize) {
				death = true;
				return;
			}
		}
		
		/// 単純オブジェクトの描画
		void onDraw(Screen screen) {
			if (death) return;

			int height = cast(int)(rect.getHeight()/2);
			int width =  cast(int)(rect.getWidth()/2);
			screen.bltRotate(t, posx, posy, &rect, angle.get(), 1.0f, width, height);
		}
		
		/// コンストラクタ
		this() {
			angle = new RootCounter;
			angle.set(0,0,1);
			dx = new RootCounterS;
			dx.set(0,0,1);
			dy = new RootCounterS;
			dy.set(0,0,1);
			enable = true;
		}

		/// デストラクタ
		~this() {
			death = false;
			posx = 0;
			posy = 0;
		}
	}
	

	/// 分解するテクスチャ
	void setTexture(Texture t_) {
		tex = t_;
	}

	/// 表示位置
	void setXY(int x,int y) {
		posx = x;
		posy = y;
	}

	/// 待機時間の設定
	void setWaitCount(uint u) {
		waitCount = u;
	}

	/// フェードの設定
	void setFade(bool fade_,int step=4) {
		fade = fade_;
		fadeStep = step;
		alpha.set(255,0,step);
	}

	/// 現在の対象テクスチャの取得
	Texture getTexture() {
		return tex;
	}

	/// 分解待機状態か
	bool isWait() {
		return cast(bool) (waitCount > 0);
	}

	/// 終了したか
	bool isFinish() {
		return finish;
	}

	/// 分解描画中
	bool isBreaking() {
		return cast(bool) (waitCount==0);
	}

	/// 状態のクリア
	void clear() {
		object = null;
		finish = false;
		alpha.set(255, 0, fadeStep);
	}
	
	/// マスクデータを使用し、sx, sy単位で分割を行う
	/*
		アルファ付きサーフェイスから、アルファを参照し、非０の座標を有効な
		部分を判定し、分割する
	*/
	void divisionTextureWithSurface(inout Surface surface, int divWidth, int divHeight) {
		if (surface is null) return;
		
		RectF[][] rects;
		RectF[] rect1Dim;
		// 分割矩形を取得
		rects = ApartRegion.apartFromTexture(surface, divWidth, divHeight);

		assert( !(rects is null) );
		
		rect1Dim = ApartRegion.uniteRect(rects, 3, 10);
		
		Log.print("divResult : %s \n", rect1Dim.length);
		
		// 矩形を巡回し、パーティクルを生成する
		foreach (inout RectF rc; rect1Dim) {
			BreakObject bo = new BreakObject();
			setBreakObjAttribute(bo, rc.getWidth(), rc.getHeight(), rc.left, rc.top);
			bo.enable = rc.enable;
			object ~= bo;
		}
	}

	/// column × row に分割する
	void divisionTexture(int column,int row) {
		if (tex is null) return;
		object = null;

		int width = cast(int) tex.getWidth();
		int height = cast(int) tex.getHeight();
		float aWidth = width / column;
		float aHeight = height / row;
		
		for(float w=0.0f,h=0.0f; ; ) {
			BreakObject bo = new BreakObject;
			
			// 単位矩形の指定から、BreakObjectの属性を設定する
			setBreakObjAttribute(bo, aWidth, aHeight, w, h);

			object ~= bo;

			w += aWidth;
			if(!(cast(int)w<width)) {
				w = 0.0f;
				h += aHeight;
				if (cast(int)h>height) break;
			}
		}
	}
	
	/// 内部パーティクル情報の取得
	BreakObject[] getObjectInfo() {
		return object;
	}

	/// 毎回呼び出すなり
	void onMove(Screen screen) {
		if (waitCount > 0) {
			waitCount--;
			return;
		}

		if (finish) return;

		if (fade) alpha++;

		bool invoke = false;
		foreach (BreakObject o;object) {
			if (!o.death && o.enable) {
				o.onMove();
				invoke = true;
			}
		}

		if (!invoke) {
			finish = true;
		}
	}

	/// 毎回呼び出すなり
	void onDraw(Screen screen) {
		if (finish) return;
		if (fade) {
			screen.setColor(255,255,255,alpha.get());
		}
		foreach (int i,inout BreakObject o;object) {
			if (!o.death)
				o.onDraw(screen);
		}
		if (fade) {
			screen.resetColor();
		}
	}

	/// コンストラクタ
	this() {
		alpha = new RootCounterS;
		alpha.set(0,0,1);
	}
	
	/// 静的コンストラクタ
	static this() {
		rand = new Rand();
		rand.randomize();
	}
	

protected:

	/// 初期化処理
	void onInit() {
	}
	
	/** BreakObject の属性を設定する
	 *  @param 	bo			設定するBreakObject
	 *  @param unitWidth	単位幅
	 	@param unitHeight	単位高
	 	@param w			走査位置、ｘ
	 	@param h			走査位置、y	
	 */
	void setBreakObjAttribute(inout BreakObject bo, float unitWidth, float unitHeight, float w, float h) {
		// 自身全体画像の幅
		int width = cast(int) tex.getWidth();
		// 自身全体画像の高さ
		int height = cast(int) tex.getHeight();
		// 符号変数
		int abs = 1;
		// 飛び散る係数
		float keisu = 1.0f;

		// 底辺を求める
		float bottom = h + unitHeight;
		
		// 底辺が画像高さを超えている場合は修正する
		if ( cast(int) bottom > height ) {
			bottom = height;
		}
		
		// テクスチャのセット
		bo.t = tex;

		// 矩形の設定
		bo.rect.left = w;
		bo.rect.top = h;
		bo.rect.right = bo.rect.left+unitWidth;
		bo.rect.bottom = bottom;

		// 斜辺の長さを求める
		float wid = bo.rect.getWidth();
		float hei = bo.rect.getHeight();

		bo.maxSize = cast(int)sqrt(wid*wid+hei*hei);

		// アトリビュートの設定
		bo.posx = posx + cast(int)bo.rect.left;
		bo.posy = posy + cast(int)bo.rect.top;

		// 自分の位置が画像の左に位置するならば
		if ( cast(int)w < (width / 2) ) {
			abs = -1;
			wid = bo.rect.left - width/2;
			keisu = wid/(width/2);
		} else {
			abs = 1;
			wid = width/2 - bo.rect.left;
			keisu = wid/(width/2);
		}

		//----- 散らばる処理アトリビュート -----
		// 横方向の移動		
		int xStart = ( 3 + rand.get(3) ) * abs;
		int xStep = -( 12 + rand.get(5) );

		// 下方向の移動
		int yEnd = 4 + rand.get(2);
		int yStep = -( 5 + rand.get(5) );
		
		// 角回転速度
		int angleStep = 5 + rand.get(15);

		bo.dx.set(xStart, 0, xStep);
		bo.dy.set(0, yEnd, yStep);
		bo.angle.set(0, 511, angleStep);
	}

		


protected:
	static const int ANGLE_RAND = 5;
	static const int X_RAND = 3;
	static const int Y_RAND = 5;
	static Rand rand;

	bool init;
	bool finish;
	Texture tex;

	bool fade;
	int fadeStep;
	RootCounterS alpha;

	uint waitCount;

	int posx;
	int posy;
	BreakObject[] object;

}
