/** 
* Copyright 2006-2007 massimocorner.com
* License: http://www.massimocorner.com/license.htm
* @author      Massimo Foti (massimo@massimocorner.com)
* @version     0.3.1, 2007-01-28
* @require     tmt_form.js
*/

if(typeof(tmt) == "undefined"){
	alert("Error: tmt.core JavaScript library missing");
}

tmt.form = {};

// Constants
tmt.form.MESSAGE_CLASS = "tmtFormMessage";
tmt.form.ERROR_MESSAGE_CLASS = "tmtFormErrorMessage";

/**
* Check a set of form fields (radio or checkboxes)
*/
tmt.form.checkFields = function(){
	tmt.setNodeAttribute(arguments, "checked", true);
}

/**
* Uncheck a set of form fields (radio or checkboxes)
*/
tmt.form.uncheckFields = function(){
	tmt.setNodeAttribute(arguments, "checked", false);
}

/**
* Toggle the checked attribute on a set of form fields. If it's true it set it to false and viceversa
*/
tmt.form.toggleCheckFields = function(){
	for(var i=0; i<arguments.length; i++){
		var fieldNode = tmt.get(arguments[i]);
		if(fieldNode){
			fieldNode.checked ? fieldNode.checked = false : fieldNode.checked = true;
		}
	}
}

/**
* Programmatically select options inside a <select> tag
* The first argument can be a DOM node, the id or the name of the <select>
* In case of multiple tags sharing the same name the first fund in the document will be used
* The second argument can be a simple value or a comma-delimited list (for select-multiple)
*/
tmt.form.checkSelect = function(theNode, values){
	// Split in case we got a comma-separated list (for select-multiple)
	var valueArray = values.split(",");
	var selectNode = tmt.get(theNode);
	// If what we get is a name, use the first node matching the name
	if(selectNode == null){
		selectNode = document.getElementsByName(theNode)[0];
	}
	for(var i=0; i<selectNode.options.length; i++){
		for(var j=0; j<valueArray.length; j++){
			if(valueArray[j] == tmt.form.getOptionNodeValue(selectNode.options[i])){
				selectNode.options[i].selected = true;
			}
		}
	}
}

/**
* Programmatically de-select options inside a <select> tag
* The first argument can be a DOM node, the id or the name of the <select>
* In case of multiple tags sharing the same name the first fund in the document will be used
*/
tmt.form.resetSelect = function(theNode){
	var selectNode = tmt.get(theNode);
	// If what we get is a name, use the first node matching the name
	if(selectNode == null){
		selectNode = document.getElementsByName(theNode)[0];
	}
	for(var i=0; i<selectNode.options.length; i++){
		selectNode.options[i].selected = false;
	}
}

/**
* Programmatically check radio buttons or checkboxes based on their values
* The first argument is the name of the group
* The second argument can be a simple value or a comma-delimited list (for checkboxes)
*/
tmt.form.checkGroup = function(groupName, values){
	// Split in case we got a comma-separated list (for checkboxes)
	var valueArray = values.split(",");
	var groupNodes = document.getElementsByName(groupName);
	for(var i=0; i<groupNodes.length; i++){
		for(var j=0; j<valueArray.length; j++){
			if(groupNodes[i].value == valueArray[j]){
				groupNodes[i].checked = true;
			}
		}
	}
}

/**
* Uncheck a whole group of radio buttons or checkboxes
*/
tmt.form.resetGroup = function(groupName){
	var groupNodes = document.getElementsByName(groupName);
	for(var i=0; i<groupNodes.length; i++){
		groupNodes[i].checked = false;
	}
}

/**
* Disable a set of form fields
*/
tmt.form.disableFields = function(){
	tmt.setNodeAttribute(arguments, "disabled", true);
}

/**
* Enable a set of form fields
*/
tmt.form.enableFields = function(){
	tmt.setNodeAttribute(arguments, "disabled", false);
}

/**
* Toggle the disabled attribute on a set of form fields. If it's true it set it to false and viceversa
*/
tmt.form.toggleEnableFields = function(){
	for(var i=0; i<arguments.length; i++){
		var fieldNode = tmt.get(arguments[i]);
		if(fieldNode){
			fieldNode.disabled ? fieldNode.disabled = false : fieldNode.disabled = true;
		}
	}
}

/**
* Return the container <form> of a given node. Return false if the node isn't contained inside a form
*/
tmt.form.getParentForm = function(startNode){
	var parentObj = startNode.parentNode;
	while(parentObj){
		if(parentObj.tagName.toLowerCase() == "form"){
			return parentObj;
		}
		else{
			parentObj = parentObj.parentNode;
			continue;
		}
	}
	// The field is outside of a form
	return false; 
}

/**
* Given an option node, return its value. If no value is available, return its text
*/
tmt.form.getOptionNodeValue = function(optionNode){
	var optionValue = optionNode.value;
	if(!optionValue){
		optionValue = optionNode.text;
	}
	return optionValue;
}

/**
* Return an array of submit button nodes contained inside a given node
*/
tmt.form.getSubmitNodes = function(startNode){
	var submitArray = [];
	var inputNodes = startNode.getElementsByTagName("input");
	for(var i=0; i<inputNodes.length; i++){
		if(inputNodes[i].getAttribute("type").toLowerCase() == "submit"){
			submitArray[submitArray.length] = inputNodes[i];
		}
	}
	return submitArray;
}

/**
* Assembles form name/value pairs and return them inside an encoded string
*/
tmt.form.serializeForm = function(formNode, demoronize){
	var values = [];
	for(var i = 0; i < formNode.elements.length; i++){
		var fieldNode = formNode.elements[i];
		// Skip fieldsets and field without name attribute
		if(!fieldNode || !fieldNode.name || fieldNode.tagName.toLowerCase() == "fieldset"){
			continue;
		}
		var fieldName = encodeURIComponent(fieldNode.name);
		var fieldType = fieldNode.type.toLowerCase();
		// Handle different kind of fields
		switch(fieldType){
			case "select-multiple":
				for(var j = 0; j < fieldNode.options.length; j++){
					if(fieldNode.options[j].selected){
						values.push(fieldName + "=" + encodeURIComponent(tmt.form.getOptionNodeValue(fieldNode.options[j])));
					}
				}
				break;
			case "select-one":
				for(var k = 0; k < fieldNode.options.length; k++){
					if(fieldNode.options[k].selected){
						values.push(fieldName + "=" + encodeURIComponent(tmt.form.getOptionNodeValue(fieldNode.options[k])));
						break;
					}
				}
				break;
			// Radio and checkboxes get handled the same way
			case "radio":
			case "checkbox":
				if(fieldNode.checked){
					values.push(fieldName + "=" + encodeURIComponent(fieldNode.value));
				}
				break;
			// Skip reset
			case "reset":
				break;
			// Skip buttons
			case "button":
				break;
			// default handles all the text fields
			default:
				var fieldValue = fieldNode.value;
				// Get rid of Word's garbage if required
				if(demoronize){
					fieldValue = tmt.form.stringDemoronizer(fieldNode.value);
				}
				values.push(fieldName + "=" + encodeURIComponent(fieldValue));
				break;
		}
	}
	return values.join("&");
}

/**
* Display a message a message above a given form node
*/
tmt.form.displayMessage = function(formNode, html){
	tmt.form.displayBox(formNode, html, tmt.form.MESSAGE_CLASS);
}

/**
* Display a message an error message above a given form node
*/
tmt.form.displayErrorMessage = function(formNode, html){
	tmt.form.displayBox(formNode, html, tmt.form.ERROR_MESSAGE_CLASS);
}

/**
* Display a box with a message above a given form node
* Overwrite this method if you want to change the way tmt.form.displayMessage and tmt.form.displayErrorMessage behaves
*/
tmt.form.displayBox = function(formNode, html, cssClass){
	if(!cssClass){
		cssClass = tmt.form.MESSAGE_CLASS;
	}
	// Create a <div> that will act as an error display
	var displayNode = document.createElement("div");
	// Create an id that will identify the errors who belongs to this specific form and assign it to the <div>
	var errorId = "tmtFormMessageBox";
	if(formNode.getAttribute("id")){
		errorId += formNode.getAttribute("id");
	}
	else if(formNode.getAttribute("name")){
		errorId += formNode.getAttribute("name");
	}
	displayNode.setAttribute("id", errorId);
	displayNode.className = cssClass;
	displayNode.innerHTML = html;		
	var oldDisplay = document.getElementById(errorId);
	// If an error display is already there, we replace it, if not, we create one from scratch 
	if(oldDisplay){
		formNode.parentNode.replaceChild(displayNode, oldDisplay); 
	}
	else{
		formNode.parentNode.insertBefore(displayNode, formNode);
	}
}

/**
* Replace MS Word's non-ISO characters with plausible substitutes
*/
tmt.form.stringDemoronizer = function stringDemoronizer(str){
	str = str.replace(new RegExp(String.fromCharCode(710), "g"), "^");
	str = str.replace(new RegExp(String.fromCharCode(732), "g"), "~");
	// Evil "smarty" quotes
	str = str.replace(new RegExp(String.fromCharCode(8216), "g"), "'");
	str = str.replace(new RegExp(String.fromCharCode(8217), "g"), "'");
	str = str.replace(new RegExp(String.fromCharCode(8220), "g"), '"');
	str = str.replace(new RegExp(String.fromCharCode(8221), "g"), '"');
	// More garbage
	str = str.replace(new RegExp(String.fromCharCode(8211), "g"), "-");
	str = str.replace(new RegExp(String.fromCharCode(8212), "g"), "--");
	str = str.replace(new RegExp(String.fromCharCode(8218), "g"), ",");
	str = str.replace(new RegExp(String.fromCharCode(8222), "g"), ",,");
	str = str.replace(new RegExp(String.fromCharCode(8226), "g"), "*");
	str = str.replace(new RegExp(String.fromCharCode(8230), "g"), "...");
	str = str.replace(new RegExp(String.fromCharCode(8364), "g"), "€");
	return str;
}