/**
	Arabic-Roman-Arabic Converter
	functions for converting arabic to roman numerals and vice versa

	Copyright (c) 2004 Borislav Manolov

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	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 General Public License for more details.

	Author: Borislav Manolov
		b.manolov at the server gmail.com
		http://purl.org/NET/borislav
*/


function arab2rom(number) {
	ones     = new Array('', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX');
	decades  = new Array('', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC');
	hundreds = new Array('', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM');
	tousands = new Array('', 'M', 'MM', 'MMM');
	all = new Array(ones, decades, hundreds, tousands);
	if (number > 3999) {
		alert('The number is greater than 3999!');
		return '<ERROR>';
	}
	if (number < 1) {
		alert('The number is not positive!');
		return '<ERROR>';
	}

	numstr = number.toString();
	len = numstr.length;
	romanstr = '';
	// generation
	for (i = 0; i < len; i++) {
		romanstr += all[len - i - 1][numstr.charAt(i)];
	}

	return romanstr;
}


function rom2arab(romanstr) {
	invalid_number_err = 'The string is not a valid roman numeral!';
	err = 'ERR';

	// maximal characters for a class, e.g. DCCC, XXXV, VIII
	// tousands, hundreds, decades, ones
	max = new Array(3, 4, 4, 4);
	// can a class contain more characters or there must follow
	// next class, i.e. after XC can follow only ones (V, I)
	can_more = new Array(true, true, true, true);
	simple = new Array(false, false, false, false);
	// class chars counter: tousands, hundreds, decades, ones
	counter = new Array(0, 0, 0, 0);

	romanstr = romanstr.toUpperCase();
	len = romanstr.length;
	arab = 0;
	for (i = 0; i < len; i++) {
		switch (romanstr.charAt(i)) {
		case 'M':
			if ( ++counter[0] > max[0] || !can_more[0] ) {
				alert(invalid_number_err);
				return err;
			}
			arab += 1000;
			break;
		case 'D':
			can_more[0] = false;
			if ( ++counter[1] > max[1] || !can_more[1] || simple[1] ) {
				alert(invalid_number_err);
				return err;
			}
			switch (romanstr.charAt(i+1)) {
			case 'M':
				alert(invalid_number_err);
				return err;
			default:
				arab += 500;
				simple[1] = true;
			}
			break;
		case 'C':
			can_more[0] = false;
			if ( ++counter[1] > max[1] || !can_more[1] || simple[2] ) {
				alert(invalid_number_err);
				return err;
			}
			switch (romanstr.charAt(i+1)) {
			case 'M':
				arab += 900;
				i++;
				can_more[1] = false;
				break;
			case 'D':
				arab += 400;
				i++;
				can_more[1] = false;
				break;
			default:
				arab += 100;
				simple[1] = true;
			}
			break;
		case 'L':
			current = 2;
			if ( ++counter[2] > max[2] || !can_more[2] || simple[2]) {
				alert(invalid_number_err);
				return err;
			}
			switch (romanstr.charAt(i+1)) {
			case 'M': case 'D': case 'C':
				alert(invalid_number_err);
				return err;
			default:
				arab += 50;
				simple[2] = true;
			}
			break;
		case 'X':
			current = 2;
			if ( ++counter[2] > max[2] || !can_more[2] || simple[3] ) {
				alert(invalid_number_err);
				return err;
			}
			switch (romanstr.charAt(i+1)) {
			case 'M': case 'D':
				alert(invalid_number_err);
				return err;
			case 'C':
				arab += 90;
				i++;
				can_more[2] = false;
				break;
			case 'L':
				arab += 40;
				i++;
				can_more[2] = false;
				break;
			default:
				arab += 10;
				simple[2] = true;
			}
			break;
		case 'V':
			current = 3;
			if ( ++counter[3] > max[3] || !can_more[3] || simple[3]) {
				alert(invalid_number_err);
				return err;
			}
			switch (romanstr.charAt(i+1)) {
			case 'M': case 'D': case 'C': case 'L': case 'X':
				alert(invalid_number_err);
				return err;
			default:
				arab += 5;
				simple[3] = true;
			}
			break;
		case 'I':
			current = 3;
			if ( ++counter[3] > max[3] || !can_more[3] ) {
				alert(invalid_number_err);
				return err;
			}
			switch (romanstr.charAt(i+1)) {
			case 'M': case 'D': case 'C': case 'L':
				alert(invalid_number_err);
				return err;
			case 'X':
				arab += 9;
				i++;
				can_more[3] = false;
				break;
			case 'V':
				arab += 4;
				i++;
				can_more[3] = false;
				break;
			default:
				arab += 1;
				simple[3] = true;
			}
			break;
		default:
			alert(invalid_number_err);
			return err;
		} // end switch (romanstr.charAt(i))
	} // end for (i = 0; i < len; i++)
	return arab;
}
