// contents of ../_/js/input/input.js
var focusElement;
function onLoad()
{
	if(focusElement)
		$(focusElement).focus();
}


function Input(e, prop)
{
	e = (typeof(e) == 'string') ? $(e) : (e ? e : $(prop.id));
	if(e == null)
	{
		alert('NULL id: '+prop.id);
		return;
	}
	ce(e);

	for(var key in prop)
	{
		try 
		{
			var child = prop[key];
			if(child)
				e[key] = child;
		} 
		catch(error) { }
	}
	
	if(prop.titleStyle == 'INSET' || prop.titleStyle == 'BOTH')
	{
		e.onfocus = function()
		{
			e.className = e.className.replace(/\s*titleInset/, ''); 
			if(e.title == e.value)
				e.value = '';
				//e.select();
		};
		
		e.onblur = function()
		{
			if(e.value == '') 
				e.value = e.title; 
			if(e.title == e.value) 
				e.className += ' titleInset';
		};
	}
	e.onchange_ = e.onchange;
	e.onchange = function()
	{
		if(e.form && e.form.onchange)
			e.form.onchange();
		if(e.onchange_)
			e.onchange_();
	};
	
	e.check = function()
	{
		if(e.required && e.value == '')
		{
			e.error = e.message;
			e.parentNode.appendChild(e.getError());
			return e.error;
		}
		else return null;
	};
	
	e.getError = function()
	{
		return e.errorObj || (e.errorObj = ce('div').at(e.error).sp('className', 'error'));
	};
	
	e.getValue = function()
	{
		return e.value;
	};

	if(e.focused)
		focusElement = e.id;
		
	return e;
}

function TipMessage(e, prop)
{
	return null; //Input(e, prop);
}

function Group(e, prop)
{
	e = Input(e, prop);
	
	var fields = {};
	for(var key in e.fields)
	{
		var obj = e.fields[key];
		if(obj != null)
		{
			if(window[obj.jsFunc])
				fields[key] = window[obj.jsFunc](null, obj);
			else ce(document.body).at('undefined javascript function: '+obj.jsFunc+' '+obj['class']+' '+key).ac(ce('br'));
		}
	}
	e.fields = fields;
	
	e.check = function()
	{
		var errors = [];
		for(var key in fields)
		{
			var error = fields[key].check();
			if(error)
				errors.push(error);
		}
		return errors.length ? errors : null;
	};
	
	e.getValue = function()
	{
		var obj = {};
		for(var key in e.fields)
			if(e.fields[key].getValue)
				obj[key] = e.fields[key].getValue();
		return obj;
	};
	return e;
}

function CheckMultiple(e, prop)
{
	e = Select(e, prop);
	e.inputs = e.getElementsByTagName('input');
	
	for(var n = 0; n < e.inputs.length; n++)
		e.inputs[n].onclick = function()
		{
			if(this.form && this.form.onchange)
				this.form.onchange();
		};
	e.getValue = function()
	{
//		printR(e.inputs);
		var arr = [];
		for(var n = 0; n < e.inputs.length; n++)
			if(e.inputs[n].checked)
				arr.push(e.inputs[n].value);
//		printR(arr);
		return arr;
	}	
	return e;
}

function Radio(e, prop)
{
	e = Select(e, prop);
	e.inputs = e.getElementsByTagName('input');

	for(var n = 0; n < e.inputs.length; n++)
	{
		e.inputs[n].onclick = function() { if(e.onchange instanceof Function) e.onchange(); };
		e.inputs[n].onchange = null;
	}

	e.getValue = function()
	{
		for(var n = 0; n < e.inputs.length; n++)
		{
			if(e.inputs[n].checked)
				return e.inputs[n].value;
		}
		return null;
	};
	
	return e;
}

function Alternate(e, prop)
{
	e = Group(e, prop);
	for(var key in e.fields)
	{
		e.field = e.fields[key];
		break;
	}
	var currentForm = e.field.getValue();
	
	e.field.onchange = function()
	{
			if(currentForm)
				e.fields[currentForm].style.display = 'none';
			currentForm = e.field.getValue();
			e.fields[currentForm].style.display = '';
	};
	
	e.getValue = function()
	{
		var key = e.field.getValue();
		return key ? e.fields[key].getValue() : null;
	};
	
	return e;
}
function AlternateForm(e, prop)
{
	e = Form(e, prop);
	e.getValue = function()
	{
		return e.field.getValue();		
	};
	return e;
}

function CountForm(e, prop)
{
	e = Form(e, prop);
	var countField = ce($('count_'+prop.id));
	var data;
	
	e.onchange = function() 
	{
		var temp = e.getValue();
		if(data == null || compare(temp, data) == false)
			e.load(e.service, data = temp, display);
		return false;
	};
	
	function compare(x, y)
	{
		for(var key in x)
		{
			if((x[key] instanceof Object) && (y[key] instanceof Object))
			{
				if(compare(x[key], y[key]) == false)
					return false;
			}
			else if(x[key] != y[key])
				return false;
		}
		for(var key in y)
			if(y[key] != x[key])
				return false;
		return true;
	}
	
	function display(count)
	{
		countField.cl().at(e.countMessage.replace(/COUNT/, count));
	}

//	alert(countField);
//	e.onchange = function() { e.submit(); }
	return e;
}

function Form(e, prop)
{
	e = Group(e, prop);
	var div = ce('div'); e.ac(div);
	ce(e.saveForm);
//	e.saveForm = Submit(null, e.saveForm);
	
	e.load = load;
	e.onsubmit = onSubmit;
	return e;

	function onSubmit()
	{
//		alert(e.check() == null);
		return e.check() == null;
	}
	function display(text)
	{
		printR(text, div);
	}
	
	function load(url, data, handler)
	{
		if(data instanceof Object)
			data = toURL(data);

		var request = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
		request.onreadystatechange = onStateChange;
		if(e.method == 'get')
		{
			url += (url.match(/\?/) ? '' : '?1=1')+data;
			request.open('GET', url, true);
			request.send('');
		}
		else
		{
			request.open('POST', url, true);
			request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			request.send(data);
		}
		
		function onStateChange()
		{
			if(request.readyState == 4) // 4 means done loading
			{
				if(request.status == 200)
					handler(request.responseText);
				else alert('Load Failed: status: '+request.status+": "+request.statusText);
			}
		}
		
		function toURL(data, pre)
		{
			if(typeof(data) == 'object')
			{
				var url = '';
				if(data instanceof Array)
				{
					for(var n = 0; n < data.length; n++)
						url += toURL(data[n], (pre || '&data')+'['+n+']');
				}
				else
				{
					for(var key in data)
						url += toURL(data[key], pre ? pre+'['+key+']' : '&'+key);
				}
				return url;
			}
			else return pre+'='+encodeURI(data).replace(/&/g, '$@$'); // decoded in Data::Value()
		}
	}
}

function MultipleForm(e, prop)
{
	e = Form(e, prop);
	e.field = e.fields[prop.field.baseName]; //window[prop.field.jsFunc](prop.field, prop.field);
	e.check = function()
	{
		return e.field.check();
	};

	return e;
}

function MultipleBlockForm(e, prop)
{
	e = MultipleForm(e, prop);
	return e;
}

function MultipleSingleForm(e, prop)
{
	e = Form(e, prop);
	return e;
}

function MultipleInline(e, prop)
{
	e = Multiple(e, prop);
	return e;
}

function MultipleBlock(e, prop)
{
	e = Multiple(e, prop);
	
	for(var n = 0; n < e.rows.length; n++)
	{
		var row = e.rows[n];
		row.removeRow.onclick = function()
		{
			var current = this.parentNode;
			while(current.nodeName.toUpperCase() != 'TBODY')
				current = current.parentNode;
			current.parentNode.removeChild(current);
			return false;
		}
	}

	return e;
}


function Multiple(e, prop)
{
	e = Input(e, prop); // should extend Group, but initializing fields array is causing trouble
//	alert(e.addRow+' '+prop.addRow);
//	e.addRow = Submit(null, prop.addRow);
//	alert(e.addRow);
//for(var key in e.fields)
//	if(e.fields[key] == e.addRow)
//		alert(key+' '+e.fields[key]+' '+e.addRow);

	for(var n = 0; n < e.rows.length; n++)
	{
		var row = e.rows[n];
		for(var key in row)
		{
			var obj = row[key];
//			alert(obj);
			if(obj != null)
			{
				if(window[obj.jsFunc])
					row[key] = eval(obj.jsFunc)(null, obj);
				else ce(document.body).at('undefined javascript function: '+obj.jsFunc+' '+obj['class']+' '+key).ac(ce('br'));
			}

		}

		if(row.removeRow)
			row.removeRow.onclick = function()
			{
				var current = this.parentNode;
				while(current.nodeName.toUpperCase() != 'TR')
					current = current.parentNode;
				ce(current).rs();
				return false;
			};
	}

	e.check = function()
	{
		var errors = [];
		for(var n = 0; n < e.rows.length; n++)
		{
			var row = e.rows[n];
			var rowErrors = [];
			for(var key in row)
			{
				if(row[key]) // hidden fields are null
				{
					var error = row[key].check();
					if(error)
						rowErrors.push(error);
				}
			}
			if(rowErrors.length)
				errors.push(rowErrors);
		}
		return errors.length ? errors : null;
	};
	
	
	
/*
	e.addRow.onclick = function()
	{
		var table = e.getElementsByTagName('table')[1];
		var tr = ce('tr'); // var temp = tr.innerHTML = e.rowTemplate.replace(/<tr[^>]*>|<\/tr>/g, '');
		var matches = e.rowTemplate.match(/<td[^>]*>(.*?)<\/td>/g);
		for(var n = 0; n < matches.length; n++)
		{
			var td = ce('td'); 
			td.innerHTML = matches[n].replace(/<td[^>]*>|<\/td>/g, ''); 
			ac(td, tr);
		}
		ac(tr, table.tBodies[0]);
		alert(tr+' '+table.tBodies[0]+'\n\n'+e.rowTemplate+'\n\n'+"\n\n"+tr.innerHTML);
		return false;
		
		var row = {};
		for(var key in e.fields)
		{
			var obj = e.fields[key];
			if(obj.jsFunc && typeof(window[obj.jsFunc]) == 'function')
			{
			alert(obj.id+'\n'+tr.innerHTML);
				var field = row[key] = eval(obj.jsFunc)(null, obj);
				
				field.id += '_'+(e.idCounter++);
				field.name = (e.name ? e.name+'[rows]' : 'rows')+'['+e.rows.length+']['+field.name+']';
				alert(field.id+' '+field.name+' '+field);
			}
			else alert(obj.jsFunc);
		}
		rows.push(row);
		return false;
	};
//	*/
	return e;
}

function PrimaryKey(e, prop)
{
	e = Hidden(e, prop);
	return e;
}
function Hidden(e, prop)
{
	e = Input(e, prop);
	return e;
}
function HiddenURL(e, prop)
{
	e = Hidden(e, prop);
	return e;
}

function CompactRange(e, prop)
{
	e = Text(e, prop);
	return e;
}

function CompactRangeTime(e, prop)
{
	e = CompactRange(e, prop);
	return e;
}

function CompactRangeNumeric(e, prop)
{
	e = CompactRange(e, prop);
	return e;
}

function Range(e, prop)
{
	e = Input(e, prop);
	if(window[e.fieldType])
	{
		e.minField = window[e.fieldType](null, prop.minField);
		e.maxField = window[e.fieldType](null, prop.maxField);
	}
	
	e.getValue = function()
	{
		return {min:e.minField.value, max:e.maxField.value};
	};
	return e;
}

function NumericRange(e, prop)
{
	e = Range(e, prop);
	return e;
}

function NumericMoneyRange(e, prop)
{
	e = NumericRange(e, prop);
	return e;
}

function SelectInteger(e, prop)
{
	e = Select(e, prop);
	return e;
}

function Select(e, prop)
{
	e = Input(e, prop);
	
/*	var check = e.check;
	e.check = function()
	{
		alert(prop.required+' '+prop.message+' '+prop.defaultValue+' '+e.selectedIndex+' '+check());
	};
*/
	return e;
}

function Submit(e, prop)
{
	e = Input(e, prop);
	return e;
}

function Upload(e, prop)
{
	e = Input(e, prop);
	e.change = Submit(null, prop.change);
	e.hiddenF = Hidden(null, prop.hidden);
	e.iframe = window[e.name] = ce('iframe').sp('className', e.className).sp('src', e.frameSrc);
	e.change.onclick = function() { showIframe(); return false; };

	var links = e.parentNode.getElementsByTagName('a');
	var link = links.length ? ce(links[0]) : null;

	e.iframe.preview = showPreview;
	if(e.style.display == '')
		showIframe();

	e.check = function()
	{
		if(prop.required && e.iframe.parentNode == e.parentNode)
			return e.error = 'Please wait for the file to finish uploading';
		return null;
	};
	
	return e;

	function showPreview(href)
	{
		e.change.st('display', '');
		e.hiddenF.value = href; 
		e.iframe.rs();
		ce(e.parentNode).ib(link = ce('a').sp('href', href).at(href), e.change);
	}
	
	function showIframe()
	{
		e.st('display', 'none');
		e.change.st('display', 'none');
		e.hiddenF.value = '';
		ce(e.parentNode).ac(e.iframe);
		if(link)
			link = link.rs();
	}
}


function Email(e, prop)
{
	e = Text(e, prop);

	var check = e.check;
	e.check = function()
	{
		if(e.required)
		{
			if(e.value.match(/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/) == null)
			{
				e.error = 'This is not a valid email address';
				e.parentNode.appendChild(e.getError());
				return e.error;
			}
			return check();
		}
	};

	return e;
}

function Composite(e, prop)
{
	e = Input(e, prop);
	return e;
}

function Phone(e, prop)
{
	e = Composite(e, prop);
	if(e.required == false)
		prop.num1.required = prop.num2.required = prop.num3.required = false;
		
	var input1 = Text(null, prop.num1);
	var input2 = Text(null, prop.num2);
	var input3 = Text(null, prop.num3);

//	element.focus    = function() { input1.focus(); };
//	element.getValue = function() { return input1.value+(prop.sep || '-')+input2.value+(prop.sep || '-')+input3.value; };
//	element.setValue = setValue;
//	element.check    = function() { return (prop.e && (input1.value.length != 3 || input2.value.length != 3 || input3.value.length != 4)) ? prop.e : false; };
	
	function setValue(values)
	{
		if(values instanceof String)
		{
			var match = values.match(/([\d]{3})[^\d]*([\d]{3})[^\d]*([\d]{4})/);
			values = (match) ? [match[1], match[2], match[3]] : [];
		}
		else if((values instanceof Array) == false)
			values = [];
		input1.value = (values.length > 0) ? values[0] : '';
		input2.value = (values.length > 1) ? values[1] : '';
		input3.value = (values.length > 2) ? values[2] : '';
	}

	var keyCode, tab = false, shift = false, stop = false;
	
	input1.onkeydown = input2.onkeydown = input3.onkeydown = function(ev)
	{
		stop = false;
		keyCode = (ev) ? ev.which : event.keyCode;
		if(keyCode == 9)
		{
			tab = true;
			shift = (ev) ? ev.shiftKey : event.shiftKey;
			return ((this == input3 && shift == false && (input3.value.length > 0 || input1.value.length == 0)) || (this == input1 && shift));
		}
		else tab = false;

		if(keyCode == 8 && this.value.length == 0)
		{
			if(this == input2)
				input1.focus();
			else if(this == input3)
				input2.focus();
		}
	};
	
	input1.onkeyup = function() 
	{
		if(stop)
			return false;
		if(tab)
		{
			stop = true;
			if(shift == false)
			{
				input2.focus();
				input2.select();
			}
		}
		else if(input1.value.length == 3)
		{
			input2.focus();
			input2.select();
		}
	};
	input2.onkeyup = function() 
	{
		if(stop)
			return false;
		if(tab)
		{
			stop = true;
			if(shift)
			{
				input1.focus();
				input1.select();
			}
			else if(input2.value.length > 0 || input1.value.length == 0)
			{
				input3.focus();
				input3.select();
			}
			return false;
		}
		else if(input2.value.length == 3)
		{
			input3.focus();
			input3.select();
		}
	};
	input3.onkeyup = function() 
	{
		if(stop)
			return false;
		if(tab)
		{
			stop = true;
			if(shift)
			{
				input2.focus();
				input2.select();
			}
		}
	};
	
	return e;
}

function PlainText(e, prop)
{
	e = Input(e, prop);
	e.check = function() { return null; }
}

function TextArea(e, prop)
{
	if(prop.value)
		prop.value = prop.value.replace(/<br c="nl" \/>/g, "\n");
	e = Text(e, prop);
	
	return e;
}

function Password(e, prop)
{
	e = Text(e, prop);
	return e;
}

function Href(e, prop)
{
	e = Text(e, prop);
	return e;
}

function Text(e, prop)
{
	e = Input(e, prop);
	var className = e.className;

	var temp = (e.parentNode.getElementsByClassName) ? e.parentNode.getElementsByClassName('error') : getElementsByClassName(e.parentNode, 'div', 'error');
	if(temp.length)
		e.errorObj = ce(temp[0]);
	
	var onfocus = e.onfocus;
	e.onfocus = function()
	{ 
		if(onfocus) onfocus();
		e.className = e.className+' focused';
		if(e.errorObj)
			e.errorObj = e.errorObj.rs();
	};
	var onblur = e.onblur;
	e.onblur = function()
	{
		if(onblur) onblur();
		e.className = e.className.replace(/\s*focused/, '');
		if(e.check())
			e.parentNode.appendChild(e.getError());
	}
/*		
	try
	{
		e.addEventListener('focus', function() 
		{ 
			e.className = e.className+' focused';
			if(e.errorObj)
				e.errorObj = e.errorObj.rs();
		}, true);
		e.addEventListener('blur', function() 
		{
			e.className = e.className.replace(/\s*focused/, '');
			if(e.check())
				e.parentNode.appendChild(e.getError());
		}, true);
	}
	catch(error) { }
	*/
	var check = e.check;
	e.check = function()
	{
		if(e.required)
		{		
			if(e.length && e.length != e.value.length)
				return e.error = 'must be '+e.length+' characters';
			if(e.minlength && e.minlength > e.value.length)
				return e.error = 'must be at least '+e.minlength+' characters';
			return check();
		}
	};
	
	return e;
}

function CompactRangeDate(e, prop)
{
	return CompactRange(e, prop);
}

function DateCompactRange(e, prop)
{
	return Range(e, prop);
}

function DateCompact(e, prop)
{
	e = Text(e, prop);
	return e;
}

function Numeric(e, prop)
{
	e = Text(e, prop);
	var check = e.check;
	e.check = function()
	{
		if(e.required)
		{
			if(e.value.match(/^\s*(\.\d+|\d+\.?\d*?)\s*$/) == null)
				return e.error = e.message;
			return check();
		}
	};
	
	return e;
}

function NumericMoney(e, prop)
{
	e = Numeric(e, prop);
	var value = e.value;
	
	var onkeyup = e.onkeyup;
	e.onkeyup = function(ev)
	{
		if(onkeyup) 
			onkeyup();
		var keyCode = ev ? ev.keyCode : event.keyCode;
//		printR(keyCode+' ', e.parentNode);
//printR('['+String.fromCharCode(ev.keyCode)+' '+ev.keyCode+'] ', e.parentNode);
		if(document.selection)
		{
			var bm = document.selection.createRange().getBookmark();
			var sel = e.createTextRange();
			sel.moveToBookmark(bm);
			var sleft = e.createTextRange();
			sleft.collapse(true);
			sleft.setEndPoint("EndToStart", sel);
			e.selectionStart = sleft.text.length
			e.selectionEnd = sleft.text.length + sel.text.length;
			e.selectedText = sel.text;
		}
		if(e.value && e.selectionEnd >= e.value.length && keyCode >= 48 || keyCode == 8)// && e.value.match(/\d$/))
			e.value = format(parseFloat(e.value.replace(/[^\d\.]/g, '')), prop.decimalPlaces);
	};
	
	var onblur = e.onblur;
	e.onblur = function() 
	{ 
		if(onblur) onblur(); 
		e.value = format(parseFloat(e.value.replace(/[^\d\.]/g, '')), prop.decimalPlaces);
		if(value != e.value && e.form.onchange)
			e.form.onchange();
	};
	
	return e;
	
	function format(num, places)
	{
		if(isNaN(num))
			return '';

		var out = '';
		var match = (num.toFixed(places)+'').match(/(\d+)\.?(\d*)/);
		num = match[1];
		dec = match[2];
		var len = num.length;
		for(var n = 1; n <= len; n++)
			out = ((n % 3) == 0 && len > 4 && n < len ? ',' : '')+num.charAt(len - n) + out;
		return (out != 0 ? '$' : '')+out+(parseInt(dec) ? '.'+dec : '');
	}
}

function Integer(e, prop)
{
	e = Text(e, prop);
	var check = e.check;
	e.check = function()
	{
		if(e.required)
		{
			if(e.value.match(/^\s*\d+\s*$/) == null)
				return e.error = e.message;
			return check();
		}
	};
	
	return e;
}

function TextAutoMultipleId(e, prop)
{
	e = TextAutoMultiple(e, prop);
	return e;
}

function TextAutoMultiple(e, prop)
{
	e = TextAuto(e, prop);
	return e;
}
function TextAutoId(e, prop)
{
	e = TextAuto(e, prop);
	return e;
}

TextAuto.cache = {};
function TextAuto(e, prop)
{
	e = Text(e, prop);
	var name = e.name;
	var ul = ce('ul').sp('className', 'textAuto'); e.parentNode.appendChild(ul);

	var limit = e.displayLimit || 15;
	var offset = 0;
	var index = 0, dataSet;
	var last  = e.value;
	var lastSelection = e.value;
	var timerID, lock = false;
	var onLoadHandler = null;
	var valueAtFocus;

	var cacheKey = name;
	if(TextAuto.cache[cacheKey] == undefined)
		TextAuto.cache[cacheKey] = {};
	var cache = TextAuto.cache[cacheKey];

	var onblur = e.onblur;
	e.onblur = function()
	{
		if(e.onblur)
			onblur();
		e.name = name;
		window.setTimeout(function() { ul.st('display', 'none'); }, 500);
		if(e.value != valueAtFocus && e.form.onchange)
			e.form.onchange();
	};
//	var onclick = e.onclick;
//	e.onclick = function() { if(onclick) onclick(); lookup(); };
	var onfocus = e.onfocus;
	e.onfocus = function() { if(onfocus) onfocus(); valueAtFocus = e.value; ul.cl(); ul.st('display', ''); lookup(); e.name = Math.random(); };
	
	try
	{
//		e.addEventListener("click", function preventDef(event) { event.preventDefault(); }, false);
/*		
		e.addEventListener('blur', function()
		{
			e.name = name;
//			if(document.all == null) // for FireFox
//				e.focus();
			window.setTimeout(function() { ul.st('display', 'none'); }, 500);
			
			if(e.value != valueAtFocus && e.form.onchange)
				e.form.onchange();
		}, true);
*/
//		e.addEventListener('click', function() { lookup(); }, true);
//		e.addEventListener('focus', function() { valueAtFocus = e.value; ul.cl(); ul.st('display', ''); e.name = Math.random(); }, true);
	}
	catch(exception) { }
	
	e.onkeydown = function(ev)
	{
		var keyCode = ev ? ev.which : event.keyCode;
		if(keyCode == 38) // up
		{
			killEvent(ev);
			moveToIndex(index - 1);
			
			return false;
		}
		else if(keyCode == 40) // down
		{
			killEvent(ev);
			moveToIndex(index + 1);
			return false;
		}
		else if(keyCode == 13 && index > 0) // enter when an item is selected
		{
			killEvent(ev);
			ul.childNodes[index - 1].onclick();
			return false;
		}
		else if(keyCode == 13)
		{
			e.name = name;
			return true;
		}
		else if(keyCode == 9) // tab
		{
//			alert(prop.tabComplete+' '+last+' '+ul.childNodes.length);
//			if(prop.tabComplete && index)
			if(index)
				ul.childNodes[index - 1].onclick();
			ul.st('display', 'none');
			return true;
		}
		else return true;
	};
	
	e.onkeyup = function(ev)
	{
		var keyCode = ev ? ev.which : event.keyCode;
		if(keyCode == 38 || keyCode == 40 || keyCode == 13 && index > 0)
		{
			killEvent(ev);
			return false;
		}
			
		var key = e.value.toLowerCase();
		if(prop.delimiter)
		{
			key = key.replace(new RegExp('^.*'+prop.delimiter+'\\s*'), '');
//			var elem = ce(e.parentNode); elem.at('_'+key+'_ ');
		}
		var data = cache[key];

		if(timerID)
			window.clearTimeout(timerID);
		
		if(data)
		{
			last = key;
			show(data);
		}
		else if(lock == false)
		{
			var temp = key;
			while(temp.length > 1 && prop.jsFilter != 'JS_MATCH') // looks back through the cache to see if there is anything it can display and filter
			{
				if((data = cache[temp = temp.substr(0, temp.length - 1)]) && data.length < limit)
				{
					last = key;
					show(data);
					filter(key);
					return;
				}
			}
			
			if(key.length < last.length || filter(key)) // if there are less than limit items displayed
				timerID = window.setTimeout(lookup, 100);

			last = key;
		}
		else onLoadHandler = function() { e.onkeyup(ev); };
	};
	
	return e;
	

	function lookup()
	{
		var key = e.value.toLowerCase();
		if(prop.delimiter)
		{
			key = key.replace(new RegExp('^.*'+prop.delimiter+'\\s*'), '');
//			var elem = ce(e.parentNode); elem.at('_'+key+'_ ');
		}
		if(e.isStatic)
		{
			var len = key.length;
			var options = [];
			for(var n = 0; n < e.options.length; n++)
			{
				if(prop.jsFilter == 'JS_MATCH')
				{
				var regex;
					if(e.options[n].match(regex = new RegExp('(^| )'+key, 'i')))
						options.push(e.options[n]);
//					alert(regex);
				}
				else if(e.options[n].substring(0, len).toLowerCase() == key)
					options.push(e.options[n]);
			}
			show(cache[key] = options);
		}
		else // must load from server, e.options is the service path
		{
			lock = true;
			var request = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
			request.onreadystatechange = onStateChange;
			request.open('GET', e.options+'?key='+key, true);
			request.send('');
		}
		
		function onStateChange()
		{
			if(request.readyState == 4) // 4 means done loading
			{
				if(request.status == 200)
				{
					var data = eval(request.responseText);
					show(cache[key] = data);
				}
				else alert('Load Failed: status: '+request.status+": "+request.statusText);
			}
			lock = false;
		}
	}

	function selectIndex(index2)
	{
		if(prop.delimiter && e.value.indexOf(prop.delimiter) > -1)
		{
			last = dataSet[index2];
			e.value = e.value.replace(new RegExp('('+prop.delimiter+'\\s*)[^'+prop.delimiter+']*$'), '$1'+last+prop.delimiter);
		}
		else
		{
			e.value = last = dataSet[index2];
			e.value += prop.delimiter || '';
		}
		
		lastSelection = last;
		e.focus();
		ul.st('display', 'none');
		index = 0;
		//last = null;
		e.form.onchange();
	}
	
	function moveToIndex(newIndex) // index starts at 1, 0 for no selection
	{
		var lis = ul.childNodes;
		if(lis.length)
		{
			if(index > 0 && index <= lis.length)
				lis[index - 1].className = '';
			
			if(newIndex < 0)
				index = lis.length;
			else if(newIndex > lis.length)
				index = 1;
			else index = newIndex;
			
			if(index)
				lis[index - 1].className = 'current';
		}
	}
	
	function filter(key)
	{
		var key = key.toLowerCase();
		var length = key.length;
		var lis = ul.childNodes;

		for(var n = lis.length - 1; n >= 0; n--)
		{
			if(prop.jsFilter == 'JS_MATCH')
			{
				if(lis[n].innerHTML.match(new RegExp('(^| )'+key, 'i')) == null)
					lis[n].rs();
			}
			else if(lis[n].innerHTML.substr(0, length).toLowerCase() != key)
				lis[n].rs();
		}
		return lis.length < limit;
	}
	
	function show(data)
	{
		dataSet = data;
		index = 0;
		ul.cl();
		ul.st('display', '');
		for(var n = 0; n < data.length && n < limit; n++)
			ul.ac(getLi(n));
		function getLi(index) { return ce('li').at(data[n]).sp('onclick', function() { selectIndex(index); }); }

		if(prop.tabComplete && dataSet.length && e.value && (prop.delimiter == null && e.value != lastSelection || prop.delimiter && e.value.match(new RegExp(prop.delimiter+'$')) == null))
			moveToIndex(1);
	}
}




function killEvent(ev)
{
	if(ev)
	{
		ev.stopPropagation();
		ev.preventDefault();
	}
	else
	{
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	}
}

function clone(obj)
{
	if(typeof(obj) == 'object')
	{
		if(obj instanceof Array)
		{
			var array = [];
			for(var n = 0; n < obj.length; n++)
				array.push(clone(obj[n]));
			return array;
		}
		else
		{
			var newObj = new Object();
			for(var key in obj)
				newObj[key] = clone(obj[key]);
			return newObj;
		}
	}
	else return obj;
}
// contents of ../_/js/input/element.js
function $(id) { return document.getElementById(id); }
function ct(t) { return document.createTextNode(t); }

function ce(e) 
{
	if(typeof(e) == 'string')
		e = document.createElement(e);
	
	e.ac = function(c) { e.appendChild(c); return e; };
	e.at = function(t) { e.ac(document.createTextNode(t)); return e; };
	e.ia = function(n, o) { e.insertBefore(n, o.nextSibline); return e; };
	e.ib = function(n, o) { e.insertBefore(n, o); return e; };
	e.rc = function(c) { e.removeChild(c); return e; };
	e.rs = function() { e.parentNode.removeChild(e); return e; };
	e.rw = function(c) { e.parentNode.replaceChild(c, e); return e; };
	e.cl = function() { while(e.lastChild) e.removeChild(e.lastChild); return e; };
	
	e.sp = function(k, v, f) { /* if(!f && e[k] === undefined) document.body.appendChild(document.createTextNode('Error, setting invalid property: '+k)); */ e[k] = v; return e; };
	e.st = function(k, v) { e.style[k.replace(/\-(\w)/, function(_, s) { return s.toUpperCase(); })] = v; return e; };

	e.printR = function(v) { printR(v, e); };
	e.dump = function(d) { printR(e, d); };
	return e;
}

function printR(obj, dest)
{
	if((obj instanceof Object) && !(obj instanceof Function) || (obj instanceof Array))
	{
		var e = ce('dl');
		for(var key in obj)
		{
			var c = obj[key];
			if((c instanceof Object) || (c instanceof Array))
			{
				var dd = ce('dd');
				e.ac(ce('dt').ac(ce('a')
					.at(key)
					.sp('href', 'javascript:;')
					.sp('dd', dd)
					.sp('c', c)
					.sp('onclick', function() { if(this.dd.firstChild) this.dd.cl(); else printR(this.c, this.dd); }))
				).ac(dd);
			}
			else e.ac(ce('dt').at(key)).ac(ce('dd').at(c));
		}
	}
	else var e = ct(obj);
	
	(dest ? dest : document.body).appendChild(e);
};

function getElementsByClassName(oElm, strTagName, strClassName)
{
	var arrElements = (strTagName == "*" && oElm.all) ? oElm.all : oElm.getElementsByTagName(strTagName);
	var arrReturnElements = [];
	strClassName = strClassName.replace(/\-/g, "\\-");
	var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	for(var i = 0; i < arrElements.length; i++)
	{
		oElement = arrElements[i];
		if(oRegExp.test(oElement.className))
			arrReturnElements.push(oElement);
	}
	return arrReturnElements;
}
// contents of js/index.js
function onLoad()
{
}

function cal(input, value)
{
	var cal_iframe = $('cal_iframe');
	var src = cal_iframe.src;
	cal_iframe.src = input.checked ?  src+value : src.replace(value, '');
}

function fixHeight()
{
	var site_div    = $('site_div');
	var header_div  = $('header_div');
	var content_div = $('content_div');
	var footer_div  = $('footer_div');
	
	var padding = 250; // same as bottom margin

	setHeight();
	window.onresize = setHeight;
	function setHeight()
	{
		var pageH = (document.documentElement) ? document.documentElement.clientHeight : document.body.clientHeight;
	//	var offset = footer_div.offsetHeight + container_div.offsetTop + 10;
		var offset = padding + content_div.offsetTop + footer_div.offsetHeight;
	//	var containerH = container_div.clientHeight;

	//	if(pageH > containerH + offset)
		var height = pageH - offset;
		content_div.style.minHeight = height+'px';

		if(navigator.userAgent.match(/MSIE 6/i))
			$('backdrop_div').style.height = (site_div.offsetHeight - 35)+'px';
		
		if(document.getElementById('cal_iframe') && height > 400)
			$('cal_iframe').style.height = (height - $('cal_iframe').offsetTop - 10)+'px';
			
	}
}

function ie6()
{
	//alert('here');
}

function activateTable(id, cols)
{
	var table = $(id);
	var thead = table.tHead;
	var titles = thead.firstChild.innerHTML.match(/<th[^>]*>([^<]*)<\/th>/gi);
	for(var n = 0; n < titles.length; n++)
		titles[n] = titles[n].replace(/<[^>]*>/g, '');
	var tbody = table.tBodies[0];
	var cells = thead.rows[0].cells;
	var filterTr = ce('tr').sp('className', 'filter');

	if(tbody == undefined)
		return;
		
	var rows = tbody.rows;
	var lastIndex = 0, prevIndex = -1;
	var allRows = [];
	for(var n = 0; n < rows.length; n++)
		allRows.push(rows[n]);
	var filterInputs = [];

	for(var n = 0; n < cells.length; n++)
	{
		var th = ce(cells[n]);
		var obj = cols[n];
		if(obj)
		{
			if(obj.current && obj.dir != 'DESC')
				prevIndex = n;
			var asc = (obj.dir == 'DESC') ? !obj.current : obj.current; // XOR
			var img = ce('img').sp('className', 'sort').sp('alt', !asc ? '^' : 'v').sp('src', 'img/sort_'+(!asc ? 'asc' : 'desc')+'.png');
			var a = ce('a').ac(th.firstChild || ct('')).ac(img).sp('class', 'sort').sp('href', 'javascript:;').sp('onclick', sort).sp('index', n).sp('img', img);
			th.ac(a);

			for(var x = 0; x < rows.length; x++)
				if(rows[x].className != 'expand')
					cellValue(rows[x].cells[n], obj);
		}
		
		if(obj && obj.filter)
		{
			var input = ce('input')
				.sp('type', 'text')
				.sp('size', 1)
				.sp('className', 'filter')
				.st('width', '100%')
//				.sp('onkeyup', function() { filter(true); })
				.sp('onkeyup', filter)
//				.sp('onblur', function() { filter(false); })
				.sp('index', n);
			filterInputs[n] = input;
			filterTr.ac(ce('th').ac(input));
		}
		else filterTr.ac(ce('th').at(''));
	}
	
	for(var n = 0; n < rows.length; n++)
	{
		var row = rows[n];
		var html = '<table cellspacing="0">';
//		var data = row.innerHTML.match(/<td([\s\S]*?)<\/td>/gi);
		var data = row.innerHTML.match(/<td[^>]*>([\s\S]*?)<\/td>/gi);

		for(var x = 0; x < data.length; x++)
			if(x < titles.length && titles[x])
//				html += '<tr><th>'+titles[x]+'</th><td>'+data[x].replace(/<[^>]*>/g, '')+'</td></tr>';
				html += '<tr><th>'+titles[x]+'</th><td>'+data[x].replace(/^<[^>]*>|<[^>]*>$/, '')+'</td></tr>';
		html += '</table>';

		if(n + 1 < rows.length && rows[n + 1].className == 'expand')
			html += rows[++n].firstChild.innerHTML;

		addTip(row, html);
	}
	
	thead.appendChild(filterTr);
	
	function cellValue(cell, obj)
	{
		var cell = rows[x].cells[n];
		cell.filterValue = cell.innerHTML.replace(/<[^>]*>/g, '');
		
		if(obj.type == 'DATE') // YYYY-MM-DD must be hidden as the last element in the cell
			cell.value = cell.lastChild.innerHTML;
		else cell.value = cell.innerHTML.replace(/<[^>]*>/g, '');
		
		if(obj.type == 'NUMBER')
			cell.value = parseFloat(cell.value) || 0;
		else if(obj.caseI !== false)
			cell.value = cell.value.toLowerCase();
	}
	
	function filter()
	{
		var filter;
		var filters = [];
		for(var key in filterInputs)
			if(filter = createFilter(filterInputs[key].value, cols[filterInputs[key].index].type, cols[filterInputs[key].index].prog))
				filters[key] = filter;
//		alert(filters.join('\n'));
		var removeRow;
		for(var n = 0; n < allRows.length; n++)
		{
			var row = allRows[n];
			if(row.className != 'expand') // expanded rows hidden if previous row hidden
			{
				removeRow = false;
				//for(var x = 0; x < row.cells.length; x++)
				for(var key in filters)
					if(filters[key](row.cells[key].filterValue)) // removeRow
						removeRow = true;
			}
			row.style.display = removeRow ? 'none' : '';
		}
	}

	function createFilter(val, type, progressive)
	{
		if(val === '')
			return null;//function(str) { return false; };
		else
		{
			var tokens = val.split(/([><=]+)/g);
			if(tokens.length > 1)
			{
				for(var n = 0; n < tokens.length; n++)
				{
					tokens[n] = tokens[n].replace(/^\s*|\s*$/g, '');
					if(tokens[n] == '=')
						tokens[n] = '==';
				}
				if(tokens[0] == '')
					tokens = tokens.splice(1);
				var code = '';
				for(var n = 0; n < tokens.length; n += 2)
					code += (n ? ' && ' : '')+'val '+tokens[n]+' "'+tokens[n + 1]+'"';
				return new Function('val', 'return !('+code+')');
			}
			else if(type == 'STRING' || type == 'DATE')
				return function(str) { return str.match(new RegExp(val, 'i')) == null; };
			else if(progressive)
				return function(num) { val += ''; return val != (num+'').substring(0, val.length); };
//			else return function(num) { return num != val; };
			else return function(num) { return num != val; };
		}
	}
	

	function sort()
	{
		var link = this;
		var index = link.index;
		var col = cols[index];
//		var mod = mods && mods[index] ? mods[index] : function(str) { return str; }
		var asc = index != prevIndex;
//		var asc = !(col.current ^ col.dir == 'DESC');
		link.img.sp('alt', !asc ? '^' : 'v').sp('src', 'img/sort_'+(!asc ? 'asc' : 'desc')+'.png');
		
		for(var n = 1; n < rows.length; n++)
		{
			var tr1 = rows[n];
			
			if(tr1.className != 'expand') // else value of x used from previous row
			{
				var value = tr1.cells[index].value;
				for(var x = n; (x > 0 && rows[x - 1].className == 'expand') || x > 0 && (asc && value < rows[x - 1].cells[index].value || asc == false && value > rows[x - 1].cells[index].value); x--)
					;
			}
			else x++;
			
			while(x < n && rows[x].className == 'expand') 
				x++;
			if(x < n)
				tbody.insertBefore(tr1, rows[x]);
			
		}
		
//		var counter = 0;
//		for(var n = 0; n < rows.length; n++)
//			if(rows[n].style.display != 'none')
//				rows[n].className = Math.floor(counter++ / 2) % 2 ? 'o' : 'e';
			
		lastIndex = index;
		prevIndex = asc ? index : -1;
	}
}

//addTip.current = null;
function addTip(element, tip, offsetX, offsetY)
{
	var isIE = (document.all && !window.opera);
	if(offsetX === undefined) offsetX = 10;
	if(offsetY === undefined) offsetY = 20;

	var toolTip = ce('div').sp('className', 'toolTip').sp('innerHTML', tip);
	var style = getStyle(toolTip); var temp;
	var width   = style.width   && (temp = parseInt(style.width))   ? temp : 100;
	var height  = style.height  && (temp = parseInt(style.height))  ? temp : 100;
	var padding = style.padding && (temp = parseInt(style.padding)) ? temp : 5;
	var border  = style.borderWidth && (temp = parseInt(style.borderWidth)) ? temp : 3;

	var timer;
	element.onmouseover = function(e) 
	{
		if(timer)
		{
			window.clearTimeout(timer);
			timer = null;
		}
		if(addTip.current == toolTip)
			return;
		if(addTip.current)
		{
			document.body.removeChild(addTip.current); 
			addTip.current = null;
		}
			
		addTip.current = toolTip;
		document.onmousemove = isIE ? trackIE : trackGECKO;
		document.body.appendChild(toolTip);
		height = toolTip.scrollHeight + padding + border;
		width  = toolTip.scrollWidth  + padding + border;
		document.onmousemove(e);
	};
	
	element.onmouseout  = function() 
	{ 
		timer = window.setTimeout(remove, 100);
		function remove()
		{
			timer = null;
//			document.onmousemove = null;
			if(toolTip.parentNode == document.body)
			{
				document.body.removeChild(toolTip); 
				addTip.current = null;
			}
		}
	};
	
	var doc = (document.compatMode && document.compatMode != 'BackCompat') ? document.documentElement : document.body;
	var style = getStyle(doc);
	var temp, htmlOffsetX = (temp = parseInt(style.width)) ? Math.round((getWidth() - temp) / 2) : 0;
	
	var scrollX, scrollY, innerW, innerH, maxX, maxY, x, y;

	function trackIE()
	{
		scrollX = doc.scrollLeft;
		scrollY = doc.scrollTop;
		innerW  = doc.clientWidth;
		innerH  = doc.clientHeight;
		maxX = scrollX + innerW;
		maxY = scrollY + innerH;
		x = window.event.clientX + scrollX + offsetX;
		y = window.event.clientY + scrollY + offsetY;
		
		move();
	}
	function trackGECKO(e)
	{
		scrollX = window.pageXOffset;
		scrollY = window.pageYOffset;
		innerW  = window.innerWidth;
		innerH  = window.innerHeight;
		maxX = scrollX + innerW;
		maxY = scrollY + innerH;
		x = e.pageX + offsetX - htmlOffsetX;
		y = e.pageY + offsetY;
		move();
	}
	
	function move()
	{
		toolTip.style.left = (x + width  + 2*padding < maxX ? x : x - width  - 2*offsetX - 2*padding)+'px';
		toolTip.style.top  = (y + height + 2*padding < maxY ? y : y - height - 2*offsetY - 2*padding)+'px';
	}

	function getHeight()
	{
		return (document.documentElement) ? document.documentElement.clientHeight : document.body.clientHeight;
	}
	function getWidth()
	{
		return (document.documentElement) ? document.documentElement.clientWidth  : document.body.clientWidth;
	}
	function getStyle(element)
	{
		return (element.currentStyle) ? element.currentStyle : getComputedStyle(element, null);
	}
}

function $(id)
{
	return document.getElementById(id);
}

