import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.awt.*;

import javax.swing.JPanel;
import javax.swing.JFrame;

public class pGraphics extends JPanel implements Runnable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	//
	Planner myPlanner;
	int ground;
	// armだけの動作のときはTrue;
	boolean armOnly;
	Arm arm = new Arm("arm", "black", "arm");

	public pGraphics() {
		try {
			JFrame f = new JFrame("Plannner");
			f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			f.getContentPane().add(this);
			f.pack();
			f.setSize(new Dimension(800, 600));
			f.setResizable(false); // リサイズ禁止
			f.setVisible(true);
			// this.start();
		} catch (Exception e) {
			e.printStackTrace();
		}

		Dimension d = getSize();
		int h = (int) d.getHeight();
		ground = h - 100;
	}

	/**
	 * 初期状態の表示
	 * 
	 * @param inits
	 */
	public void initDisp(String[] inits) {
		// handEmptyとclear〜以外をアレーリストに
		ArrayList<String> initsArray = new ArrayList<String>();
		for (String str : inits) {
			if (!(str.startsWith("handEmpty") || str.startsWith("clear")))
				initsArray.add(str);
		}
		// System.out.println(initsArray);
		/*
		 * ontableって定義されてるブロックを全部作ります。 んでinitArrayから削除します。
		 */
		// 削除リスト
		ArrayList<String> del = new ArrayList<String>();
		// 座標定義済みブロックネーム
		ArrayList<String> def = new ArrayList<String>();
		for (String str : initsArray) {
			HashMap<String, String> Binding = new HashMap<String, String>();
			if ((new Unifier()).unify("ontable ?x", str, Binding)) {
				del.add("ontable " + Binding.get("?x"));
				def.add(Binding.get("?x"));
				// new Block(Binding.get("?x"), findEmptyTable(), ground-50,new
				// Color(rnd.nextInt(256),rnd.nextInt(256),rnd.nextInt(256)));
				BlockOp
						.addPos(Binding.get("?x"), findEmptyTable(),
								ground - 50);
			}

		}
		initsArray.removeAll(del);
		// System.out.println(Block.allBlocks.get(0).name);
		del.clear();
		/*
		 * 次はブロックで回して、下から順に組み上げていく
		 */
		// System.out.println(BlockOp.list.get(BlockOp.indexOf(def.get(0))));
		for (int i = 0; i < def.size();) {
			Block bottom = BlockOp.list.get(BlockOp.indexOf(def.get(i)));
			HashMap<String, String> Binding = new HashMap<String, String>();
			for (String str : initsArray) {
				if ((new Unifier()).unify("?x on " + bottom.name, str, Binding)) {
					del.add(Binding.get("?x") + " on " + bottom.name);
					def.add(Binding.get("?x"));
					// new Block(Binding.get("?x"), bottom.x, bottom.y-50,new
					// Color(rnd.nextInt(256),rnd.nextInt(256),rnd.nextInt(256)));
					BlockOp.addPos(Binding.get("?x"), bottom.x, bottom.y - 50);
					i = -1;
				}
			}
			initsArray.removeAll(del);
			del.clear();
			i++;
		}
		this.start("inits");
	}

	/**
	 *初期化
	 */
	public void initSolution(Planner mine) {

		prePC = -1;
		myPlanner = mine;

		this.start("solution");
	}

	/*
	 * public Graphics2D createGraphics2D(int width, int height, BufferedImage
	 * bi, Graphics g) { Graphics2D g2 = bi.createGraphics();
	 * g2.setBackground(Color.WHITE); g2.clearRect(0, 0, width, height); return
	 * g2; }
	 */
	// (note)呼ばれていないみたい
	public void update(Graphics g) {
		paint(g);
	}

	public void paint(Graphics g) {
		Dimension d = getSize();
		int w = (int) d.getWidth();
		int h = (int) d.getHeight();
		super.paint(g); // JPanelのクリア?
		// アーム、ブロック、地面の順に描写
		paintArm(g);
		paintBlock(g);
		paintGround(g, w, h);
	}

	/**
	 * ブロックの描写
	 */
	public void paintBlock(Graphics g) {
		for (Block b : BlockOp.list) {
			if (b.x >= 0) { // xが負のときは初期化がされてないので描写しない
				if (b.shape.equals("triangle")) {
					int xPos[] = { b.x, b.x + 25, b.x + 50 };
					int yPos[] = { b.y + 50, b.y, b.y + 50 };
					g.setColor(b.colorcode);
					g.fillPolygon(xPos, yPos, 3);
					g.setColor(Color.BLACK);
					g.drawString(b.name, b.x + 20, b.y + 25);
				} else if (b.shape.equals("square")) {
					g.setColor(b.colorcode);
					g.fill3DRect(b.x, b.y, 50, 50, true);
					g.setColor(Color.BLACK);
					g.drawString(b.name, b.x + 5, b.y + 15);
				}
			}
		}
	}

	public void paintArm(Graphics g) {
		g.setColor(Color.BLACK);
		// g.fillPolygon(arm.xPos, arm.yPos, 8);
	}

	public void paintGround(Graphics g, int w, int h) {
		g.setColor(Color.PINK);
		// g.draw3DRect(0, h - 100, w, h, false);
		g.fill3DRect(0, ground, w, h, false);
	}

	int prePC;
	int destinationX;
	int destinationY;
	int state = 0; // 0うｐ 1すらいど 2ダウン
	String Blockname; // 動かすブロックの名前

	public int nextState3(int pC) {
		String plan = myPlanner.plan.get(pC).name;
		// リムーブとピックアップは読み飛ばす。
		if (plan.startsWith("remove") || plan.startsWith("pick")) {
			prePC = pC++;
			return pC; // 次のプランへ
		}
		String Bname = null;
		// 新しいプランに入ったときの処理
		if (pC != prePC) {
			Blockname = newDestination(plan);
			prePC = pC;
		}
		// アームのみの動作　ブロックを離す　動くブロックまで移動　掴む
		if (armOnly) {
			Block M = BlockOp.list.get(BlockOp.indexOf(Blockname));
			switch (state) {
			case -1:
				state = arm.release();
				break;
			case 0:
				state = up("arm", M.x, M.y);
				arm.setPosition();
				break;
			case 1:
				state = slide("arm", M.x);
				arm.setPosition();
				break;
			case 2:
				state = down("arm", M.y);
				arm.setPosition();
				break;
			case 3:
				state = arm.grasp();
				break;
			case 4:
				armOnly = false;
				state = 0;
				return pC;
			}
		}
		// ブロックの動作とそれにあわせたアームの動作
		switch (state) {
		case 0:
			state = up(Blockname, destinationX, destinationY);
			break;

		case 1:
			state = slide(Blockname, destinationX);
			break;

		case 2:
			state = down(Blockname, destinationY);
			break;

		case 3:
			state = 0;
			return ++pC;
		}
		prePC = pC;
		return pC;
	}

	/**
	 * 
	 * 新しいプランに入った時の処理
	 * 
	 * @param plan
	 *            処理するプラン
	 * @return　動かすブロックの名前を返す
	 */
	public String newDestination(String plan) {
		HashMap<String, String> Binding = new HashMap<String, String>();
		Binding.clear(); // 以前の束縛情報をクリア
		// すべてのオペレーターとプランをユニファイして変数束縛を取り出す
		for (int opNum = 0; opNum < myPlanner.operators.size(); opNum++) {
			String opName = myPlanner.operators.get(opNum).name;
			if ((new Unifier()).unify(opName, plan, Binding))
				break;
		}
		String nameB = Binding.get("?y");
		// 目的座標を決定する。
		if (nameB == null) {// テーブルの上で開いてる所を探す。
			destinationX = findEmptyTable();
			destinationY = ground - 50;
		} else { // nameBの上に置く
			// Block B = Block.nameToInstance(nameB);
			Block B = BlockOp.list.get(BlockOp.indexOf(nameB));
			destinationX = B.x;
			destinationY = B.y - 50;
		}
		return Binding.get("?x");
	}

	/**
	 * nameAブロックのyをdestinationYの高さまで上げる 通り道に別の高いブロックがあればそれを超える高さまで上げる。
	 * 
	 * @param nameA
	 *            動く奴
	 * @return 完了したらTRUE
	 */

	public int up(String nameA, int desX, int desY) {
		// Block M = Block.nameToInstance(nameA);
		Block M = BlockOp.list.get(BlockOp.indexOf(nameA));

		int top;

		// 通り道上で一番高いブロック
		if (M.x > desX)
			top = topHeight(desX + 50, M.x);
		else
			top = topHeight(M.x + 50, desX);

		// 目的座標と比べる 高い（座標は低い）方に更新
		if (top > (desY + 50))
			top = (desY + 50);
		top = top - 10;// オフセット
		if (top < (M.y + 50)) // 底辺と比べる
			M.y--;

		if (top >= (M.y + 50)) {
			return 1;
		}
		return 0;
	}

	/**
	 * destinationXまで移動する
	 * 
	 * @param top
	 *            移動するやつ
	 * @return 完了したら2
	 */
	public int slide(String top, int desX) {
		// Block M = Block.nameToInstance(top);
		Block M = BlockOp.list.get(BlockOp.indexOf(top));
		if (M.x > desX)
			M.x--;
		if (M.x < desX)
			M.x++;
		if (M.x == desX)
			return 2;

		return 1;
	}

	/**
	 * destinationYまで下ろす
	 * 
	 * @param dw
	 * @return 完了したら3
	 */
	public int down(String dw, int desY) {
		// Block M = Block.nameToInstance(dw);
		Block M = BlockOp.list.get(BlockOp.indexOf(dw));
		if (M.y < desY) {
			M.y++;
			return 2;
		}
		return 3;
	}

	/**
	 * テーブル上で開いてる座標を返す。 初期値はランダム ブロックを順に選び、そいつの右隣があいてればその座標を。
	 * ダメなら左隣。ダメなら次のブロックを選ぶ。
	 * 
	 * @return
	 */
	public int findEmptyTable() {
		Dimension d = getSize();
		int w = (int) d.getWidth();
		Random rnd = new Random();
		// 初期値はRandom
		int cx = rnd.nextInt(w - 50);
		// ブロックがあればその周辺を探す
		for (Block b : BlockOp.list) {
			if (b.x >= 0) {
				cx = b.x + 80; // 右隣が開いてるかつウィンドウの右を超えない
				if (BlockOp.xConflict(cx) && (cx + 50) < w)
					return cx;

				cx = b.x - 80; // 左隣が開いてるかつウィンドウの左を超えない
				if (BlockOp.xConflict(cx) && cx > 0)
					return cx;
			}
		}
		// 見つからない
		return cx;
	}

	/**
	 * 
	 * @param fromXこっから
	 * @param toXここまでの中で
	 * @return 一番高いY座標を返す
	 */
	public int topHeight(int fromX, int toX) {
		int top = ground;
		for (Block b1 : BlockOp.list) {
			if (fromX < b1.x && b1.x < toX) {
				// System.out.print(top);
				// System.out.print(b1.name);
				// System.out.println(b1.y);
				if (b1.y < top) // 低いほうが高いので更新
					top = b1.y;
			}
		}
		return top;
	}

	/*
	 * Runnable
	 */

	Thread thread;
	String type;

	public void start(String typ) {
		if (thread == null) {
			thread = new Thread(this);
			thread.start();
		}
		type = typ;
	}

	public void run() {
		while (!isShowing() || getSize().width == 0) {
			try {
				thread.sleep(200);
			} catch (InterruptedException e) {
			}
		}
		// 解法を描写
		if (type.equals("solution"))
			solution();
		// 初期状態を描写
		if (type.equals("inits"))
			initialize();
	}

	int frameInterval = 10;

	/**
	 * 初期状態描写
	 */
	public void initialize() {
		while (thread != null) {
			repaint();
			thread = null;
			return;
		}
		thread = null;
	}

	/**
	 * 解放の描写
	 */
	public void solution() {
		// プランのカウンター
		int pC = 0;
		while (thread != null) {
			if (pC < myPlanner.plan.size()) {
				pC = nextState3(pC);
				repaint();
				try {
					thread.sleep(frameInterval);
				} catch (InterruptedException e) {
				}
			} else {
				thread = null;
				return;
			}
		}
		thread = null;
	}

}

class Arm extends Block {
	int[] xPos=new int[13] ;
	int[] yPos=new int[13] ;
	Arm(String initName, String initColor, String initShape) {
		super(initName, initColor, initShape);
		this.name = initName;
		this.color = initColor;
		this.shape = initShape;
		this.x = 5;
		this.y = 5;
	
		//Integer xP[] = { x,x,x+5,x+5,x+55,x+55,x+60,x+60 };
		//xPos.toArray(xP);
		//ArrayList<Integer> xPo= new ArrayList<Integer>(xP);
		
		//xPos.addAll(c)
		// int yPos[] = { y,y+55,y+55,y+5,y+5,y+55,y+55,y};
	}
	public void setPosition(){
		
	}
	public int grasp() {
		return 0;

	}

	public int release() {
		return 0;

	}
}