/* Copyright (C) 2016  Otsuki Tomoshi <tomoshi@m00.itscom.net> */
#include <stdio.h>
#include <stdarg.h>
#include <direct.h>
#include "go.h"


const char* X_CORD = { "-ABCDEFGHJKLMNOPQRST-\0" };
const char* (Y_CORD[BOARD_EDGE_SIZE + 2]) = { "-",
	 "1",    "2",  "3",   "4",  "5",  "6",  "7",  "8",  "9", "10",  "11",  "12", "13",  "14", "15", "16", "17", "18", "19"
};

void send_gtp(const char* fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	vfprintf(stdout, fmt, ap);  // 標準出力に書き出す
	va_end(ap);
}

// 相手の手を受信 "play W D17" のように来る
int get_receive_pos(int* tbn, char* str)
{
	int pos_x = 0, pos_y = 0, x, y, y2;

	if (!strncmp(&str[5], "W", 1)) {
		*tbn = TBN_WH;
	}
	else if (!strncmp(&str[5], "B", 1)) {
		*tbn = TBN_BK;
	}
	else {
		fprintf(stderr, "tbn_err\n");
	}
	for (x = 1; x <= BOARD_EDGE_SIZE; x++) {
		if (!strncmp(&str[7], &X_CORD[x], 1)) {
			pos_x = x;
			break;
		}
	}

	for (y = 1; y <= 9; y++) { /* 1 keta me */
		if (!strncmp(&str[8], Y_CORD[y], 1)) {
			if (y == 1) {
				for (y2 = 10; y2 <= 19; y2++) {  /* 2 keta me */
					if (!strncmp(&str[8], Y_CORD[y2], 2)) {
						y = y2;
						break;
					}
				}
			}
			pos_y = BOARD_EDGE_SIZE + 1 - y;
			break;
		}
	}

	fprintf(stderr, "x = %d, y = %d\n", pos_x, pos_y);
	return X_Y_TO_POS(pos_x, pos_y);
}


int gtp(game_hdl_t* hdl)
{
	char str[FRAME];
	goban_t* ban = hdl->ban;

	// stdoutをバッファリングしないように。GTPで通信に失敗するので。
	//setvbuf(stdout, NULL);
    // 修正: setvbuf 関数には 3 つの引数が必要です。  
    setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);  // stderrに書くとGoGuiに表示される。
	while (1) {
		writeBan(ban);

		fprintf(stderr, "  NOW: tesuu: %d, tbn: %.1s,  (PREV): ", ban->tesuu, &COLOR_NAME[TBN2COLOR(ban->tbn)]);
		outPos(ban->histInfo[ban->tesuu - 1].pos), fprintf(stderr, "\n");

		if (fgets(str, FRAME, stdin) == NULL) break;  // 標準入力から読む

		if (strstr(str, "boardsize")) {
			send_gtp("= \n\n");    // "boardsize 19": 19路盤
			if (atoi(&str[10]) != BOARD_EDGE_SIZE) {
				fprintf(stderr, "illegal boardsize (%d != %d)\n", atoi(&str[10]), BOARD_EDGE_SIZE);
			}
			fprintf(stderr, "if you write in stderr, output into gogui\n");
		}
		else if (strstr(str, "clear_board")) {
			set_initial_pos(ban);
			send_gtp("= \n\n");
		}
		else if (strstr(str, "komi")) {
			ban->komi = atof(&str[5]);
			fprintf(stderr, "komi = %f\n", ban->komi);
			send_gtp("= \n\n");
		}
		else if (strstr(str, "undo")) {
			if (ban->tesuu >= 3) {
				unmake_move(ban);
				unmake_move(ban);
			}
			send_gtp("= \n\n");
		}
		else if (strstr(str, "name")) {
			send_gtp("= deltaGo\n\n");
		}
		else if (strstr(str, "protocol_version")) {
			send_gtp("= 2\n\n");
		}
		else if (strstr(str, "version")) {
			send_gtp("= 1.0.0\n\n");
		}
		else if (strstr(str, "genmove w") || strstr(str, "genmove b")) {
			int x, y, pos;
			double pos2prob[XY_SIZE];
			fprintf(stderr, "I'm thinking... \n");
			double time_s = Tool_GetTimeNow();

			get_feature(NULL, 0, ban->tesuu - 1, ban);
			pos = get_cnn_prob(ban, hdl, pos2prob);
			if (pos == 0) {
				fprintf(stderr, "PASS\n\n");
				send_gtp("= PASS\n\n");
			}
			else {
				x = POS_TO_X(pos);
				y = POS_TO_Y(pos);
				fprintf(stderr, "%.1s%s\n\n", &X_CORD[x], Y_CORD[y]);
				send_gtp("= %.1s%s\n\n", &X_CORD[x], Y_CORD[BOARD_EDGE_SIZE + 1 - y]);
			}
			outPos(pos);
			fprintf(stderr, "\ntime = %f\n", Tool_GetTimeNow() - time_s);
			make_move(pos, ban);
		}
		else if (strstr(str, "play")) { // 相手の手を受信 "play W D17" のように来る
			int tbn;
			int pos = get_receive_pos(&tbn, str);
			if (tbn == ban->tbn) {
				make_move(pos, ban);
			}
			else {  // 置き碁の場合?はPASSを挿入
				make_move(0, ban);
				make_move(pos, ban);
			}
			send_gtp("= \n\n");
		}
		else {
			send_gtp("= \n\n");  // それ以外のコマンドにはOKを返す
		}
	}
	return 0;
}

int main(int argc, char** argv)
{
	game_hdl_t* hdl;
	if ((hdl = open_game_hdl(argc, argv)) == NULL) {
		fprintf(stderr, "open game_hdl error\n");
		return 0;
	}
	// read cnn parameter
	FILE* fp_in;
	errno_t err = fopen_s(&fp_in, "paramter.bin", "rb");
	if (err != 0) {
		fprintf(stderr, "file open error: %s\n", "paramter.bin");
		char path[260];
		if (_getcwd(path, sizeof(path)) != NULL) {
			printf("カレントディレクトリ: %s\n", path);
		}
		else {
			perror("getcwd");
		}
		return 1;
	}
	fread(cnn_param, sizeof(cnn_t), sizeof(parameter_t) / sizeof(cnn_t), fp_in);
	gtp(hdl);
	return 0;
}

