/*
 * server.js
 * Created by 还有醋v on 2021/6/10.
 * Copyright © 2021 haiyoucuv. All rights reserved.
 */

const ws = require("nodejs-websocket");
console.log("开始创建服务...");


/**
 * 棋盘
 * @type {number}
 */
const mapData = [
	[0, 0, 0],
	[0, 0, 0],
	[0, 0, 0],
];

/**
 *  当前颜色，0 啥也没有， 1 白棋， 2 黑棋
 */
let curColor = 1;

let whitePlayer = null;   // 白棋玩家
let blackPlayer = null;   // 黑棋玩家

/**
 * 重设
 */
function reset() {
	for (let row = 0; row < 3; row++) {
		for (let col = 0; col < 3; col++) {
			mapData[row][col] = 0;
		}
	}
	curColor = 1;
}

/**
 * 判断输赢和
 */
function judge() {
	let draw = mapData[0][0];
	for (let i = 0; i < 3; i++) {
		let rowColor = mapData[i][0]; // 计算横竖输赢
		let colColor = mapData[0][i];
		draw *= mapData[i][0] * mapData[0][i];  // 计算和棋
		for (let j = 1; j < 3; j++) {
			rowColor &= mapData[i][j];    // 计算横竖输赢
			colColor &= mapData[j][i];
			draw *= mapData[i][j] * mapData[j][i];  // 计算和棋
		}

		if (rowColor || colColor) {
			return gameOver(rowColor || colColor);
		}
	}

	// 计算斜线输赢
	const x1 = mapData[0][0] & mapData[1][1] & mapData[2][2];
	const x2 = mapData[2][0] & mapData[1][1] & mapData[0][2];
	if (x1 || x2) {
		return gameOver(x1 || x2);
	}

	// 判断是否和棋
	draw && gameOver(0);
}

/**
 * 游戏结束
 * @param {number} flag 结束标志 0 和棋， 1 白棋赢， 2 黑棋赢
 */
function gameOver(flag) {
	broadcastJson({ type: "gameOver", flag });
	reset();
}


// 坐下
function sitDown(conn, data) {
	const { color } = data;
	if (color !== 1 && color !== 2) return;

	// 已经有人了啥也不做
	if (
		(color === 1 && whitePlayer)
		|| (color === 2 && blackPlayer)
	) return;

	// 已经有人了啥也不做 如果已经在座位则先下座
	conn === whitePlayer && (whitePlayer = null);
	conn === blackPlayer && (blackPlayer = null);


	color === 1 ? (whitePlayer = conn) : (blackPlayer = conn);
	broadcastRoom();
}

// 坐下
function standUp(conn, data) {
	const { color } = data;
	if (color !== 1 && color !== 2) return;

	color === 1 ? (whitePlayer = null) : (blackPlayer = null);
	broadcastRoom();
}

function chess(conn, data) {
	const { color, row, col } = data;
	if (color !== curColor) return;
	if ((conn === whitePlayer && color !== 1)) return;
	if ((conn === blackPlayer && color !== 2)) return;

	mapData[row][col] = curColor;
	curColor = 3 - curColor;
	judge();
	broadcastRoom();
}


function broadcastRoom() {
	broadcastJson({
		type: "roomData",
		onlineCount: server.connections.length,
		white: whitePlayer ? whitePlayer.key : null,
		black: blackPlayer ? blackPlayer.key : null,
		mapData, curColor
	});
}

const server = ws.createServer((conn) => {

	console.log(conn.key + "建立连接");

	sendJson(conn, { type: "init", userId: conn.key });

	broadcastRoom();

	conn.on("text", (msg) => {
		const data = JSON.parse(msg);
		const type = data.type;

		switch (type) {
			case "sitDown":
				sitDown(conn, data);
				break;

			case "standUp":
				standUp(conn, data);
				break;

			case "chess":
				chess(conn, data);
				break;
		}
	});

	// 关闭连接
	conn.on("close", (code, reason) => {
		console.log(conn.key + "关闭连接");
		if (conn === whitePlayer) {
			whitePlayer = null;
		} else if (conn === blackPlayer) {
			blackPlayer = null;
		}
		broadcastRoom();
	});

	// 异常关闭
	conn.on("error", (code, reason) => {
		console.log(conn.key + "异常关闭");
		if (conn === whitePlayer) {
			whitePlayer = null;
		} else if (conn === blackPlayer) {
			blackPlayer = null;
		}
		broadcastRoom();
	});

});


/**
 * 广播JSON格式数据
 * @param data
 */
function broadcastJson(data) {
	const msg = JSON.stringify(data);
	server.connections.forEach((conn) => {
		conn.sendText(msg);
	});
}

/**
 * 发送Json格式的消息
 * @param conn
 * @param {Object} data
 */
function sendJson(conn, data) {
	conn.send(JSON.stringify(data));
}


/**
 * 广播
 * @param {string} msg
 */
function broadcast(msg) {
	server.connections.forEach((conn) => {
		conn.sendText(msg);
	});
}

server.listen(3001, "0.0.0.0", () => {
	console.log("服务启动完毕");
});

