/**
 * Form building utility class
 * 
 * Providers methods to form input elements and manage form dependencies
 * 
 * @author Ollie Maitland
 * @copyright Byng Systems LLP
 * 
 * @package forms
 * 
 */

var jsFormBuilderCount = 0;

/**
 * Form Builder constructor
 * 
 * @param String formName Form ID reference name
 * @param Boolean Use dependencies
 */
function FormBuilder (formName, depend) 
{
	/**
	 * Set the form name for this instance
	 *
	 * @param String name
	 */
	this.setFormName = function (name)
	{
		this.formName = formName;	

		/**
		 * Holds the counter for the FormBuilder
		 *
		 * @param Int jsFormCount
		 */
		jsFormBuilderCount++;
	}

	/**
	 * Holds the form name of the current form
	 * 
	 * @param String formName
	 */
	if (formName) {
		this.setFormName (formName);	
	}

	/**
	 * Form input manipluation
	 *
	 * @param String value
	 * @param DomElement select
	 * @param FormBuilder builder
	 */
	this.chooseOther = function (value, select, builder) 
	{
		
		this.select = select;
		
		if (value != "") return;
		
		this.select.style.display = "none";
		
		this.input = this.elementFactory ("text", this.select.name);

		// Add the input block to the parent of the select block
		this.select.parentNode.appendChild (this.input);
		
		this.tag = this.getReturnTag ("Return", builder);
		
		// Add the tag to get back
		this.select.parentNode.appendChild (this.tag);

		this.input.focus();
		
	}
	
	/**
	 * Return back to a select drop down
	 * 
	 */ 
	this.returnFromOther = function () 
	{
		this.select.parentNode.removeChild (this.input);
		this.select.parentNode.removeChild (this.tag);
		
		// Now select the first from the list
		this.select.value = this.select.options[0].value;
		
		this.select.style.display = "inline";
	}
	
	/**
	 * Form element factory
	 * 
	 * @param String type DomElement tag type
	 * @param String name DomElement name
	 * @param String value DomElement input value
	 * @return DomElement
	 */ 
	this.elementFactory = function (type, name, value) 
	{	
		if (!type) type = "text";
		if (!value) value = "";

		var input = document.createElement("input");
			input.setAttribute ('type', type);
			input.setAttribute ('name', name);
			input.setAttribute ('value', value);
		
		return input;
	}
	
	/**
	 * Create a new form in DOM
	 * 
	 * @param String uri
	 * @param String name
	 * @param String action
	 * @return DomElement
	 */
	this.formFactory = function (uri, name, action)
	{
		var form = document.createElement("form");
			form.name = name;
			form.action = uri;
			form.method = "POST";
		//	form.style.visibility = 'none';
		
		var input = this.elementFactory("hidden","action", action);
			form.appendChild (input);

		return form;
	}

	/**
	 * Get a tag to return to the select drop down
	 * 
	 * @param String s
	 * @param FormBuilder builder
	 * @return String
	 */ 
	this.getReturnTag = function (s, builder)
	{
		var tag = document.createElement("span");
			tag.innerHTML = ' ( <a href="javascript:'+ (builder ? builder : "FormBuilder")+'.returnFromOther();">'+s+'</a> )';
		
		return tag;
	}
	
	/**
	 * Return the active input element
	 * 
	 * @return DomElement
	 */
	this.returnInput = function ()
	{
		return this.input;
	}
	
	/**
	 * Holds the form dependencies
	 *
	 * @see FormBuilder
	 * 
	 * @param Array
	 */
	this.depends = Array;		
	
	/**
	 * Set a dependeny
	 * 
	 * @param String f DomElement name
	 */ 
	this.setDepend = function (f) 
	{
		// retrieve the form
		this.form = ge(this.formName);
		
		// are there any dependencies for this field
		if (isObject(this.depends[f]) == false) return;	
		
		var depends = this.depends[f][0];
		var negate = this.depends[f][1];

		// check for presence of children
		if (isObject(depends) == false) return;	
	
		for (i=0; i<depends.length; i++) {
		
				
			// Get the dependee element
			element = depends[i];
			
			element = this.form.elements[element];

			// Check whether the parent is empty
			fparent = this.form.elements[f];

			//alert (typeof parent);
			switch (fparent.type) {
				case "checkbox" :
					active = fparent.checked;
				break;
				case "text" :

					if (fparent.value != "") { active = true; }
					else { active = false; }
				
				break;
				default: 		
				
					for (k=0;k<fparent.length;k++) {
						if (fparent[k].checked == true) {
							//alert (parent[k].value);
							active = fparent[k].value;
						}
					}			
					
			}

			// condition: dependency negated
			if (negate == true) {
				if (active == true) active = false;
				else active = true;
			}
			
			if (element.length) {

				if (element.type == "select-one") {
					// Select drop downs we just be disabled on the whole drop
					this.disableElement (element, active);
					
				} else {
					// Disable checkboxes and radios					
					for (k=0;k<element.length;k++) {
						this.disableElement (element[k], active);
					}
				}
						
			} else {
				this.disableElement (element, active);
			}

		}
		
	}
	
	/**
	 * Disable an element
	 * 
	 * @param DomElement element
	 * @param Boolean active
	 */ 
	this.disableElement = function  (element, active)
	{
		// condition: active is true
		if (active == true) {
			element.disabled = false;
			element.className = element.className.replace(/disabled/,'');
		} else {
			element.disabled = true;
			element.className = element.className + ' disabled';
		}
	}
	
	/**
	 * Add a dependency to the field
	 * 
	 * @param String f
	 * @param Array deps Dependencies for the DomElement f
	 * @param Boolean negate Negate the dependencies
	 */ 
	this.addDepend = function (f, deps, negate) 
	{	
		//this.depends[f] = new Array;
		this.depends[f] = [deps, negate];
	}
	
	/**
	 * Hydrate an XML request with a form
	 * 
	 * @param XmlPost postObj
	 * @param DomElement form Form to hydrate variables from
	 */
	this.hydrate = function (postObj, form) 
	{
		// Loop around the fieldset inputs
		var inputs = form.parentNode.getElementsByTagName("input");
		
		// Assign the inputs to the POST array
		for (k=0;k<inputs.length;k++)
		{
			switch (inputs[k].type) {
				case "file":
					throw inputs[k];
				break;
				case "radio":
				
					if (inputs[k].checked == true) {	
						postObj.addParam (inputs[k].name, inputs[k].value);
					}
					
				break;
				default: 
					postObj.addParam (inputs[k].name, inputs[k].value);
			}
		}
		
		// Look around the fieldset textarea tags
		var textareas = form.parentNode.getElementsByTagName("textarea");
		
		for (k=0;k<textareas.length;k++)
		{
			postObj.addParam (textareas[k].name, textareas[k].value);
		}
		
		// Loop around the fieldset <select>
		var selects = form.parentNode.getElementsByTagName("select");
		
		// Assign the inputs to the POST array
		for (k=0;k<selects.length;k++)
		{
			postObj.addParam (selects[k].name, selects[k].value);
		}		
		
		return postObj;
	}

 	/**
	 * Run form event
	 * 
	 * Method provides abstraction to the JavaScript environment from FormBuilder
	 * 
	 * @param DomElement _element
	 * @param String fn Event to run
	 */
	this.runEvent = function (_element, fn) 
	{
		try {
 			eval (fn);
		} catch (e) {
			alert ("Invalid form event: " + e.toString());
		}
		
	}	
}