/******************************************************************************
 *                                                                            *
 *    This file is part of Kokopu, a JavaScript chess library.                *
 *    Copyright (C) 2018-2022  Yoann Le Montagner <yo35 -at- melix.net>       *
 *                                                                            *
 *    This program is free software: you can redistribute it and/or           *
 *    modify it under the terms of the GNU Lesser General Public License      *
 *    as published by the Free Software Foundation, either version 3 of       *
 *    the License, or (at your option) any later version.                     *
 *                                                                            *
 *    This program is distributed in the hope that it will be useful,         *
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 *    GNU Lesser General Public License for more details.                     *
 *                                                                            *
 *    You should have received a copy of the GNU Lesser General               *
 *    Public License along with this program. If not, see                     *
 *    <http://www.gnu.org/licenses/>.                                         *
 *                                                                            *
 ******************************************************************************/


'use strict';


var bt = require('./basetypes');
var exception = require('./exception');
var impl = require('./private_position/impl');


/**
 * Execute the given callback on each of the 64 squares.
 *
 * @param {function(Square)} callback
 */
exports.forEachSquare = function(callback) {
	for(var rank=0; rank<8; ++rank) {
		for(var file=0; file<8; ++file) {
			callback(bt.squareToString(rank * 16 + file));
		}
	}
};


/**
 * Return the color of a square.
 *
 * @param {Square} square
 * @returns {Color}
 */
exports.squareColor = function(square) {
	square = bt.squareFromString(square);
	if(square < 0) {
		throw new exception.IllegalArgument('squareColor()');
	}
	return Math.floor(square/16) % 2 === square % 2 ? 'b' : 'w';
};


/**
 * Return the coordinates of a square.
 *
 * @param {Square} square
 * @returns {{rank: number, file: number}} The `rank` and `file` fields have the same meaning as in {@link coordinatesToSquare}.
 */
exports.squareToCoordinates = function(square) {
	square = bt.squareFromString(square);
	if(square < 0) {
		throw new exception.IllegalArgument('squareToCoordinates()');
	}
	return { rank:Math.floor(square/16), file:square%16 };
};


/**
 * Return the square corresponding to the given coordinates.
 *
 * @param {number} file `0` for file A, `1` for file B, ..., `7` for file H.
 * @param {number} rank `0` for the first rank, ..., `7` for the eighth rank.
 * @returns {Square}
 * @throws {exception.IllegalArgument} If either `file` or `rank` is not between 0 and 7 (inclusive).
 */
exports.coordinatesToSquare = function(file, rank) {
	if(file<0 || file>=8 || rank<0 || rank>= 8) {
		throw new exception.IllegalArgument('coordinatesToSquare()');
	}
	return bt.fileToString(file) + bt.rankToString(rank);
};


/**
 * Change white to black, and black to white.
 *
 * @param {Color} color
 * @returns {Color}
 */
exports.oppositeColor = function(color) {
	color = bt.colorFromString(color);
	if (color < 0) {
		throw new exception.IllegalArgument('oppositeColor()');
	}
	return bt.colorToString(1 - color);
};


/**
 * Whether the given variant has a canonical start position or not.
 *
 * @param {GameVariant} variant
 * @returns {boolean}
 */
exports.variantWithCanonicalStartPosition = function(variant) {
	variant = bt.variantFromString(variant);
	if (variant < 0) {
		throw new exception.IllegalArgument('oppositeColor()');
	}
	return impl.variantWithCanonicalStartPosition(variant);
};


var NAG_SYMBOLS = {
	/* eslint-disable no-mixed-spaces-and-tabs */
	  1: '!',       // good move
	  2: '?',       // bad move
	  3: '!!',      // very good move
	  4: '??',      // very bad move
	  5: '!?',      // interesting move
	  6: '?!',      // questionable move
	  7: '\u25a1',  // Only move
	  8: '\u25a1',  // Only move (ChessBase)
	 10: '=',       // equal position
	 11: '=',       // equal position (ChessBase)
	 13: '\u221e',  // unclear position
	 14: '\u2a72',  // White has a slight advantage
	 15: '\u2a71',  // Black has a slight advantage
	 16: '\u00b1',  // White has a moderate advantage
	 17: '\u2213',  // Black has a moderate advantage
	 18: '+\u2212', // White has a decisive advantage
	 19: '\u2212+', // Black has a decisive advantage
	 22: '\u2a00',  // Zugzwang
	 32: '\u27f3',  // Development advantage
	 36: '\u2191',  // Initiative
	 40: '\u2192',  // Attack
	132: '\u21c6',  // Counterplay
	138: '\u2a01',  // Zeitnot
	140: '\u2206',  // With idea...
	141: '\u2207',  // Aimed against...
	142: '\u2313',  // Better is...
	143: '\u2264',  // Worse is...
	145: 'RR',      // Editorial comment
	146: 'N',       // Novelty
	/* eslint-enable no-mixed-spaces-and-tabs */
};


/**
 * Return the human-readable symbol for the given [NAG](https://en.wikipedia.org/wiki/Numeric_Annotation_Glyphs).
 *
 * @param {number} nag
 * @returns {string}
 */
exports.nagSymbol = function(nag) {
	return nag in NAG_SYMBOLS ? NAG_SYMBOLS[nag] : '$' + nag;
};