
var FancyForms = {
	initialize: function() {

		this.selects = $$("select");
		this.checkboxesAndRadios = $$("input[type='checkbox'], input[type='radio']");
		this.checkboxRadioSpans = [];

		// insert spans for each select list
		this.selects.each(function(currentSelect) {
			var options = currentSelect.select("option");
			var selectedText = options.find(function(currentOption) {
				return currentOption.selected;
			}).childNodes[0].nodeValue;
			var wrapperSpan = new Element("span", { "class": "select_wrapper" });
			var replacementSpan = new Element("span", { "class": "select " + currentSelect.className }).update(selectedText);
			wrapperSpan.insert({ top: replacementSpan });
			currentSelect.insert({ before: wrapperSpan });
			currentSelect.addClassName("styled");
		});

		// insert spans for each radio button and checkbox
		this.checkboxesAndRadios.each(function(currentEl) {
			var replacementSpan = new Element("span", { "class": currentEl.type + " " + currentEl.type + (currentEl.checked ? "_checked" : "_unchecked") });
			currentEl.insert({ before: replacementSpan });
			this.checkboxRadioSpans.push(replacementSpan);
			currentEl.addClassName("styled");
		} .bind(this));

		this.registerEventHandlers();
	},
	registerEventHandlers: function() {
		this.selects.invoke("observe", "change", this.__selectChange.bindAsEventListener(this));
		this.selects.invoke("observe", "keydown", this.__keyboardSelect.bindAsEventListener(this));
		this.checkboxRadioSpans.invoke("observe", "mousedown", this.__push.bindAsEventListener(this));
		this.checkboxRadioSpans.invoke("observe", "mouseup", this.__check.bindAsEventListener(this));

		if (isIE) {
			/* IE doesn't fire "change" for checkboxes or radio buttons so you need to 
			observe focus and the spacebar keyup event to fake it. */
			this.checkboxesAndRadios.invoke("observe", "focus", this.__setToCurrentState.bindAsEventListener(this));
			this.checkboxesAndRadios.invoke("observe", "keyup", function(e) {
				if (e.keyCode == 32) {
					this.__setToCurrentState.bind(this).defer();
				}
			} .bind(this));
		} else {
			this.checkboxesAndRadios.invoke("observe", "change", this.__setToCurrentState.bindAsEventListener(this));
		}
	},
	__push: function(e) {
		var span = e.element();
		var input = span.next("input");
		span.className = input.type + " " + input.type + (input.checked ? "_checked_pushed" : "_unchecked_pushed");

		// in case you mousedown on a checkbox/radiobutton, move your mouse away, and let go
		document.observe("mouseup", function(e) {
			span.className = input.type + " " + input.type + (input.checked ? "_checked" : "_unchecked");
		});

	},
	__check: function(e) {
		var span = e.element();
		var input = span.next("input");
		if (input.checked) {
			span.className = input.type + " " + input.type + "_unchecked";
			input.checked = false;
		} else {
			span.className = input.type + " " + input.type + "_checked";
			input.checked = true;
		}

		/* uncheck all other radio buttons in the same group and
		make sure you cannot uncheck an already checked radio button */
		if (input.type == "radio") {
			var groupRadios = $$("input[name='" + input.name + "']").without(input);
			groupRadios.each(function(currentRadio) {
				currentRadio.previous("span").className = input.type + " " + input.type + "_unchecked";
				currentRadio.checked = false;
			});
			span.className = input.type + " " + input.type + "_checked";
			input.checked = true;
			input.fire('radio:checked');
		} else if (input.type == "checkbox") {
			input.fire('checkbox:checked');
		}
	},
	__setToCurrentState: function(e) {
		var input = e.findElement();

		if (input.type == "radio") {
			input.fire('radio:checked');
		} else if (input.type == "checkbox") {
			input.fire('checkbox:checked');
		}

		this.checkboxesAndRadios.each(function(currentEl) {
			if (currentEl.checked) {
				currentEl.previous("span").className = currentEl.type + " " + currentEl.type + "_checked";
			} else {
				currentEl.previous("span").className = currentEl.type + " " + currentEl.type + "_unchecked";
			}
		});
	},
	__keyboardSelect: function(e) {
		var select = e.element();
		var span = select.previous("span").down("span");
		var options = select.select("option");
		var currentOption = options.find(function(currentOption) {
			return currentOption.selected;
		});
		if ((e.keyCode == Event.KEY_DOWN || e.keyCode == Event.KEY_RIGHT) && currentOption.next("option")) {
			span.update(currentOption.next("option").childNodes[0].nodeValue);
		} else if ((e.keyCode == Event.KEY_UP || e.keyCode == Event.KEY_LEFT) && currentOption.previous("option")) {
			span.update(currentOption.previous("option").childNodes[0].nodeValue);
		} else if (e.keyCode == Event.KEY_PAGEDOWN || e.keyCode == Event.KEY_END) {
			span.update(options[options.length - 1].childNodes[0].nodeValue);
		} else if (e.keyCode == Event.KEY_PAGEUP || e.keyCode == Event.KEY_HOME) {
			span.update(options[0].childNodes[0].nodeValue);
		}
	},	
	
	__selectChange: function(e) {
		var select = e.element();
		var span = select.previous("span").down("span");
		var options = select.select("option");
		var value = options.find(function(currentOption) {
			return currentOption.selected;
		}).childNodes[0].nodeValue;
		span.update(value);
	}
}

document.observe("dom:loaded", function(){
	FancyForms.initialize();	
});
