Event.observe(window, "load", function()
{
	var forms = $$('form');

	for(var i = 0; i < forms.length; i++)
	{
		new Changable(forms[i]);
	}
	
	var activations = $(document.body).select('.activate');
	
	for(var i = 0; i < activations.length; i++)
	{
		if(activations[i].activate)
		{
			activations[i].activate();
			break;
		}
	}
});

if(!window.Forms)
{
	window.Forms = {};
}

Object.extend(window.Forms, 
{
	forms: new Hash(),
	
	callbacks: new Array(),
	
	initialize: function()
	{
		document.observe('keydown', this.keydown.bindAsEventListener(this));
	},
	
	keydown: function(inEvent)
	{
		if(inEvent.keyCode == Event.KEY_RETURN && inEvent.element().tagName.toLowerCase() != 'textarea')
		{
			Event.stop(inEvent);

			return false;
		}
	},

	add: function(inForm)
	{
		this.forms.set(inForm.name, inForm);
	},
	
	get: function(inName)
	{
		this.forms.get(inName);
	},
	
	addCallback: function(inAction)
	{
		this.callbacks.push(inAction);
	},

	submit: function()
	{
		var name;
		
		var hidden;
		
		for(var i = 0; i < arguments.length; i++)
		{
			if(Object.isString(arguments[i]))
			{
				name = arguments[i];
			}
			else
			{
				hidden = arguments[i];
			}
		}
	
		if(!name)
		{
			var form = document.body.select("form").first();

			if(form)
			{
				name = form.identify();
			}
		}

		var form = this.forms.get(name);

		if(form)
		{
			if(hidden)
			{
				var hiddens = new Hash(hidden);
				
				var keys = hiddens.keys();
				
				for(var i = 0; i < keys.length; i++)
				{
					var value = hiddens.get(keys[i]);
					
					if(!value)
					{
						value = "true";
					}
				
					form.element.insert({bottom: "<input type='hidden' name='" + keys[i] + "' value='" + value + "'>"});
				}
			}

			form.update();

			form.element.submit();
			
			return true;
		}
		
		return false;
	},
	
	submitUpdate: function(inHidden)
	{
		this.submit(null, inHidden);
	},
	
	submitDestination: function(destination, inHidden)
	{
		var sourceElement = $('source');
	
		if(destination == null || destination.length == 0)
		{
			destination = sourceElement.value;
		}
	
		if(destination.substring(destination.length - 1) == "_")
		{
			if(sourceElement)
			{
				var sourceParts = sourceElement.value.split("_");
			
				for(var i = 2; i < sourceParts.length; i++)
				{
					if(!destination.endsWith("_"))
					{
						destination += "_";
					}
					
					destination += sourceParts[i];
				}
			}
		}

		$('destination').value = destination;			

		this.submit(sourceElement.form.getAttribute('id'), inHidden);
	},

	maxLength: function(element, inMaxLength)
	{
		if(element.value.length > inMaxLength)
		{
			element.value = element.value.substring(0, inMaxLength);
		}
	}
});

Forms.initialize();

// ---------

var Changable = Class.create(
{
	initialize: function(inElement)
	{
		this.element = $(inElement);

		this.name = this.element.identify();
		
		this.checked = false;

		this.original = new Hash();

		var changedID = this.element.identify() + "_changed";

		this.changed = this.element.insert({bottom: "<input type='hidden' name='" + changedID + "'>"}).childElements().last();

		var elements = this.element.getElements();

		for(var i = 0; i < elements .length; i++)
		{
			if(elements[i].name.length > 0)
			{
				if(elements[i].hasClassName("empty"))
				{
					this.original.set(elements[i].name, "");
				}
				else
				{
					this.original.set(elements[i].name, elements[i].value);
				}
					
				if(elements[i].present)
				{
					elements[i].present = elements[i].present.wrap(function(proceed)
					{ 
						if(this.hasClassName("empty"))
						{ 
							return false;
						}
						else
						{ 
							return proceed(); 
						} 
					}); 
				}
			}
		}

		this.element.observe('submit', this.update.bindAsEventListener(this));
		
		Forms.add(this);	
	},

	update: function(event)
	{
		if(this.checked)
		{
			if(event)
			{
				Event.stop(event);
			}

			return;
		}
		
		this.checked = true;

		for(var i = 0; i < Forms.callbacks.length; i++)
		{
			try
			{
				eval(Forms.callbacks[i]);
			}
			catch(e)
			{
				Event.stop(event);
				
				return;
			}
		}

		var changedFields = [];
		var elements = this.element.getElements();

		for(var i = 0; i < elements.length; i++)
		{
			if(elements[i].name.length > 0)
			{
				if(elements[i].type == 'select-one' || elements[i].type == 'select-multiple')
				{
					for(var j = 0; j < elements[i].options.length; j++)
					{
						if((elements[i].options[j].selected && !elements[i].options[j].defaultSelected) ||
						  (!elements[i].options[j].selected &&  elements[i].options[j].defaultSelected))
						{
							changedFields.push(elements[i].name);
			
							break;
						}
					}
				}
				else if(elements[i].type == 'checkbox' || elements[i].type == 'radio')
				{
					if((elements[i].checked && !elements[i].defaultChecked) ||
					  (!elements[i].checked &&  elements[i].defaultChecked))
					{
						changedFields.push(elements[i].name);
					}
				}
				else 
				{
					if(elements[i].hasClassName("empty"))
					{
						elements[i].value = "";
					}
					
					if(elements[i].value != this.original.get(elements[i].name))
					{
						changedFields.push(elements[i].name);
					}
				}
			}
		}

		if(changedFields.length > 0)
		{
			this.changed.value = changedFields.join(",");
		}
	}
});

var AutoLabel = Class.create(
{
	initialize: function(element, label)
	{
		this.element = $(element);
		this.label	= label;
		this.element.observe('blur',	this.blur.bindAsEventListener(this));
		this.element.observe('focus',	this.focus.bindAsEventListener(this));
		this.update(false);
	},
	
	blur: function(event)
	{
		this.update(false);
	},
	
	focus: function(event)
	{
		this.update(true);
	},
	
	update: function(focused)
	{
		if(this.element)
		{
			if(focused)
			{
				if(this.element.hasClassName("empty"))
				{
					if(this.element.value == this.label)
					{
						this.element.value = "";
					}
					
					this.element.removeClassName("empty");
					
					this.element.style.color = "";
				}
			}
			else
			{
				if(this.element.value.length == 0)
				{
					this.element.value = this.label;
					
					this.element.addClassName("empty");
				}
			}
		}
	}
});

var AutoComplete = Class.create(
{
	initialize: function(inElement, inOptions)
	{
		this.element = $(inElement);
		
		if(!this.element)
		{
			return;
		}
	
		this.options = {
			url: null,
			onIncomplete: null
		};
		
		Object.extend(this.options, inOptions);
		
		this.position = -1;
		this.typed = this.element.value;
		
		if(!this.popup)
		{
			this.popup = this.element.insert({after: "<div class='input menu autocomplete' style='display:none'></div>"}).next();
		}
		
		this.element.observe('blur',	this.blur.bindAsEventListener(this));
		this.element.observe('keydown',	this.keydown.bindAsEventListener(this));
		this.element.observe('keyup',	this.keyup.bindAsEventListener(this));
		this.popup.observe('mousemove', this.mousemove.bindAsEventListener(this));
	},
	
	blur: function(event)
	{
		this.hide();
	},
	
	hide: function()
	{
		if(this.popup)
		{
			this.position = -1;
			this.popup.setStyle({display:"none"});
		}
	},
	
	keydown: function(event)
	{
		if(event.keyCode == Event.KEY_DOWN)
		{
			this.hilite(this.position + 1);
			
			Event.stop(event);
		}
		else if(event.keyCode == Event.KEY_UP)
		{
			this.hilite(this.position - 1);
			
			Event.stop(event);
		}
		else if(event.keyCode == Event.KEY_BACKSPACE || event.keyCode == Event.KEY_DELETE)
		{
			this.hide();
		}
		else if(event.keyCode == Event.KEY_RETURN)
		{
			Event.stop(event);
		}
	},
	
	keyup: function(event)
	{
		if(event.keyCode == Event.KEY_DOWN || event.keyCode == Event.KEY_UP)
		{
			Event.stop(event);
		}
		else if(event.keyCode == Event.KEY_RETURN)
		{
			Event.stop(event);

			this.hide();
		}
		else if(event.keyCode == Event.KEY_BACKSPACE || event.keyCode == Event.KEY_DELETE)
		{
			this.reset();
		}
		else
		{
			this.update();
		}
	},

	mousemove: function(event)
	{
		var element = event.element();
		
		var position = this.position;
		
		if(element.hasClassName("item"))
		{
			var items = this.popup.select(".item");
			
			for(var i = 0; i < items.length; i++)
			{
				if(items[i] == element)
				{
					position = i;
					
					break;
				}
			}
		}
		else
		{
			position = -1;
		}
		
		this.hilite(position);
	},
	
	reset: function()
	{
		if(this.options.onIncomplete)
		{
			this.options.onIncomplete();
		}
	},
	
	update: function()
	{
		this.typed = this.element.value;
		
		if(this.typed.length == 0)
		{
			this.hide();
			return;
		}
		
		if(!this.request)
		{
			this.request = new Ajax.Request(this.options.url,
			{
				parameters: { text: this.typed, id: this.element.identify() },
				onComplete: this.processResponse.bind(this)
			});
		}
	},
	
	hilite: function(inPosition, inFeedback)
	{		
		if(!this.items)
		{
			this.items = this.popup.select(".item");
		}
		
		if(inPosition >= this.items.length)
		{
			inPosition = this.items.length - 1;
		}
		else if(inPosition < -1)
		{
			inPosition = -1;
		}

		if(this.items.length > 0 && this.position != inPosition)
		{
			for(var i = 0; i < this.items.length; i++)
			{
				this.items[i].removeClassName("selected");
			}

			var value = this.typed;
		
			if(inPosition >= 0)
			{
				this.items[inPosition].addClassName("selected");
			
				value = this.items[inPosition].select(".value").first().innerHTML;
		
				var actionElement = this.items[inPosition].select(".action").first();
				
				if(actionElement)
				{
					eval(actionElement.innerHTML);
				}
			}

			if(!inFeedback || inFeedback == this.element.value)
			{
				this.updateValue(value, inFeedback);
			}
			
			this.popup.setStyle({display:""});
		}
		
		this.position = inPosition;
		
		document.fire("behavior:change");
	},
	
	updateValue: function(inValue, inFeedback)
	{
		if(!inFeedback || this.element.selectionStart == this.element.selectionEnd)
		{
			this.element.value = inValue;
			
			var from = 0;
			var to = this.element.value.length;
		
			if(this.element.value.toLowerCase().startsWith(this.typed.toLowerCase()))
			{
				from = this.typed.length;
			}
	
			this.element.selectionStart = from;
			this.element.selectionEnd = to;
		}
	},
	
	processResponse: function(inResponse)
	{
		var feedback = eval(inResponse.getHeader("autocomplete"));
	
		if(this.typed == feedback)
		{
			if(inResponse.status == 200 && inResponse.responseText.length > 0)
			{
				this.popup.update(inResponse.responseText);
				
				if(this.popup.style.display == "none")
				{
					var position = this.element.positionedOffset();
					var dimensions = this.element.getDimensions();
				
					this.popup.setStyle(
					{
						minWidth: dimensions.width + "px",
						position: "absolute",
						display: "block",
						zIndex: 100,
						left: position.left + "px",
						top: (position.top + dimensions.height + 2) + "px"
					});
				}
				
				this.position = -1;
				this.items = this.popup.select(".item");
		
				for(var i = 0; i < this.items.length; i++)
				{
					var value = this.items[i].select(".value").first().innerHTML;
		
					if(value.toLowerCase().startsWith(feedback.toLowerCase()))
					{
						this.hilite(i, feedback);
						break;
					}
				}
			}
			else
			{
				this.popup.update("");
				this.popup.setStyle({display:"none"});
				this.items = null;
				this.position = -1;
				this.reset();
			}
		}
		
		this.request = null;
	}
});
