Source: record.js

'use strict';

var Board = require('./board');
var Node = require('./node');

/**
 * Create a go game record that can handle plays and variations. A Board
 * object is created that will reflect the current position in game record.
 *
 * @param {int} width Board width.
 * @param {int} height Board height.
 * @constructor
 */
var Record = function(width, height) {
  this.jboard = new Board(width, height ? height : width);
  this.root = this.current = null;
  this.info = {}; // game information
};

/**
 * Get board object.
 *
 * @returns {Board} Board object.
 */
Record.prototype.getBoard = function() {
  return this.jboard;
};

/**
 * Get current node.
 *
 * @returns {Node} Current node.
 */
Record.prototype.getCurrentNode = function() {
  return this.current;
};


/**
 * Get root node.
 *
 * @returns {Node} Root node.
 */
Record.prototype.getRootNode = function() {
  return this.root;
};

/**
 * Create new empty node under current one.
 *
 * @param {bool} clearParentMarks True to clear parent node marks.
 * @param {Object} info Node information - ko coordinate, comment, etc.
 * @returns {Node} New, current node.
 */
Record.prototype.createNode = function(clearParentMarks, options) {
  var node = new Node(this.jboard, this.current, options);

  if(clearParentMarks)
    node.clearParentMarks();

  if(this.root === null)
    this.root = node;

  return (this.current = node);
};

/**
 * Advance to the next node in the game tree.
 *
 * @param {int} [variation] parameter to specify which variation to select, if there are several branches.
 * @returns {Node} New current node or null if at the end of game tree.
 */
Record.prototype.next = function(variation) {
  if(this.current === null)
    return null;

  if(!variation)
    variation = 0;

  if(variation >= this.current.children.length)
    return null;

  this.current = this.current.children[variation];
  this.current.apply(this.jboard);

  return this.current;
};

/**
 * Back up a node in the game tree.
 *
 * @returns {Node} New current node or null if at the beginning of game tree.
 */
Record.prototype.previous = function() {
  if(this.current === null || this.current.parent === null)
    return null; // empty or no parent

  this.current.revert(this.jboard);
  this.current = this.current.parent;

  return this.current;
};

/**
 * Get current variation number (zero-based).
 *
 * @returns {int} Current variations.
 */
Record.prototype.getVariation = function() {
  if(this.current === null || this.current.parent === null)
    return 0;
  return this.current.parent.children.indexOf(this.current);
};

/**
 * Go to a variation. Uses previous() and next().
 *
 * @param {int} [variation] parameter to specify which variation to select, if there are several branches.
 */
Record.prototype.setVariation = function(variation) {
  if(this.previous() === null)
    return null;
  return this.next(variation);
};

/**
 * Get number of variations for current node.
 *
 * @returns {int} Number of variations.
 */
Record.prototype.getVariations = function() {
  if(this.current === null || this.current.parent === null)
    return 1;

  return this.current.parent.children.length; // "nice"
};

/**
 * Go to the beginning of the game tree.
 *
 * @returns {Node} New current node.
 */
Record.prototype.first = function() {
  this.current = this.root;
  this.jboard.clear();

  if(this.current !== null)
    this.current.apply(this.jboard);

  return this.current;
};

/**
 * Create a snapshot of current Record state. Will contain board state and
 * current node.
 *
 * @returns Snapshot to be used with restoreSnapshot().
 */
Record.prototype.createSnapshot = function() {
  return {jboard: this.jboard.getRaw(), current: this.current};
};

/**
 * Restore the Record to the state contained in snapshot. Use only if you
 * REALLY know what you are doing, this is mainly for creating Record
 * quickly from SGF.
 *
 * @param {Object} raw Snapshot created with createSnapshot().
 */
Record.prototype.restoreSnapshot = function(raw) {
  this.jboard.setRaw(raw.jboard);
  this.current = raw.current;
};

/**
 * Normalize record so the longest variation is the first.
 *
 * @param {Node} node The node to start with. Defaults to root if unset.
 * @returns int Length of longest subsequence.
 */
Record.prototype.normalize = function(node) {
  var i, len, maxLen = 0, maxI = 0;

  if(!node) node = this.getRootNode();

  for(i=0; i<node.children.length; i++) {
    len = this.normalize(node.children[i]);
    if(maxLen < len) { maxLen = len; maxI = i; }
  }

  if(maxI) { // If needed, swap longest first
    i = node.children[0];
    node.children[0] = node.children[maxI];
    node.children[maxI] = i;
  }

  return maxLen + 1; // longest subsequence plus this
};

module.exports = Record;