module yamalib.hexpropagate;

private import std.date;
private import y4d;
private import ytl.vector;
private import yamalib.log.log;


/// 隣接しているHexのフラグ
struct HexFlag {
	struct Wall {
		bool w = true;
		bool b = false;
	}

	Wall[6] wall;
	bool show = false;
}

/** Hex内を移動するオブジェクトの基底クラス */
abstract class HexExplorer {

	enum {a,b,c,d,e,f};

	/// static 縦×横の大きさの設定
	static void setHexSize(int x,int y) {
		int i,j,sx,sy;
		hex = new HexFlag[][y];
		for (i = 0; i<hex[].length; ++i) {
			hex[i] = new HexFlag[x];
		}

		// 上辺を固める
		for (i=0; i<hex[0].length; ++i) {
			hex[0][i].wall[a].b = true;
			hex[0][i].wall[b].b = true;
		}

		// 左辺を固める
		for (i=0; i<hex.length; ++i) {
			hex[i][0].wall[a].b = true;
		    hex[i][0].wall[e].b = true;
			hex[i][0].wall[f].b = true;
		}

		// 下辺を固める
		sy = hex.length-1;
		for (i=0; i<hex[sy].length; ++i) {
			hex[sy][i].wall[d].b = true;
			hex[sy][i].wall[e].b = true;
		}

		// 右辺を固める
		sx = hex[0].length-1;
		for (i=0; i<hex.length; ++i) {
			hex[i][sx].wall[b].b = true;
			hex[i][sx].wall[c].b = true;
			hex[i][sx].wall[d].b = true;
		}
	}

	/// static 状態の初期化
	static void reset() {
		int i,sx,sy,x,y;
		for (y=0; y<hex.length; ++y) {
			for (x=0; x<hex[y].length; ++x) {
				hex[y][x].show = false;
				hex[y][x].wall[a].w = true;
				hex[y][x].wall[b].w = true;
				hex[y][x].wall[c].w = true;
				hex[y][x].wall[d].w = true;
				hex[y][x].wall[e].w = true;
				hex[y][x].wall[f].w = true;
			}
		}
	}

	/// static 構築中のHexFlagを返す
	static HexFlag[][] getHexFlag() {
		return hex;
	}

protected:
	static HexFlag[][] hex;		//!< ＨＥＸの状態をあらわす配列
	HexFlag* hf;
}

/***
  HexMapを破壊していく破壊子
 **/
class HexDeletor : HexExplorer{
	/// 次を探査し移動する
	bool searchNext() {
		if (route.size() == 0) return false;

		int num;

CONTINUE:;
		hf = &(hex[y][x]);
		num = 0;

		if (!hf.wall[a].w && !hf.wall[a].b) {
			num++;
		}
		if (!hf.wall[b].w && !hf.wall[b].b) {
			num++;
		}
		if (!hf.wall[c].w && !hf.wall[c].b) {
			num++;
		}
		if (!hf.wall[d].w && !hf.wall[d].b) {
			num++;
		}
		if (!hf.wall[e].w && !hf.wall[e].b) {
			num++;
		}
		if (!hf.wall[f].w && !hf.wall[f].b) {
			num++;
		}
		if (num == 0) {
			// 破壊完了　新しい地域を探す
			int i,j;
			bool found = false;
			if (route.size() == 0) {
				for(i=0; i<hex[].length; ++i) {
					for(j=0; j<hex.length; ++j) {
						if (hex[j][i].show) {
							found = true;
							break;
						}
					}
				}
			}

			if (found) {
				x = j;
				y = i;
				Point tmp;
				tmp.x = x;
				tmp.y = y;
				route.push_back(tmp);
				goto CONTINUE;
			} else {
				return false;
			}

			Point pt = route.pop_back();
			x = cast(int)pt.x;
			y = cast(int)pt.y;
			goto CONTINUE;
		}

		int rnd = rand.get(num);
		if (!hf.wall[0].w && !hf.wall[a].b) {
			if (rnd == 0) {
				if (!go2a()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (!hf.wall[b].w && !hf.wall[b].b) {
			if (rnd == 0) {
				if (!go2b()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (!hf.wall[c].w && !hf.wall[c].b) {
			if (rnd == 0) {
				if (!go2c()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (!hf.wall[d].w && !hf.wall[d].b) {
			if (rnd == 0) {
				if (!go2d()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (!hf.wall[e].w && !hf.wall[e].b) {
			if (rnd == 0) {
				if (!go2e()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (!hf.wall[f].w && !hf.wall[f].b) {
			if (rnd == 0) {
				if (!go2f()) {
					goto CONTINUE;
				}
			}
		}

		// 移動経路をpush
		Point tmp;
		tmp.x = x;
		tmp.y = y;
		route.push_back(tmp);

		return true;
	}

	/// 現在地の設定
	void setPos(int x,int y) {
		if (y >= hex.length) y = hex.length - 1;
		if (x >= hex[y].length) x = hex[y].length - 1;

		this.x = x; this.y = y;
		Point tmp;
		tmp.x = x;
		tmp.y = y;
		route.push_back(tmp);
	}
	
	/// リセット
	void clear() {
		route = new vector!(Point);
		Point tmp;
		tmp.x = 0;
		tmp.y = 0;
		route.push_back(tmp);
	}
	
	/// コンストラクタ
	this() {
		rand = new Rand();
		rand.randomize();
		route = new vector!(Point);
		Point tmp;
		tmp.x = 0;
		tmp.y = 0;
		route.push_back(tmp);
	}

private:
	bool go2a() {
		// 自身のaを壊す
		hex[y][x].wall[a].w = true;
		y = y - 1;
		if ((y%2)==0) {
			x = x - 1;
		}
		// 移動先のdを壊す
		hex[y][x].wall[d].w = true;

		if (!hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = false;
			return true;
		}
	}
	bool go2b() {
		// 自身のbを壊す
		hex[y][x].wall[b].w = true;
		y = y - 1;
		if ((y%2) != 0) {
			x = x + 1;
		}

		// 移動先のeを壊す
		hex[y][x].wall[e].w = true;

		if (!hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = false;
			return true;
		}
	}
	bool go2c() {
		// 自身のcを壊す
		hex[y][x].wall[c].w = true;
		x = x + 1;

		// 移動先のfを壊す
		hex[y][x].wall[f].w = true;

		if (!hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = false;
			return true;
		}
	}
	bool go2d() {
		// 自身のdを壊す
		hex[y][x].wall[d].w = true;
		y = y + 1;
		if ((y%2) != 0) {
			x = x + 1;
		}

		// 移動先のaを壊す
		hex[y][x].wall[a].w = true;

		if (hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = false;
			return true;
		}
	}
	bool go2e() {
		// 自身のeを壊す
		hex[y][x].wall[e].w = true;
		y = y + 1;
		if ((y%2)==0) {
			x = x - 1;
		}

		// 移動先のbを壊す
		hex[y][x].wall[b].w = true;

		if (!hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = false;
			return true;
		}
	}
	bool go2f() {
		// 自身のfを壊す
		hex[y][x].wall[f].w = true;
		x = x - 1;

		// 移動先のcを壊す
		hex[y][x].wall[c].w = true;

		if (!hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = false;
			return true;
		}
	}

protected:
	vector!(Point) route;		//!< 探査中の経路
	int x,y;					//!< 探査子の位置
	Rand rand;
}

/**
   HexMapを探査していく探査子
*/
class HexSearcher : HexExplorer {
	/// 次を探査し移動する
	bool searchNext() {
		if (route.size() == 0) return false;

		int num;

CONTINUE:;
		HexFlag* hf = &(hex[y][x]);
		num = 0;

		if (hf.wall[a].w && !hf.wall[a].b) {
			num++;
		}
		if (hf.wall[b].w && !hf.wall[b].b) {
			num++;
		}
		if (hf.wall[c].w && !hf.wall[c].b) {
			num++;
		}
		if (hf.wall[d].w && !hf.wall[d].b) {
			num++;
		}
		if (hf.wall[e].w && !hf.wall[e].b) {
			num++;
		}
		if (hf.wall[f].w && !hf.wall[f].b) {
			num++;
		}
		if (num == 0) {
			// 行くべきところがない

			// 描画完了
			if (route.size() == 0) return false;

			char[512] buf;
			Point pt = route.pop_back();
			Log.print("POP-remain:%s\n", route.size());
			x = cast(int)pt.x;
			y = cast(int)pt.y;
			goto CONTINUE;
		}

		int rnd = rand.get(num);
		if (hf.wall[a].w && !hf.wall[a].b) {
			if (rnd == 0) {
				if (!go2a()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (hf.wall[b].w && !hf.wall[b].b) {
			if (rnd == 0) {
				if (!go2b()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (hf.wall[c].w && !hf.wall[c].b) {
			if (rnd == 0) {
				if (!go2c()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (hf.wall[d].w && !hf.wall[d].b) {
			if (rnd == 0) {
				if (!go2d()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (hf.wall[e].w && !hf.wall[e].b) {
			if (rnd == 0) {
				if (!go2e()) {
					goto CONTINUE;
				}
			}
			--rnd;
		}
		if (hf.wall[f].w && !hf.wall[f].b) {
			if (rnd == 0) {
				if (!go2f()) {
					goto CONTINUE;
				}
			}
		}

		// 移動経路をpush
		Point tmp;
		tmp.x = x;
		tmp.y = y;
		route.push_back(tmp);

		return true;
	}

	/// 現在地の設定
	void setPos(int x,int y) {
		if (y >= hex.length) y = hex.length - 1;
		if (x >= hex[y].length) x = hex[y].length - 1;

		this.x = x; this.y = y;
		Point tmp;
		tmp.x = x;
		tmp.y = y;
		route.push_back(tmp);
	}

	/// リセット
	void clear() {
		route = new vector!(Point);
		Point tmp;
		tmp.x = 0;
		tmp.y = 0;
		route.push_back(tmp);
	}
	
	this() {
		rand = new Rand();
		rand.randomize();
		route = new vector!(Point);
		Point tmp;
		tmp.x = 0;
		tmp.y = 0;
		route.push_back(tmp);
	}

private:
	bool go2a() {
		// 自身のaを壊す
		hex[y][x].wall[a].w = false;
		y = y - 1;
		if ((y%2)==0) {
			x = x - 1;
		}
		// 移動先のdを壊す
		hex[y][x].wall[d].w = false;

		if (hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = true;
			return true;
		}
	}
	bool go2b() {
		// 自身のbを壊す
		hex[y][x].wall[b].w = false;
		y = y - 1;
		if ((y%2) != 0) {
			x = x + 1;
		}

		// 移動先のeを壊す
		hex[y][x].wall[e].w = false;

		if (hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = true;
			return true;
		}
	}
	bool go2c() {
		// 自身のcを壊す
		hex[y][x].wall[c].w = false;
		x = x + 1;

		// 移動先のfを壊す
		hex[y][x].wall[f].w = false;

		if (hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = true;
			return true;
		}
	}
	bool go2d() {
		// 自身のdを壊す
		hex[y][x].wall[d].w = false;
		y = y + 1;
		if ((y%2) != 0) {
			x = x + 1;
		}

		// 移動先のaを壊す
		hex[y][x].wall[a].w = false;

		if (hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = true;
			return true;
		}
	}
	bool go2e() {
		// 自身のeを壊す
		hex[y][x].wall[e].w = false;
		y = y + 1;
		if ((y%2)==0) {
			x = x - 1;
		}

		// 移動先のbを壊す
		hex[y][x].wall[b].w = false;

		if (hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = true;
			return true;
		}
	}
	bool go2f() {
		// 自身のfを壊す
		hex[y][x].wall[f].w = false;
		x = x - 1;

		// 移動先のcを壊す
		hex[y][x].wall[c].w = false;

		if (hex[y][x].show) {
			return false;
		} else {
			hex[y][x].show = true;
			return true;
		}
	}

protected:
	vector!(Point) route;		//!< 探査中の経路
	int x,y;					//!< 探査子の位置
	Rand rand;
}


/**
   ヘックスが増殖して描画されるクラス
*/
class HexPropagate {

	/// 画像のセット
	void setTextureLoader(TextureLoader tex,int no) {
		tl = tex;
		tno = no;
		tx = cast(int)tl.get(no).getWidth();
		ty = cast(int)tl.get(no).getHeight();
	}

	void setHexSize(int x,int y) {
		for (int i; i < searcher.length; ++i) {
			searcher[i].setHexSize(x,y);
			searcher[i].setPos(rnd.get(x), rnd.get(y));
		}
		del.setHexSize(x,y);
		del.setPos(20,20);
		hexX = x;
		hexY = y;
	}

	/// 状態のクリア
	void clear(bool bRandPos=false) { 
		HexSearcher.reset(); 
		
		foreach ( inout HexSearcher hs; searcher ) {
			hs.clear();
			if (bRandPos) {				
				hs.setPos( rnd.get(hexX), rnd.get(hexY) );
			}
		}
	}

	/// 毎回呼び出すナリ
	void onDraw(Screen screen) {
		if (tl == null) return;

		count++;

		HexFlag[][] hex = HexSearcher.getHexFlag();

		for (int i; i < searcher.length; ++i) {
			searcher[i].searchNext();
		}

		if (count > 1000) {
			del.searchNext();
		}

		int x,y,ox,sy;
		// 次行の高さ
		sy = cast(int)((ty/4.0f)*3);
		for (y=0; y<hex.length; ++y) {
			if (y%2) ox = tx/2;
			else 	 ox = 0;
			for (x=0; x<hex[y].length; ++x) {
				if (hex[y][x].show) {
					screen.blt(tl.get(tno),tx*x+ox,sy*y);
				}
			}
		}
	}

	/// コンストラクタ
	this() {
		searcher = new HexSearcher[1];
		searcher[0] = new HexSearcher;
		del = new HexDeletor;
		count = 0;
	}
	
	/// 静的コンストラクタ
	static this() {
		rnd = new Rand();
		rnd.randomize();
	}
	
protected:
	static Rand rnd;

	TextureLoader tl;			//!< テクスチャローダ
	Texture t;					//!< ヘックスの画像
	int hexX;
	int hexY;
	uint count;					//!< ループ回数
	int tx,ty;					//!< テクスチャのサイズ
	int tno;					//!< テクスチャナンバ
	uint flamecounter;			//!< フレームカウンタ
	HexSearcher[] searcher;		//!< 探査子
	HexDeletor	del;			//!< 破壊子
}


