// blank line needed for js concatenation
P4.Util =
{
	blurbify: function(string, length)
		{
		if (string != null && string.length > length)
			return string.substring(0, length - 3) + '...';
		else
			return string;
	},
	parseCurrency: function(currencyString)
		{
		if (!currencyString)
			return null;
		if (!this.matchesExactly(currencyString, /(- )?\(?.?[0-9]+[0-9\.\,]*\)?/))
			alert('unable to parse currency "' + currencyString + '"');
		var negativeParens = /\(.[0-9\.\,]*\)/g.test(currencyString);
		var negativeMinus = currencyString.substring(0, 2) == '- ';
		if (negativeParens)
			currencyString = currencyString.split(/[\(\)]/g)[1];
		if (negativeMinus)
			currencyString = currencyString.substring(2);
		if (!/^[0-9][0-9]+.*/.test(currencyString)) // remove currency symbol
			currencyString = currencyString.substring(1, currencyString.length);
		if (this.isCommaSeparator(currencyString))
		{
			// comma separator
			currencyString = currencyString.replace(/\./g, '');
			// remove periods
			currencyString = currencyString.replace(/\,/g, '.');
			// replace comma separator with period
		}
		else
		{
			// period separator
			currencyString = currencyString.replace(/\,/g, '');
			// remove commas
		}
		var numValue = new Number(currencyString);
		return negativeParens || negativeMinus ? -numValue : numValue;
	},

	formatNumberLike: function(value, example, fractionDigits, showSign)
		{
		var currencySymbol = this.getCurrencySymbol(example);
		var fractionSeparator = this.getFractionSeparator(example);
		return this.formatNumber(value, fractionDigits, fractionSeparator, currencySymbol, showSign);
	},

	formatNumber: function(value, fractionDigits, fractionSeparator, currencySymbol, showSign)
		{
		var divisor = fractionDigits == null ? 1 : Math.pow(10, fractionDigits);
		if (!currencySymbol)
			currencySymbol = '';
		if (!fractionSeparator)
			fractionSeparator = '.';
		var neg = false;
		if (value < 0)
		{
			neg = true;
			value = value * -1;
		}
		value = value.toString().replace(/\|\./g, '');
		if (isNaN(value))
			value = '0';
		var fraction = Math.floor((value * divisor + 0.5) % divisor);
		value = Math.floor((value * divisor + 0.5) / divisor).toString();
		if (fraction < 10) fraction = '0' + fraction;
		fraction = fractionSeparator + fraction;
		for (var i = 0; i < Math.floor((value.length - (1 + i)) / 3); i++)
			value = value.substring(0, value.length - (4 * i + 3)) + ',' + value.substring(value.length - (4 * i + 3));
		var result = currencySymbol + value + fraction;
		if (showSign)
			return (neg ? '-' : '+') + result;
		else if (neg)
			return '- ' + result;
		else
			return result;
	},

	removeIdAttribute: function()
		{
		$A(arguments).each(function(id)
			{
			var element = $(id);
			if (id)
				element.removeAttribute('id');
		});
	},

	matchesExactly: function(string, regex)
		{
		return regex.test(string) && string.match(regex)[0].length == string.length;
	},

	isCommaSeparator: function(currencyString)
		{
		return this.matchesExactly(currencyString, /.*\,[0-9]{2}/);
	},

	isRightClick: function(event)
		{
		return (event.which && event.which == 3) ||
		       (event.button && event.button == 2);
	},

	getFractionSeparator: function(currencyString)
		{
		return this.isCommaSeparator(currencyString) ? ',' : '.';
	},

	getCurrencySymbol: function(currencyString)
		{
		if (/\([^0-9][0-9]+\.*/.test(currencyString))		 // negative (parentheses) with symbol
			return currencyString.charAt(1);
		if (/-[^0-9][0-9]+\.*/.test(currencyString))		 // negative (sign) with symbol
			return currencyString.charAt(1);
		if (/-\ [^0-9][0-9]+\.*/.test(currencyString))		 // negative (sign and space) with symbol
			return currencyString.charAt(2);
		else if (/[^0-9][0-9]+\.*/.test(currencyString))	 // positive with symbol
			return currencyString.charAt(0);
		else
			return null;
	},

	stripPx: function(length)
		{
		if (length == null || length == '0' || length == 'intrinsic')
			return 0;
		var matches = length.match(/([0-9]+)px/);
		if (matches)
			return new Number(matches[1]);
		else
			throw 'no "px" units found on value "' + length + '"';
	},

	getOffsetToPutOnPage: function(element)
		{
		element = $(element);
		var offset = { x:0, y:0 };
		var cumulativeOffset = Position.cumulativeOffset(element);
		var scroll = this.getWindowScroll(window);
		// if off left side, move right
		if (cumulativeOffset[0] < scroll.left)
			offset.x = cumulativeOffset[0] - scroll.left;
		// if off top side, move down
		if (cumulativeOffset[1] < scroll.top)
			offset.y = cumulativeOffset[1] - scroll.top;
		var dimensions = Element.getDimensions(element);
		var rightEdgeOfElement = cumulativeOffset[0] + dimensions.width;
		var rightEdgeOfWindow = scroll.left + scroll.width - 20;
		// 20 for scroll bar
		// if off right side, move left
		if (!offset.x && rightEdgeOfElement > rightEdgeOfWindow)
			offset.x = rightEdgeOfWindow - rightEdgeOfElement;
		var bottomEdgeOfElement = cumulativeOffset[1] + dimensions.height;
		var bottomEdgeOfWindow = scroll.top + scroll.height - 20;
		// 20 for scroll bar
		// if off bottom side, move up
		if (!offset.y && bottomEdgeOfElement > bottomEdgeOfWindow)
			offset.y = bottomEdgeOfWindow - bottomEdgeOfElement;
		// if going to move too far left, move as far left as possible, but no further
		if (cumulativeOffset[0] + offset.x < scroll.left)
			offset.x = scroll.left - cumulativeOffset[0];
		// if going to move too far up, move as far up as possible, but no further
		if (cumulativeOffset[1] + offset.y < scroll.top)
			offset.y = scroll.top - cumulativeOffset[1];
		return offset;
	},

	getWindowScroll: function(w)
		// stolen from scriptaculous
		{
		var T, L, W, H;
		with (w.document)
		{
			if (w.document.documentElement && documentElement.scrollTop)
			{
				T = documentElement.scrollTop;
				L = documentElement.scrollLeft;
			}
			else if (w.document.body)
			{
				T = body.scrollTop;
				L = body.scrollLeft;
			}
			if (w.innerWidth)
			{
				W = w.innerWidth;
				H = w.innerHeight;
			}
			else if (w.document.documentElement && documentElement.clientWidth)
			{
				W = documentElement.clientWidth;
				H = documentElement.clientHeight;
			}
			else
			{
				W = body.offsetWidth;
				H = body.offsetHeight;
			}
		}
		return { top: T, left: L, width: W, height: H };
	},

	positionOnPage: function(element, options)
		{
		element = $(element);
		var offset = this.getOffsetToPutOnPage(element);
		if (offset.x || offset.y)
		{
			var zeroDuration = options && options.duration != null && options.duration == 0;
			if (typeof Effect != 'undefined' && typeof Effect.Move != 'undefined' && !zeroDuration)
			{
				options = Object.extend({}, options);
				Object.extend(options, offset);
				return new Effect.Move(element, options);
			}
			else
			{
				var position = element.cumulativeOffset();
				element.setStyle(
				{
					left: (position.left + offset.x) + 'px',
					top: (position.top + offset.y) + 'px'
				});
			}
		}
		else if (options.afterFinish)
			options.afterFinish();
	},

	getDefinedTop: function(element)
		{
		return this.stripPx(Element.getStyle(element, 'top'));
	},

	getDefinedLeft: function(element)
		{
		return this.stripPx(Element.getStyle(element, 'left'));
	},

	getDefinedHeight: function(element)
		{
		return this.stripPx(Element.getStyle(element, 'height'));
	},

	getDefinedWidth: function(element)
		{
		return this.stripPx(Element.getStyle(element, 'width'));
	},

	oddEven: function(elements)
		{
		$A(elements).each(function(element, index)
			{
			if (index % 2 == 0)
			{
				Element.removeClassName(element, 'odd');
				Element.addClassName(element, 'even');
			}
			else
			{
				Element.removeClassName(element, 'even');
				Element.addClassName(element, 'odd');
			}
		});
	}
};

document.getElementsByIdRegex = function(root, regex, acc)
	{
	if (root.id && regex.test(root.id))
		acc.push(root);
	$(root.childNodes).each(function(child)
		{
		this.getElementsByIdRegex(child, regex, acc);
	}.bind(this));
};

String.prototype.enumToCamelCase = function()
	{
	return this.replace(/_/, '-').toLowerCase().toLowerCamelCase();
};

String.prototype.toLowerCamelCase = function()
	{
	var camelized = this.camelize();
	return camelized.charAt(0).toLowerCase() + camelized.substring(1);
};

String.prototype.trim = function()
	{
	return this.replace(/(^\s*)|(\s*$)/g, '');
};

Element.getChildWithNodeName = function(parent, nodeName)
	{
	nodeName = nodeName.toLowerCase();
	return $A(parent.childNodes).detect(function(child)
		{
		return child.nodeName.toLowerCase() == nodeName;
	});
};
P4.Util.KeyWatcher = Class.create({
	initialize: function(code)
		{
		this.down = false;
		document.observe('keydown', function(event)
			{
			if (event.keyCode == code)
				this.down = true;
		}.bindAsEventListener(this));
		document.observe('keyup', function(event)
			{
			if (event.keyCode == code)
				this.down = false;
		}.bindAsEventListener(this));
	}
});