package com.haru.tetoru.parts;


public class RotateRule {

	private static final int CANDIDATE_NUM = 5;
	private static final int STATE_NUM = 4;

	private enum Dir {
		_(0, 0),
		L(-1, 0),
		R(1, 0),
		U(0, -1),
		D(0, 1),
		LU(-1, -1),
		RU(1, -1),
		LD(-1, 1),
		RD(1, 1),
		D2(0, 2),
		U2(0, -2),
		RD2(1, 2),
		LD2(-1, 2),
		RU2(1, -2),
		LU2(-1, -2),
		L2(-2, 0),
		R2(2, 0),
		L2D(-2, 1),
		R2U(2, -1),
		R2D(2, 1),
		L2U(-2, -1);

		private int x;
		private int y;

		private Dir(int x, int y) {
			this.x = x;
			this.y = y;
		}

		public Point get() {
			return new Point(x, y);
		}
	};
	

	//	初期状態
	//	右回転	 基本回転	 左1	 左1上1	 下2	 左1下2
	//	左回転	 基本回転	 右1	 右1上1	 下2	 右1下2
	//	右90度回転状態
	//	右回転	 基本回転	 右1	 右1下1	 上2	 右1上2
	//	左回転	 基本回転	 右1	 右1下1	 上2	 右1上2
	//	180度回転状態
	//	右回転	 基本回転	 右1	 右1上1	 下2	 右1下2
	//	左回転	 基本回転	 左1	 左1上1	 下2	 左1下2
	//	左90度回転状態
	//	右回転	 基本回転	 左1	 左1下1	 上2	 左1上2
	//	左回転	 基本回転	 左1	 左1下1	 上2	 左1上2
	private static Dir[][][] tblOther = { /* new Dir[NUM][STATE_NUM][DEMENSION] */
		/* 第1候補 */
		{
			{Dir._, Dir._}, /* 初期状態 {右回転, 左回転} */
			{Dir._, Dir._}, /* 右90度回転状態 */
			{Dir._, Dir._}, /* 180度回転状態 */
			{Dir._, Dir._}  /* 左90度回転状態 */
		},
		/* 第2候補 */
		{
			{Dir.L, Dir.R}, /* 初期状態 {右回転, 左回転} */
			{Dir.R, Dir.R}, /* 右90度回転状態 */
			{Dir.R, Dir.L}, /* 180度回転状態 */
			{Dir.L, Dir.L}  /* 左90度回転状態 */
		},
		/* 第3候補 */
		{
			{Dir.LU, Dir.RU}, /* 初期状態 {右回転, 左回転} */
			{Dir.RD, Dir.RD}, /* 右90度回転状態 */
			{Dir.RU, Dir.LU}, /* 180度回転状態 */
			{Dir.LD, Dir.LD}  /* 左90度回転状態 */
		},
		/* 第4候補 */
		{
			{Dir.D2, Dir.D2}, /* 初期状態 {右回転, 左回転} */
			{Dir.U2, Dir.U2}, /* 右90度回転状態 */
			{Dir.D2, Dir.D2}, /* 180度回転状態 */
			{Dir.U2, Dir.U2}  /* 左90度回転状態 */
		},
		/* 第5候補 */
		{
			{Dir.LD2, Dir.RD2}, /* 初期状態 {右回転, 左回転} */
			{Dir.RU2, Dir.RU2}, /* 右90度回転状態 */
			{Dir.RD2, Dir.LD2}, /* 180度回転状態 */
			{Dir.LU2, Dir.LU2}  /* 左90度回転状態 */
		},
	};

	/* Tミノの場合、第3候補の初期状態と180度回転状態はパス */
	private static Dir[][][] tblT = {
		/* 第1候補 */
		{
			{Dir._, Dir._}, /* 初期状態 {右回転, 左回転} */
			{Dir._, Dir._}, /* 右90度回転状態 */
			{Dir._, Dir._}, /* 180度回転状態 */
			{Dir._, Dir._}  /* 左90度回転状態 */
		},
		/* 第2候補 */
		{
			{Dir.L, Dir.R}, /* 初期状態 {右回転, 左回転} */
			{Dir.R, Dir.R}, /* 右90度回転状態 */
			{Dir.R, Dir.L}, /* 180度回転状態 */
			{Dir.L, Dir.L}  /* 左90度回転状態 */
		},
		/* 第3候補 */
		{
			{Dir._, Dir._},   /* 初期状態 {右回転, 左回転} */
			{Dir.RD, Dir.RD}, /* 右90度回転状態 */
			{Dir._, Dir._},   /* 180度回転状態 */
			{Dir.LD, Dir.LD}  /* 左90度回転状態 */
		},
		/* 第4候補 */
		{
			{Dir.D2, Dir.D2}, /* 初期状態 {右回転, 左回転} */
			{Dir.U2, Dir.U2}, /* 右90度回転状態 */
			{Dir.D2, Dir.D2}, /* 180度回転状態 */
			{Dir.U2, Dir.U2}  /* 左90度回転状態 */
		},
		/* 第5候補 */
		{
			{Dir.LD2, Dir.RD2}, /* 初期状態 {右回転, 左回転} */
			{Dir.RU2, Dir.RU2}, /* 右90度回転状態 */
			{Dir.RD2, Dir.LD2}, /* 180度回転状態 */
			{Dir.LU2, Dir.LU2}  /* 左90度回転状態 */
		},
	};

	/* Iミノは特殊 */
	//	初期状態
	//	右回転	 基本回転	 左2	 右1	 左2下1	 右1上2
	//	左回転	 基本回転	 左1	 右2	 左1上2	 右2下1
	//	右90度回転状態
	//	右回転	 基本回転	 左1	 右2	 左1上2	 右2下1
	//	左回転	 基本回転	 右2	 左1	 右2上1	 左1下2
	//	180度回転状態
	//	右回転	 基本回転	 右1	 左2	 右1下2	 左2上1
	//	左回転	 基本回転	 右2	 左1	 右2上1	 左1下2
	//	左90度回転状態
	//	右回転	 基本回転	 右1	 左2	 右1下2	 左2上1
	//	左回転	 基本回転	 左2	 右1	 左2下1	 右1上2
	private static Dir[][][] tblI = {
		/* 第1候補 */
		{
			{Dir._, Dir._}, /* 初期状態 {右回転, 左回転} */
			{Dir._, Dir._}, /* 右90度回転状態 */
			{Dir._, Dir._}, /* 180度回転状態 */
			{Dir._, Dir._}  /* 左90度回転状態 */
		},
		/* 第2候補 */
		{
			{Dir.L2, Dir.L}, /* 初期状態 {右回転, 左回転} */
			{Dir.L, Dir.R2}, /* 右90度回転状態 */
			{Dir.R, Dir.R2}, /* 180度回転状態 */
			{Dir.R, Dir.L2}  /* 左90度回転状態 */
		},
		/* 第3候補 */
		{
			{Dir.R, Dir.R2}, /* 初期状態 {右回転, 左回転} */
			{Dir.R2, Dir.L}, /* 右90度回転状態 */
			{Dir.L2, Dir.L}, /* 180度回転状態 */
			{Dir.L2, Dir.R}  /* 左90度回転状態 */
		},
		/* 第4候補 */
		{
			{Dir.L2D, Dir.LU2}, /* 初期状態 {右回転, 左回転} */
			{Dir.LU2, Dir.R2U}, /* 右90度回転状態 */
			{Dir.RD2, Dir.R2U}, /* 180度回転状態 */
			{Dir.RD2, Dir.L2D}  /* 左90度回転状態 */
		},
		/* 第5候補 */
		{
			{Dir.RU2, Dir.R2D}, /* 初期状態 {右回転, 左回転} */
			{Dir.R2D, Dir.LD2}, /* 右90度回転状態 */
			{Dir.L2U, Dir.LD2}, /* 180度回転状態 */
			{Dir.L2U, Dir.RU2}  /* 左90度回転状態 */
		},
	};


	/**
	 * 回転法則に従って、中心の移動方向を取得する。
	 * 詳しくはSRS(スーパーローテーションシステム)で検索。
	 * @param i 候補(range from 1 to 5)
	 * @param type ミノ種類
	 * @param turn 回転前の回転状態
	 * @param dr 回転の方向
	 * @return
	 */
	public static Point moveDirection(int candidate, int type, int turn, int dr) {
		/* 引数チェック */
		if (1 > candidate || CANDIDATE_NUM < candidate) {
			return new Point(-1, -1);
		}

		/* turnの補正(引数チェックしない代わり) */
		turn = turn % STATE_NUM;

		/* 回転の方向を添字に変換 */
		int idxDr = (Mino.R_RIGHT == dr) ? 0 : 1;


		/* 移動方向テーブルを取得 */
		Dir[][][] tbl = 
				(Block.I == type) ? tblI :
				(Block.T == type) ? tblT 
								  : tblOther; 

		return tbl[candidate - 1][turn][idxDr].get();
	}
}
