var Menu = Class.create();
Menu.menuTimeout = null;
Menu.targets = [];

Menu.prototype = {
	initialize : function(link, target) {
		link = $(link);
		target = $(target);
		
		if (!link || !target)
		{
			// If either the link or the target doesn't exist, do nothing.
			return;
		}
		
		Menu.targets.push(target);
			
		Event.observe(link, "mouseover", function() {
			clearTimeout(Menu.menuTimeout);
			Menu.targets.each(Element.hide);
			Element.show(target);
		});
	
		Event.observe(link, "mouseout", function() {
			Menu.menuTimeout = setTimeout(function() {
				Element.hide(target);
			}, 1500);		
		});
	
		Event.observe(target, "mouseover", function() {
			clearTimeout(Menu.menuTimeout);
		});
	
		Event.observe(target, "mouseout", function() {
			Menu.menuTimeout = setTimeout(function() {
				Element.hide(target);
			}, 1500);
		});	
	}
};

var Overlay = Class.create();
Overlay.prototype = {
	setOptions: function(options) {
		this.options = {
			style : {},
			draggable : false,
			hideHandle : false
		}
		Object.extend(this.options, options || {});
		
		if(!this.options.style.width)
		{
			this.options.style.width = "550px";
		}
	},

	initialize: function(content, anchor, options) {
		this.setOptions(options);
	
		this.content = $(content);
		this.anchor = $(anchor);
		
		this.div = $(Builder.node('div', {
				className: 'overlayContainer'
			}));
		this.closeIcon = $(Builder.node('img', {
				src: '/images/icons/action_stop.gif',
				className: 'closeIcon'
			}));
		this.div.setStyle(this.options.style);
		this.div.hide();
		
		this.content.parentNode.replaceChild(this.div, this.content);
		this.div.appendChild(Builder.node('div', [ this.closeIcon, this.content ]));
		this.content.show();
		
		this.anchor.observe('click', this.show.bind(this));	
		this.closeIcon.observe('click', this.hide.bind(this));
		
		if(this.options.draggable)
		{
			new Draggable(this.div);
		}
	},
	
	show: function() {
		if(this.options.hideHandle)
		{
			new Effect.Fade(this.anchor, { queue: 'front', duration: .5 });
		}
		new Effect.Appear(this.div, { queue: 'end', duration: .5});
	},
	
	hide: function() {
		new Effect.SlideUp(this.div, { queue : 'front', duration: .5 });
		if(this.options.hideHandle)
		{
			new Effect.Appear(this.anchor, { queue : 'end', duration: .5 });
		}
	}
};

var Toggler = Class.create();
Toggler.prototype = {
	initialize: function(interestField, showValues, toggleFields, instantaneous) {
		interestField = $(interestField);
		showValues = [showValues].flatten();
		toggleFields = [toggleFields].flatten();
		instantaneous = instantaneous || false;
			
		Event.observe(interestField, "change", function() {
			
			var found = showValues.include($F(interestField));
			
			toggleFields.each(function(toggleField) {
				if ($(toggleField) != null)
				{
					if($(toggleField).nodeName == 'TR' || instantaneous)
					{
						found ? Element.show(toggleField) : Element.hide(toggleField);
					}
					else
					{
						found ? new Effect.Appear(toggleField) : new Effect.Fade(toggleField);
					}
				}
			});
		});
		
		var found = showValues.include($F(interestField));
		toggleFields.each(function(toggleField) {
			if ($(toggleField) != null)
			{
				if (found)
					Element.show(toggleField);
				else
					Element.hide(toggleField);
			}
		});
	}
};

var ExpandingEditor = Class.create();
ExpandingEditor.prototype = {
		
	initialize: function(smallInput) {
		smallInput = $(smallInput);
				
		Event.observe(smallInput, "focus", function() {		
			var numCols = smallInput.getAttribute("size") || 25;
			if (numCols < 25) numCols = 25;

			var largeInput = $(Builder.node("textarea", { cols : numCols, rows : 10 }, $F(smallInput)));
			largeInput.setStyle({border : 0});
			
			var div = $(Builder.node("div", largeInput));
			div.setStyle({
				border : "2px solid purple",
				background : "white",
				position: "absolute",
				display: "none"
			});
			smallInput.parentNode.appendChild(div);
			smallInput.setStyle({visibility : "hidden"}); // hide
			
			Position.clone(smallInput, div, { setWidth : false, setHeight : false});
										
			Event.observe(largeInput, "blur", function() {
				smallInput.value = $F(largeInput).gsub(/\s+/, " ");
				div.remove();
				smallInput.setStyle({visibility : "visible"});
			});
			
			var maxlength = smallInput.getAttribute("maxlength");
			if (maxlength)
			{
				new RestrictedLengthField(largeInput, maxlength);
			}
			
			// show and focus
			div.show();
			largeInput.focus();
		});
	}
};

var Totaller = Class.create();
Totaller.prototype = {
	fields : [],
	totalMarkup : undefined,

	initialize : function (fields, totalMarkup) {
		this.totalMarkup = $(totalMarkup);
		this.fields = fields;

		var boundUpdate = this.update.bind(this);
		fields.each(function(field) {
			field.observe("change", boundUpdate);
		});
		
		this.update();
	},
	
	update : function() {
		var total = 0;
		this.fields.each(function(f) { total += Number($F(f)) || 0; });
		this.totalMarkup.update("$" + total.toFixed(3));
	}
};

var Decimaller = Class.create();
Decimaller.decimate = function(value, places) {
	places = places || 2;
	
	if (value !== "" && !isNaN(Number(value)))
		return Number(value).toFixed(places);
	else
		return value;
}

Decimaller.prototype = {
	initialize : function(field, places) {
		field = $(field);
	
		field.value = Decimaller.decimate(field.value, places);
	
		Event.observe(field, "change", function() {
			field.value = Decimaller.decimate(field.value, places);
		});
	}
};

var AutoPopulateTracker = Class.create();
AutoPopulateTracker.prototype = {
	setClean : function() { this.clean = true; },
	setDirty : function() { this.clean = false; },
	onSubmitHandler : function(e) {
			if(!this.clean)
			{
				if (!confirm(this.warning))
				{
					Event.stop(e);
				}
			}
		},
	initialize: function(formToSubmit, description, populaterFields) {
			this.clean = true;

			var message =  "Changes were made to the " + description + " that were not populated to the rest of the form. ";
			message += "Click 'Cancel' to return to the page and make further changes.  Otherwise, click 'OK' to continue.";
			
			this.warning = message;
		
			if (populaterFields)
			{
				var dirtyFuncRef = this.setDirty.bind(this);
				
				populaterFields.each(function(field) {
					field = $(field);
					if (field)
					{
						Event.observe(field, "change", dirtyFuncRef);
					}
				});
			}
			
			Event.observe(formToSubmit, "submit", this.onSubmitHandler.bind(this));
		}
};


var RestrictedLengthField = Class.create();
RestrictedLengthField.prototype = {
	initialize : function(field, maximumLength) {
		field = $(field);

		var restrictLength = function() {
			setTimeout(function() {
				if ($F(field).length > maximumLength)
				{
					field.value = $F(field).substr(0, maximumLength);
					alert("You cannot exceed " + maximumLength + " characters for this field.");
				}
			}, 10);
		};

		Event.observe(field, "keypress", restrictLength);
		Event.observe(field, "blur", restrictLength);
	}
};

var UFNDateDisabler = Class.create();
UFNDateDisabler.prototype = {
	initialize : function(ufnCheckBox, dateField) {
		ufnCheckBox = $(ufnCheckBox);
		dateField = $(dateField);

		function toggleEnable()
		{
			if (ufnCheckBox.checked)
				dateField.disable();
			else
				dateField.enable();
		}

		function update()
		{
			dateField.value = "mm/dd/yyyy";
			toggleEnable();
		}

		toggleEnable(); // right now!
		Event.observe(ufnCheckBox, "click", update); // later, too!
	}	
};

function EventHandler(fn) {
	// when a function that expects an event reference needs
	// to be used as an event handler, use this, and the
	// magic will work
	
	return function(event) {
		var element = Event.element(event);
		fn(element);
	}
};
// usage: Event.observe("some-ref", "click", new EventHandler(functionThatExpectsAnElement));
