pgn method

dynamic pgn([
  1. Map? options
])

Return the PGN representation of the game thus far

Implementation

pgn([Map? options]) {
  /* using the specification from http://www.chessclub.com/help/PGN-spec
     * example for html usage: .pgn({ max_width: 72, newline_char: "<br />" })
     */
  var newline = (options != null &&
          options.containsKey("newline_char") &&
          options["newline_char"] != null)
      ? options['newline_char']
      : '\n';
  var maxWidth = (options != null &&
          options.containsKey("max_width") &&
          options["max_width"] != null)
      ? options["max_width"]
      : 0;
  var result = [];
  bool headerExists = false;

  /* add the PGN header headerrmation */
  for (var i in header.keys) {
    /* TODO: order of enumerated properties in header object is not
       * guaranteed, see ECMA-262 spec (section 12.6.4)
       */
    result.add(
        '[' + i.toString() + ' \"' + header[i].toString() + '\"]' + newline);
    headerExists = true;
  }

  if (headerExists && (history.length != 0)) {
    result.add(newline);
  }

  List<String> moves = sanMoves();

  if (maxWidth == 0) {
    return result.join('') + moves.join(' ');
  }

  /* wrap the PGN output at max_width */
  var currentWidth = 0;
  for (int i = 0; i < moves.length; i++) {
    /* if the current move will push past max_width */
    if (currentWidth + moves[i].length > maxWidth && i != 0) {
      /* don't end the line with whitespace */
      if (result[result.length - 1] == ' ') {
        result.removeLast();
      }

      result.add(newline);
      currentWidth = 0;
    } else if (i != 0) {
      result.add(' ');
      currentWidth++;
    }
    result.add(moves[i]);
    currentWidth += moves[i].length;
  }

  return result.join('');
}