package org.test.wuziqi;

import loon.LSystem;
import loon.LTexture;
import loon.Screen;
import loon.canvas.Canvas;
import loon.canvas.Image;
import loon.canvas.LColor;
import loon.component.LComponent;
import loon.component.LPanel;
import loon.component.LToast;
import loon.events.ClickListener;
import loon.events.SysTouch;
import loon.font.IFont;
import loon.geom.PointI;
import loon.opengl.GLEx;
import loon.utils.MathUtils;
import loon.utils.processes.RealtimeProcess;
import loon.utils.timer.LTimerContext;

public class GobangPanel extends LPanel {
	
	private ComputurTask task = null; // 自动任务
	private LToast toast = null; // 提示信息
	private final int OFFSET = 40;// 棋盘偏移
	private final int CELL_WIDTH = 40;// 棋格宽度
	private int computerSide = Chess.BLACK;// 默认机器持黑
	private int humanSide = Chess.WHITE;
	private int cx = WuziBoard.CENTER, cy = WuziBoard.CENTER;
	private boolean isShowOrder = false;// 显示落子顺序
	private int[] lastStep;// 上一个落子点
	private WuziBoard bd;// 棋盘，重要
	private Brain br;// AI，重要
	public static final int MANUAL = 0;// 双人模式
	public static final int HALF = 1;// 人机模式
	public static final int AUTO = 2;// 双机模式
	public static final int EVAL = 3;// 估值函数
	public static final int TREE = 4;// 估值函数+搜索树
	private int mode;// 模式
	private int intel;// 智能
	private boolean isGameOver = true;

	// 显示落子顺序
	public void troggleOrder() {
		isShowOrder = !isShowOrder;
	}

	// 悔棋
	public void undo() {
		PointI p = bd.undo();
		if (p != null) {
			lastStep[0] = p.x;
			lastStep[1] = p.y;
		}
	}

	public GobangPanel() {
		super(0, 0, 650, 650);

		lastStep = new int[2];

		this.setBackground(LColor.orange);

		bd = new WuziBoard();

		this.customRendering = false;

		SetClick(new ClickListener() {

			@Override
			public void UpClick(LComponent comp, float x, float y) {
				// TODO Auto-generated method stub

			}

			@Override
			public void DragClick(LComponent comp, float x, float y) {

			}

			@Override
			public void DownClick(LComponent comp, float x1, float y1) {

				if (isGameOver) {
					showMessage("请开始新游戏！");
					return;
				}
				int x = MathUtils.round((x1 - OFFSET) * 1.0f / CELL_WIDTH) + 1;
				int y = MathUtils.round((y1 - OFFSET) * 1.0f / CELL_WIDTH) + 1;
				if (cx >= 1 && cx <= WuziBoard.BOARD_SIZE && cy >= 1
						&& cy <= WuziBoard.BOARD_SIZE) {
					if (mode == MANUAL) {// 双人

						putChess(x, y);
					} else if (mode == HALF) {// 人机

						if (bd.getPlayer() == humanSide) {

							if (putChess(x, y)) {
								Log.debug("\n----白棋完毕----");
								if (intel == EVAL) {
									int[] bestStep = br.findOneBestStep();// 估值函数AI
									putChess(bestStep[0], bestStep[1]);
								} else if (intel == TREE) {
									int[] bestStep = br.findTreeBestStep();// 估值函数+搜索树AI
									putChess(bestStep[0], bestStep[1]);
								}
								Log.debug("\n----黑棋完毕----");
							}

						}
					}
				}

			}

			@Override
			public void DoClick(LComponent comp) {
				// TODO Auto-generated method stub

			}
		});
	}

	@Override
	public void createUI(GLEx g, int x1, int y1, LComponent component,
			LTexture[] buttonImage) {
		// 保存原始画笔
		g.saveBrush();
		// 画棋盘
		drawBoard(g);
		// 画天元和星
		drawStar(g, WuziBoard.CENTER, WuziBoard.CENTER);
		drawStar(g, (WuziBoard.BOARD_SIZE + 1) / 4,
				(WuziBoard.BOARD_SIZE + 1) / 4);
		drawStar(g, (WuziBoard.BOARD_SIZE + 1) / 4,
				(WuziBoard.BOARD_SIZE + 1) * 3 / 4);
		drawStar(g, (WuziBoard.BOARD_SIZE + 1) * 3 / 4,
				(WuziBoard.BOARD_SIZE + 1) / 4);
		drawStar(g, (WuziBoard.BOARD_SIZE + 1) * 3 / 4,
				(WuziBoard.BOARD_SIZE + 1) * 3 / 4);
		// 画数字和字母
		drawNumAndLetter(g);
		// 画提示框
		drawCell(g, cx, cy, 0);

		if (!isGameOver) {
			// 画所有棋子
			for (int x = 1; x <= WuziBoard.BOARD_SIZE; ++x) {
				for (int y = 1; y <= WuziBoard.BOARD_SIZE; ++y) {
					drawChess(g, x, y, bd.getData()[x][y].getSide());
				}
			}
			// 画顺序
			if (isShowOrder)
				drawOrder(g);
			else {
				if (lastStep[0] > 0 && lastStep[1] > 0) {
					g.setColor(LColor.red);
					g.fillRect((lastStep[0] - 1) * CELL_WIDTH + OFFSET
							- CELL_WIDTH / 10, (lastStep[1] - 1) * CELL_WIDTH
							+ OFFSET - CELL_WIDTH / 10, CELL_WIDTH / 5,
							CELL_WIDTH / 5);

				}
			}
		}
		// 还原画笔
		g.restoreBrush();
	}

	private LTexture boardTexture;

	// 画棋盘
	private void drawBoard(GLEx g) {
		if (boardTexture == null) {
			Image img = Image.createImage(width(), height());
			Canvas cs = img.getCanvas();
			cs.setColor(LColor.black);
			cs.setStrokeWidth(2f);
			for (int x = 0; x < WuziBoard.BOARD_SIZE; ++x) {
				cs.drawLine(x * CELL_WIDTH + OFFSET, OFFSET, x * CELL_WIDTH
						+ OFFSET, (WuziBoard.BOARD_SIZE - 1) * CELL_WIDTH
						+ OFFSET);

			}
			for (int y = 0; y < WuziBoard.BOARD_SIZE; ++y) {
				cs.drawLine(OFFSET, y * CELL_WIDTH + OFFSET,
						(WuziBoard.BOARD_SIZE - 1) * CELL_WIDTH + OFFSET, y
								* CELL_WIDTH + OFFSET);

			}
			boardTexture = img.texture();
			img.close();
		}
		g.draw(boardTexture, 0, 0);
	}

	// 画天元和星
	private void drawStar(GLEx g, int cx, int cy) {
		g.fillOval((cx - 1) * CELL_WIDTH + OFFSET - 4, (cy - 1) * CELL_WIDTH
				+ OFFSET - 4, 8, 8);
	}

	// 画数字和字母
	private void drawNumAndLetter(GLEx g) {
		IFont fm = g.getFont();
		float stringWidth, stringAscent;
		stringAscent = -fm.getAscent();
		for (int i = 1; i <= WuziBoard.BOARD_SIZE; i++) {

			String num = String.valueOf(WuziBoard.BOARD_SIZE - i + 1);
			stringWidth = fm.stringWidth(num);
			g.drawString(String.valueOf(WuziBoard.BOARD_SIZE - i + 1), OFFSET
					/ 4 - stringWidth / 2, OFFSET + (CELL_WIDTH * (i - 1))
					+ stringAscent / 2);

			String letter = String.valueOf((char) (64 + i));
			stringWidth = fm.stringWidth(letter);
			g.drawString(String.valueOf((char) (64 + i)), OFFSET
					+ (CELL_WIDTH * (i - 1)) - stringWidth / 2, OFFSET * 3 / 4
					+ OFFSET + CELL_WIDTH * (WuziBoard.BOARD_SIZE - 1)
					+ stringAscent / 2);
		}
	}

	// 画棋子
	private void drawChess(GLEx g, int cx, int cy, int player) {
		if (player == 0)
			return;
		int size = CELL_WIDTH * 5 / 6;
		g.setColor(player == Chess.BLACK ? LColor.black : LColor.white);
		g.fillOval((cx - 1) * CELL_WIDTH + OFFSET - size / 2, (cy - 1)
				* CELL_WIDTH - size / 2 + OFFSET, size, size);
	}

	// 画预选框
	private void drawCell(GLEx g, int x, int y, int c) {// c 是style
		int length = CELL_WIDTH / 4;
		int xx = (x - 1) * CELL_WIDTH + OFFSET;
		int yy = (y - 1) * CELL_WIDTH + OFFSET;
		int x1, y1, x2, y2, x3, y3, x4, y4;
		x1 = x4 = xx - CELL_WIDTH / 2;
		x2 = x3 = xx + CELL_WIDTH / 2;
		y1 = y2 = yy - CELL_WIDTH / 2;
		y3 = y4 = yy + CELL_WIDTH / 2;
		g.setColor(LColor.red);
		g.drawLine(x1, y1, x1 + length, y1);
		g.drawLine(x1, y1, x1, y1 + length);
		g.drawLine(x2, y2, x2 - length, y2);
		g.drawLine(x2, y2, x2, y2 + length);
		g.drawLine(x3, y3, x3 - length, y3);
		g.drawLine(x3, y3, x3, y3 - length);
		g.drawLine(x4, y4, x4 + length, y4);
		g.drawLine(x4, y4, x4, y4 - length);
	}

	// 画落子顺序
	private void drawOrder(GLEx g) {
		int[][] history = bd.getHistory();
		if (history.length > 0) {
			g.setColor(LColor.red);
			for (int i = 0; i < history.length; i++) {
				int x = history[i][0];
				int y = history[i][1];
				String text = String.valueOf(i + 1);
				// 居中
				IFont fm = g.getFont();
				int stringWidth = fm.stringWidth(text);
				float stringAscent = -fm.getAscent();
				g.drawString(text, (x - 1) * CELL_WIDTH + OFFSET - stringWidth
						/ 2, (y - 1) * CELL_WIDTH + OFFSET + stringAscent / 2);
			}
		}
	}

	// 开始游戏
	public void startGame(int mode, int intel, int level, int node) {
		Screen.removeProcess(task);
		// 清除
		bd.reset();
		isGameOver = true;
		this.mode = mode;
		this.intel = intel;
		bd.reset();
		lastStep[0] = lastStep[1] = WuziBoard.CENTER;
		br = new Brain(bd, level, node);
		bd.start();
		isGameOver = false;
		showMessage("游戏开始！");
		if (mode == AUTO) {// 双机
			task = new ComputurTask();
			task.setDelay(LSystem.SECOND);
			Screen.addProcess(task);
		}

	}

	@Override
	public void update(long t) {
		if (contains(SysTouch.getX(), SysTouch.getY())) {
			int tx = MathUtils.round((SysTouch.getX() - OFFSET) * 1.0f / CELL_WIDTH) + 1;
			int ty = MathUtils.round((SysTouch.getY() - OFFSET) * 1.0f / CELL_WIDTH) + 1;
			if (tx >= 1 && tx <= WuziBoard.BOARD_SIZE && ty >= 1
					&& ty <= WuziBoard.BOARD_SIZE) {
				cx = tx;
				cy = ty;
			}
		}
	}

	private boolean putChess(int x, int y) {
		if (bd.putChess(x, y)) {
			lastStep[0] = x;// 保存上一步落子点
			lastStep[1] = y;
			int winSide = bd.isGameOver();// 判断终局
			if (winSide > 0) {
				if (winSide == humanSide) {
					showMessage("白方赢了！");
				} else if (winSide == computerSide) {
					showMessage("黑方赢了！");
				} else {
					showMessage("双方平手");
				}

				// 清除
				bd.reset();
				isGameOver = true;
				return false;
			}

			return true;
		}
		return false;

	}

	public void showMessage(String mes) {
		if (toast != null) {
			getScreen().remove(toast);
		}
		getScreen().add(toast = LToast.makeText(mes, LToast.Style.ERROR));
	}

	// 双机
	private class ComputurTask extends RealtimeProcess {

		@Override
		public void run(LTimerContext time) {

			int[] bestStep = br.findTreeBestStep();
			if (!putChess(bestStep[0], bestStep[1])) {
				this.kill();
			}

		}

	}
}