/**
 * Sequence Converter
 *
 * Copyright 2007 Google Inc.
 * http://neil.fraser.name/news/2007/12/29/
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */

/**
 * @fileoverview Converts integers to roman numerals to letters.  Used to convert
 * between the three main types of ordered lists ('1,2,3', 'i,ii,iii', 'a,b,c').
 * @author fraser@google.com (Neil Fraser)
 */

var sequenceConverter = {};

/**
 * The 26 letters A-Z.
 * @type {String}
 */
sequenceConverter.ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';


/**
 * Convert letters to numbers, 'a'->1, 'Z'->26, 'ab'->28
 * @param {String} alpha Input.
 * @return {Number} Integer output.  0 if invalid.
 */
sequenceConverter.alphaToInteger = function(alpha) {
  var alpha = alpha.toUpperCase();
  var integer = 0;
  for (var x = 0; x < alpha.length; x++) {
    var i = this.ALPHABET.indexOf(alpha.charAt(x)) + 1;
    if (i) {
      integer *= 26;
      integer += i;
    }
  }
  return integer;
};


/**
 * Convert numbers to letters, 1->'a', 26->'Z', 28->'ab'
 * @param {Number} integer Input.
 * @param {Boolean} uppercase A-Z vs a-z.
 * @return {String} Alpha output.  '' if invalid.
 */
sequenceConverter.integerToAlpha = function(integer,
    uppercase) {
  if (typeof integer != 'number' || integer < 1) {
    integer = 0;
  } else {
    integer = Math.floor(integer);
  }

  var alpha = '';
  while (integer > 0) {
    var i = integer % 26;
    if (i == 0) {
      // Wrap around to Z.
      i = 26;
    }
    alpha = this.ALPHABET.charAt(i - 1) + alpha;
    integer -= i;
    integer /= 26;
  }
  return uppercase ? alpha : alpha.toLowerCase();
};


/**
 * Convert roman numerals to numbers, 'i'->1, 'XXVI'->26
 * From http://www.moo.ca/math_utils:from_roman
 * originaly by Mathieu Fenniak (ported with permission)
 * @param {String} alpha Input.
 * @return {Number} Integer output.  0 if invalid.
 */
sequenceConverter.romanToInteger = function(alpha) {
  var alpha = alpha.toUpperCase();
  var integer = 0;
  for (var x = 0; x < alpha.length; x++) {
    var letter = alpha.charAt(x);
    var nextLetter = alpha.charAt(x + 1);
    if (letter == 'M') {
      integer += 1000;
    } else if (letter == 'D') {
      integer += 500;
    } else if (letter == 'C' && nextLetter == 'M') {
      integer += 900;
      x++;
    } else if (letter == 'C' && nextLetter == 'D') {
      integer += 400;
      x++;
    } else if (letter == 'C') {
      integer += 100;
    } else if (letter == 'L') {
      integer += 50;
    } else if (letter == 'X' && nextLetter == 'C') {
      integer += 90;
      x++;
    } else if (letter == 'X' && nextLetter == 'L') {
      integer += 40;
      x++;
    } else if (letter == 'X') {
      integer += 10;
    } else if (letter == 'V') {
      integer += 5;
    } else if (letter == 'I' && nextLetter == 'X') {
      integer += 9;
      x++;
    } else if (letter == 'I' && nextLetter == 'V') {
      integer += 4;
      x++;
    } else if (letter == 'I') {
      integer += 1;
    } else  {
      return 0;
    }
  }
  return integer;
};

/**
 * Convert numbers to roman numerals, 1->'i', 26->'XXVI'
 * From http://www.moo.ca/math_utils:to_roman
 * originaly by Mathieu Fenniak (ported with permission)
 * @param {Number} integer Input.
 * @param {Boolean} uppercase I vs i.
 * @return {String} Roman numeral output.  '' if invalid.
 */
sequenceConverter.integerToRoman = function(integer,
    uppercase) {
  if (typeof integer != 'number' || integer < 1) {
    integer = 0;
  } else {
    integer = Math.floor(integer);
  }

  var alpha = '';
  while (integer > 0) {
    if (integer >= 1000) {
      alpha += 'M';
      integer -= 1000;
    } else if (integer >= 900) {
      alpha += 'CM';
      integer -= 900;
    } else if (integer >= 500) {
      alpha += 'D';
      integer -= 500;
    } else if (integer >= 400) {
      alpha += 'CD';
      integer -= 400;
    } else if (integer >= 100) {
      alpha += 'C';
      integer -= 100;
    } else if (integer >= 90) {
      alpha += 'XC';
      integer -= 90;
    } else if (integer >= 50) {
      alpha += 'L';
      integer -= 50;
    } else if (integer >= 40) {
      alpha += 'XL';
      integer -= 40;
    } else if (integer >= 10) {
      alpha += 'X';
      integer -= 10;
    } else if (integer >= 9) {
      alpha += 'IX';
      integer -= 9;
    } else if (integer >= 5) {
      alpha += 'V';
      integer -= 5;
    } else if (integer >= 4) {
      alpha += 'IV';
      integer -= 4;
    } else if (integer >= 1) {
      alpha += 'I';
      integer -= 1;
    }
  }
  return uppercase ? alpha : alpha.toLowerCase();
};

