/*
	ColorChange 1.1 (v20)
	2004-2007 Nate Weaver (Wevah)
*/

ColorChange = {
	minColor: '#000',
	midColor: '#393',
	maxColor: '#f00',
	textareas: {},
	spokenLengths: {},
	setProperColor: function (obj, len) {
		if (len < 0)
			len = obj.value.spokenLength(self.spokenLengths);
		
		if (len < this.textareas[obj.id].min) {
			obj.style.color = this.minColor;
		} else if (len > this.textareas[obj.id].max) {
			obj.style.color = this.maxColor;
		} else {
			obj.style.color = this.midColor;
		}
	},
	setMinMax: function () {
		// Call to set a textarea's minimum and maximum.
		// Pass either an object reference or an element's id as the first parameter.
		// Pass either min and max as the second and third parameters, or a string of the form
		// 'min, max' as the second parameter.		
		var obj = arguments[0];

		if (typeof obj != 'object')
			obj = document.getElementById(obj);
		
		if (obj) {
			var min = 0, max = Infinity;
			
			if (arguments.length != 3) {
				var temp = arguments[1].match(/(\d+), ?(\d+)/);
				
				if (temp) {
					min = temp[1];
					max = temp[2];
				}
			} else {
				min = arguments[1];
				max = arguments[2];
			}
			
			this.textareas[obj.id] = { min: min, max: max };
			
			obj.onchange = obj.onkeyup = function () {
				var calculatedLength = obj.value.spokenLength(ColorChange.spokenLengths);
				ColorChange.setProperColor(obj, calculatedLength);
				var num = obj.id.match(/(\d+)$/);
				obj.form['sizebox_' + num[1]].value = calculatedLength;
			};
			
			ColorChange.setProperColor(obj, -1);
		}
	},
	setDefaultMinMax: function() {
		var idregex;
		
		if (arguments[0].constructor == RegExp) {
			idregex = arguments[0];
		} else {
			idregex = new RegExp('^' + arguments[0]);
		}
		
		elems = document.getElementsByTagName('textarea');
		
		for (var i = 0; i < elems.length; ++i) {
			if (idregex.test(elems[i].id)) {
				ColorChange.setMinMax(elems[i], arguments[1], arguments[2]);
			}
		}
	}
};

// Count the number of alphanumeric characters that aren't in parentheses (including nesting), and treat certain
// strings as other lengths

String.prototype.spokenLength = function (lengths) {
	var calculatedLength = 0;
	var len = this.length;
	var parenDepth = 0;
	
	for (var i = 0; i < len; ++i) {
		var c = this.charAt(i);
		
		if (c == '(')
			++parenDepth;
		else if (c == ')' && parenDepth > 0)
			--parenDepth;
		else if (parenDepth == 0) {
			if (lengths && lengths[c]) {
				var val = lengths[c];
				
				if (typeof val == 'number')
					calculatedLength += val;
				else
					calculatedLength += val.length;
			} else if (c.search(/^[A-Za-z0-9]$/) != -1) {
				if (c.search(/^[0-9]$/) != -1) {
					var nextNotNumberIndex = this.substring(i).search(/[^0-9.,]/);
					
					var numberChunk = this.substring(i, nextNotNumberIndex != -1 ? i + nextNotNumberIndex : len);
					calculatedLength += numberChunk.numberWrittenForm().spokenLength();
					
					if (nextNotNumberIndex != -1)
						i += nextNotNumberIndex;
					else
						i = len;
				} else
					++calculatedLength;
			}
		}
	}
	
	return calculatedLength;
};

String.prototype.numberWrittenForm = function (thousandsSeparator, decimalSeparator) {
	if (this == 0)
		return 'zero';
	
	if (!thousandsSeparator)
		thousandsSeparator = ',';
		
	if (!decimalSeparator)
		decimalSeparator = '.';
		
	var reverseRegex = new RegExp('[^0-9\\' + thousandsSeparator + '\\' + decimalSeparator + ']');
	
	if (this.search(reverseRegex) != -1)
		return this;
		
	var parts = (this.split(decimalSeparator));
	
	if (parts.length > 2)
		return this;
	
	var ret = '';
	
	var stringed = parts[0].replace(thousandsSeparator, '', 'g');
	var idx = 0;
	
	var clumpNames = ['', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion']; // etc.
	var numberNames = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
	var tens = ['ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninty'];
	var teens = ['eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'ninteen'];
	
	var numClumps = Math.ceil(stringed.length / 3);
	var remainingLength = stringed.length;
		
	for (var clumpIdx = numClumps; clumpIdx > 0; --clumpIdx) {
		var currentClump = stringed.substring(stringed.length - remainingLength, stringed.length - remainingLength + (remainingLength % 3 ? remainingLength % 3 : 3));
		remainingLength -= currentClump.length;
		var clumpIsNonZero = false;
		var hasTens = false;
		
		for (var i = 0; i < currentClump.length; ++i) {
			var c = parseInt(currentClump.charAt(i));
	
			if (c != 0) {
				if (currentClump.length - i == 2) {
					if (c == 1) {
						c = currentClump.charAt(++i);
						
						if (c == 0) {
							ret += ' ten';
						} else {
							ret += ' ' + teens[c - 1];
						}
					} else {
						ret += ' ' + tens[c - 1];
						hasTens = true;
					}
				} else {
					if (hasTens)
						ret += '-';
					else
						ret += ' ';
					
					ret += numberNames[c];
					
					if (currentClump.length - i == 3)
						ret += ' hundred';
				}
				
				clumpIsNonZero = true;
			}
		}
		
		if (clumpIsNonZero && clumpIdx != 1)
			ret += ' ' + clumpNames[clumpIdx - 1];
	}
	
	if (parts.length > 1) {
		ret += ' point';
		
		for (var i = 0; i < parts[1].length; ++i) {
			var c = parseInt(parts[1].charAt(i));
			
			ret += ' ' + numberNames[c];
		}
	}
	
	return ret.substring(1); // strip off the leading space
};

Number.prototype.numberWrittenForm = function () {
	return this.toString().numberWrittenForm();
};
