var html5Forms = new function(){
	var me = this;
	
	
	var delayEventTimeout = null;
	
	me.timer = new Timer(me);
	
	me.inputNodes = new Array();
	me.outputNodes = new Array();
	
	var quoteRe = /\"/g;
	
	var dummyIDCount = 0;
	var supportsOutputNatively = false;
	
	me.init = function(){
		if (EventHelpers.hasPageLoadHappened(arguments)) {
			return;
		}
		// jslog.debug('initing');
		
		indexOutputNodes();
		insertElements();
		me.resolveOutputs();
	}
	
	
	
	
	
	function getNextDummyID () {
		dummyIDCount ++;
		return "id" + dummyIDCount;
	}
	
	function indexOutputNodes () {
		var outputElements = document.getElementsByTagName('output');
		for (var i=0; i<outputElements.length; i++) {
			var outputEl = outputElements[i];
			if (outputEl.value != undefined) {
				// this browser supports the output tag .. bail
				supportsOutputNatively = true;
				break;
			}
			me.outputNodes.push(new OutputElement(outputEl))
		}
		// jslog.debug('outputs: ' + outputElements.length)
	}
	
	function insertElements(){
		// jslog.debug('inserting elements')
		
		
		// Remove the onload event as we are creating the sliders with a JS call
		fdSliderController.removeOnLoadEvent();
		
		var formElements = cssQuery('input, textarea, select');
		
		// leave if this browser supports the range type.
		if (formElements.length <= 0) {
			return;
		}
		jslog.debug('length ' + formElements.length);
		for (var i = 0; i < formElements.length; i++) {
			
			
			var formElement = formElements[i];
			
			// first - set event to resolve output tags
			EventHelpers.addEvent(formElement, 'change', me.resolveOutputs);
			
			
			// jslog.debug('form element: ' + XMLHelpers.getOuterXML(formElement))
			var elType = getAttributeValue(formElement, 'type');
			// jslog.debug(elType)
			switch (elType) {
				case "range":
					
					// check to see if the browser supports range.
					if (formElement.type != 'range') {
						me.inputNodes.push(new RangeElement(formElement));
					}
					break;
					
				case "date": 
				case "week":
				case "month":
				case "datetime":
					// check to see if the browser supports range.
					if (formElement.type != elType) {
						
						me.inputNodes.push(new CalendarElement(formElement, elType));
					}
					break;
				case "color":
					if (formElement.type != elType) {
						me.inputNodes.push(new ColorElement(formElement, elType));
					}
					
					break;
			}
			
		}
		
		
		fdSliderController.redrawAll();
		
		if (window.jscolor) {
			jscolor.init();
		}
	}
	
	function getAttributeValue(node, type) {
		var typeRe = new RegExp(type + '=([\"a-zA-Z]*)');
		var typeVal = XMLHelpers.getOuterXML(node).match(typeRe);
		if (typeVal && typeVal.length >= 1) {
			return typeVal[1].replace(quoteRe, '');
		} else {
			return null;
		}
	}
	
	
	
	function delayedFireEvent(el, ev){
			
			if (!document.createEventObject ) {
				me.fireEvent(el, ev);
			}
			else {
				if (delayEventTimeout != null) {
					me.timer.clearTimeout(delayEventTimeout)
				}
				// jslog.debug('timeout: ' + delayEventTimeout)
				delayEventTimeout = me.timer.setTimeout('fireEvent', 1, el, ev);
				//	delayEventTimeout = me.timer.setTimeout('fireEvent', 10, el, ev);
			}
		}
		
	me.fireEvent = EventHelpers.fireEvent;
	
	me.resolveOutputs = function () {
		for (var i=0; i<me.outputNodes.length; i++) {
			var outputNode = me.outputNodes[i];
			outputNode.resolve();
		}
	}
	
	me.hideInput = function (node) {
		node.style.position = 'absolute';
		node.style.top = '-1000px';
		node.style.left = '-1000px';
		node.style.visibility = 'hidden'
	}
	
	
			
	
	
	
	/*
	 * Range Element
	 */
	
	function RangeElement(node){
		var me = this;
		
		me.node = node;
		me.sliderNode = null;
		
		function init (){
			var min = parseFloat(DOMHelpers.getAttributeValue(me.node, 'min'));
			var max = parseFloat(DOMHelpers.getAttributeValue(me.node, 'max'));
			
			if (isNaN(min)) {
				min = 0;
			}
			
			if (isNaN(max)) {
				max = 100;
			}
			
			
			var step = DOMHelpers.getAttributeValue(me.node, 'step');
			
			
			
			if (!step) {
				step = "1"
			}
			
			// Must add id if not there (Requirement of the script)
			if (!me.node.id) {
				me.node.id = "HTML5Form-slider" + getNextDummyID();
			}
			
			// Create an Object to hold the slider's initialisation data
			var options = {
				// A reference to the input
				inp: me.node,
				// A String containing the increment value (and the return precision, in this case 2 decimal places "x.20")
				inc: step,
				// Maximum keyboard increment (automatically uses double the normal increment if not given)
				maxInc: step,
				// Numeric range
				range: [min, max],
				// Callback functions
				callbacks: {
					"update": [me.changeEvent]
				},
				// String representing the classNames to give the created slider
				classNames: "html5Forms-slider fd_jump",
				// Tween the handle onclick?
				tween: false,
				// Is this a vertical slider
				vertical: false,
				// Do we hide the associated input on slider creation
				hideInput: false,
				// Does the handle jump to the nearest click value point when the bar is clicked (tween cannot then be true)
				clickJump: true,
				// Full ARIA required
				fullARIA: false,
				// Do we disable the mouseWheel for this slider
				noMouseWheel: false
			
			};
			
			// Create the slider
			fdSliderController.createSlider(options);
			
			//tweak styles
			me.sliderNode = document.getElementById('fd-slider-' + me.node.id);
			me.sliderNode.style.width = me.node.offsetWidth + "px";
			
			elDisplay = me.node.style.display
			if (elDisplay != 'block') {
				me.sliderNode.style.display = 'inline-block';
			//me.sliderNode.style.paddingTop = "0.9em";
			}
			
			html5Forms.hideInput(me.node);
			
			document.getElementById('fd-slider-' + me.node.id).style.zIndex = '0';
		
			me.node.tabIndex = "-1";
			me.node.type = "text";
		
		}
		
		me.changeEvent = function (e){		
			delayedFireEvent(me.node, 'change');
			
		}
		
		init();
		
	}
	
	function CalendarElement (node, type) {
		var me = this;
		
		me.node = node;
		
		
		function init() {
			
			// Must add id if not there (Requirement of the script)
			if (!me.node.id) {
				me.node.id = "HTML5Form-calendar" + getNextDummyID();
			}
			
			
			var formatString = "";
			switch (type) {
				case 'date':
					formatString = "%Y-%m-%d";
					break;
				case 'month':
					formatString = "%Y-%m";
					break;
				case 'week':
					formatString = "%Y-W%W";
					break;
				case 'datetime':
					formatString = "%Y-%m-%d %H:%M"
					break;
			}
			
			me.node.readOnly = true;
			
			
			
			Calendar.setup(
			    {
				  eventName   :"focus",
				  showsTime   : type.indexOf('time') >= 0,
				  //cache		  : true,
			      inputField  : me.node.id,      // ID of the input field
			      ifFormat    : formatString,    // the date format
			      button      : me.node.id       // ID of the button
			    }
  			);
			
			
			
			//EventHelpers.addEvent(me.node, 'focus', openCalendar);
			EventHelpers.addEvent(me.node, 'blur', closeCalendar);
			//EventHelpers.addEvent(me.node, 'keypress', keydownEvent)
			me.node.type = "text";
			
		}
		
		function openCalendar(e) {
			var cal = window.calendar;
			cal.element.style.zIndex = 0;
		}
		
		function closeCalendar(e){
				var cal = window.calendar;
				if (cal) {
					cal.hide();
				}
		} 
		
		function keydownEvent(e) {
			
		 	var c = EventHelpers.getKey(e);
			if (c == 13) {
				EventHelpers.preventDefault(e);
			}
			
		}
		
		init();
		
	}
	
	
	
	
	
	
	
	/*
	 * Output Element
	 */
	function OutputElement (node) {
		var me = this;
		me.node = node;
		
		var value;
		var valueFormula;
		var parentForm;
	
		var valueRe = /this\.value/g;
		var varRe = /([a-zA-Z][a-zA-Z0-9]*\.value)/g;
		
		function init () {
			parentForm = DOMHelpers.getAncestorByTagName(node, 'form');
			if (!parentForm.id) {
				parentForm.id = getNextDummyID();
			}
			
			valueFormula = getValueFormula();
			// jslog.debug('onforminput ' + valueFormula)
		}
		
		function getValueFormula () {
			var formula =  DOMHelpers.getAttributeValue(me.node, 'onforminput');
			formula = formula
				.replace(valueRe, 'value')
				.replace(varRe, 'document.forms["' + parentForm.id + '"].$1');
			return formula;
		}
		
		me.resolve = function () {
			eval(valueFormula);
			// jslog.debug('value = ' + value);
			// jslog.debug(XMLHelpers.getOuterXML(me.node));
			me.node.innerHTML = value;
			me.node.value = value;
			
		}
		
		
		init();
	}
	
	function ColorElement (node) {
		var me = this;
		
		me.node = node;
		
		function init () {
			CSSHelpers.addClass(me.node, 'color');
			me.node.type = "text";
		}
		
		
		init();
	}
	
		
	
} 

// jslog.debug('adding page load event');
EventHelpers.addPageLoadEvent('html5Forms.init');

