+/**
+ * @param {Number} remaining_ms
+ * @param {boolean} show_seconds
+ */
+var format_clock = function(remaining_ms, show_seconds) {
+ if (remaining_ms <= 0) {
+ if (show_seconds) {
+ return "00:00:00";
+ } else {
+ return "00:00";
+ }
+ }
+
+ var remaining = Math.floor(remaining_ms / 1000);
+ var seconds = remaining % 60;
+ remaining = (remaining - seconds) / 60;
+ var minutes = remaining % 60;
+ remaining = (remaining - minutes) / 60;
+ var hours = remaining;
+ if (show_seconds) {
+ return format_2d(hours) + ":" + format_2d(minutes) + ":" + format_2d(seconds);
+ } else {
+ return format_2d(hours) + ":" + format_2d(minutes);
+ }
+}
+
+/**
+ * @param {Number} x
+ */
+var format_2d = function(x) {
+ if (x >= 10) {
+ return x;
+ } else {
+ return "0" + x;
+ }
+}
+
+/**
+ * @param {string} move
+ * @param {Number} move_num
+ * @param {boolean} white_to_play
+ */
+var format_move_with_number = function(move, move_num, white_to_play) {
+ var ret;
+ if (white_to_play) {
+ ret = (move_num - 1) + '… ';
+ } else {
+ ret = move_num + '. ';
+ }
+ ret += move;
+ return ret;
+}
+
+/**
+ * @param {string} move
+ * @param {Number} halfmove_num
+ */
+var format_halfmove_with_number = function(move, halfmove_num) {
+ return format_move_with_number(
+ move,
+ Math.floor(halfmove_num / 2) + 1,
+ halfmove_num % 2 == 0);
+}
+
+/**
+ * @param {Object} data
+ * @param {Number} halfmove_num
+ */
+var format_tooltip = function(data, halfmove_num) {
+ if (data['score_history'][halfmove_num] ||
+ halfmove_num === data['position']['pretty_history'].length) {
+ var move;
+ var short_score;
+ if (halfmove_num === data['position']['pretty_history'].length) {
+ move = data['position']['last_move'];
+ short_score = data['short_score'];
+ } else {
+ move = data['position']['pretty_history'][halfmove_num];
+ short_score = data['score_history'][halfmove_num][1];
+ }
+ var move_with_number = format_halfmove_with_number(move, halfmove_num);
+
+ return "After " + move_with_number + ": " + short_score;
+ } else {
+ for (var i = halfmove_num; i --> 0; ) {
+ if (data['score_history'][i]) {
+ var move = data['position']['pretty_history'][i];
+ return "[Analysis kept from " + format_halfmove_with_number(move, i) + "]";
+ }
+ }
+ }
+}
+
+/**
+ * @param {boolean} sort_by_score
+ */
+var resort_refutation_lines = function(sort_by_score) {
+ sort_refutation_lines_by_score = sort_by_score;
+ if (supports_html5_storage()) {
+ localStorage['sort_refutation_lines_by_score'] = sort_by_score ? 1 : 0;
+ }
+ update_refutation_lines();
+}
+window['resort_refutation_lines'] = resort_refutation_lines;
+
+/**
+ * @param {boolean} truncate_history
+ */
+var set_truncate_history = function(truncate_history) {
+ truncate_display_history = truncate_history;
+ update_refutation_lines();
+}
+window['set_truncate_history'] = set_truncate_history;
+
+/**
+ * @param {number} line_num
+ * @param {number} move_num
+ */
+var show_line = function(line_num, move_num) {
+ if (line_num == -1) {
+ current_display_line = null;
+ current_display_move = null;
+ if (displayed_analysis_data) {
+ // TODO: Support exiting to history position if we are in an
+ // analysis line of a history position.
+ displayed_analysis_data = null;
+ update_board(current_analysis_data, displayed_analysis_data);
+ }
+ } else {
+ current_display_line = display_lines[line_num];
+ current_display_move = move_num;
+ }
+ current_display_line_is_history = (line_num == 0);
+
+ update_historic_analysis();
+ update_displayed_line();
+ update_highlight();
+ redraw_arrows();
+}
+window['show_line'] = show_line;
+
+var prev_move = function() {
+ if (current_display_move > -1) {
+ --current_display_move;
+ }
+ update_historic_analysis();
+ update_displayed_line();
+}
+window['prev_move'] = prev_move;
+
+var next_move = function() {
+ if (current_display_line && current_display_move < current_display_line.pretty_pv.length - 1) {
+ ++current_display_move;
+ }
+ update_historic_analysis();
+ update_displayed_line();
+}
+window['next_move'] = next_move;
+
+var update_historic_analysis = function() {
+ if (!current_display_line_is_history) {
+ return;
+ }
+ if (current_display_move == current_display_line.pretty_pv.length - 1) {
+ displayed_analysis_data = null;
+ update_board(current_analysis_data, displayed_analysis_data);
+ }
+
+ // Fetch old analysis for this line if it exists.
+ var hiddenboard = chess_from(null, current_display_line.pretty_pv, current_display_move);
+ var filename = "/history/move" + (current_display_move + 1) + "-" +
+ hiddenboard.fen().replace(/ /g, '_').replace(/\//g, '-') + ".json";
+
+ $.ajax({
+ url: filename
+ }).done(function(data, textstatus, xhr) {
+ displayed_analysis_data = data;
+ update_board(current_analysis_data, displayed_analysis_data);
+ }).fail(function() {
+ displayed_analysis_data = {'failed': true};
+ update_board(current_analysis_data, displayed_analysis_data);
+ });
+}
+
+/**
+ * @param {string} fen
+ */
+var update_imbalance = function(fen) {
+ var hiddenboard = new Chess(fen);
+ var imbalance = {'k': 0, 'q': 0, 'r': 0, 'b': 0, 'n': 0, 'p': 0};
+ for (var row = 0; row < 8; ++row) {
+ for (var col = 0; col < 8; ++col) {
+ var col_text = String.fromCharCode('a1'.charCodeAt(0) + col);
+ var row_text = String.fromCharCode('a1'.charCodeAt(1) + row);
+ var square = col_text + row_text;
+ var contents = hiddenboard.get(square);
+ if (contents !== null) {
+ if (contents.color === 'w') {
+ ++imbalance[contents.type];
+ } else {
+ --imbalance[contents.type];
+ }
+ }
+ }
+ }
+ var white_imbalance = '';
+ var black_imbalance = '';
+ for (var piece in imbalance) {
+ for (var i = 0; i < imbalance[piece]; ++i) {
+ white_imbalance += '<img src="img/chesspieces/wikipedia/w' + piece.toUpperCase() + '.png" alt="" style="width: 15px;height: 15px;">';
+ }
+ for (var i = 0; i < -imbalance[piece]; ++i) {
+ black_imbalance += '<img src="img/chesspieces/wikipedia/b' + piece.toUpperCase() + '.png" alt="" style="width: 15px;height: 15px;">';
+ }
+ }
+ $('#whiteimbalance').html(white_imbalance);
+ $('#blackimbalance').html(black_imbalance);
+}
+
+var update_displayed_line = function() {
+ if (highlighted_move !== null) {
+ highlighted_move.removeClass('highlight');
+ }
+ if (current_display_line === null) {
+ $("#linenav").hide();
+ $("#linemsg").show();
+ board.position(fen);
+ update_imbalance(fen);
+ return;
+ }
+
+ $("#linenav").show();
+ $("#linemsg").hide();
+
+ if (current_display_move <= 0) {
+ $("#prevmove").html("Previous");
+ } else {
+ $("#prevmove").html("<a href=\"javascript:prev_move();\">Previous</a></span>");
+ }
+ if (current_display_move == current_display_line.pretty_pv.length - 1) {
+ $("#nextmove").html("Next");
+ } else {
+ $("#nextmove").html("<a href=\"javascript:next_move();\">Next</a></span>");
+ }
+
+ highlighted_move = $("#automove" + current_display_line.line_number + "-" + current_display_move);
+ highlighted_move.addClass('highlight');
+
+ var hiddenboard = chess_from(current_display_line.start_fen, current_display_line.pretty_pv, current_display_move);
+ board.position(hiddenboard.fen());
+ update_imbalance(hiddenboard.fen());
+}
+
+/**
+ * @param {boolean} param_enable_sound
+ */
+var set_sound = function(param_enable_sound) {
+ enable_sound = param_enable_sound;
+ if (enable_sound) {
+ $("#soundon").html("<strong>On</strong>");
+ $("#soundoff").html("<a href=\"javascript:set_sound(false)\">Off</a>");
+
+ // Seemingly at least Firefox prefers MP3 over Opus; tell it otherwise,
+ // and also preload the file since the user has selected audio.
+ var ding = document.getElementById('ding');
+ if (ding && ding.canPlayType && ding.canPlayType('audio/ogg; codecs="opus"') === 'probably') {
+ ding.src = 'ding.opus';
+ ding.load();
+ }
+ } else {
+ $("#soundon").html("<a href=\"javascript:set_sound(true)\">On</a>");
+ $("#soundoff").html("<strong>Off</strong>");
+ }
+ if (supports_html5_storage()) {
+ localStorage['enable_sound'] = enable_sound ? 1 : 0;
+ }
+}
+window['set_sound'] = set_sound;
+