var IRULE_MIN_LENGTH   = 0;
var IRULE_MAX_LENGTH   = 1;
var IRULE_UNIQUE       = 2;
var IRULE_DOUBLE_CHECK = 3;
var IRULE_FILETYPES    = 4;
var IRULE_NUMBER       = 5;
var IRULE_FORMAT       = 9;
var ICHECK_GOOD        = 0;
var ICHECK_BAD         = 1;
var ICHECK_CHECKING    = 2;
var ICHECK_EMPTY       = 3;
var reMultiField = /(inp_.+)\[(.*)\]/;
var reField = /^inp_.+$/;

function DataSneak() {
	this.aForms = new Array();
}
	DataSneak.prototype._check = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		var sField = oField.name;
		if(aField = sField.match(reMultiField))
			sField = aField[1];
		
		if(!this.aForms[sForm]) 
			this.aForms[sForm] = new DataSneakForm(sForm, sField);
		this.aForms[sForm]._check(sField);
	}
	
	DataSneak.prototype._tagger = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		var sField = oField.name;
		if(!this.aForms[sForm]) 
			this.aForms[sForm] = new DataSneakForm(sForm, null);
		switch(this.aForms[sForm].iFormType) {
			case 0:
				break;
			case 1:
				var sLink = '?Wrowser/Module_Lists/module:' + this.aForms[sForm].iModule + '/display:xontemp/';
				openWrowser(sLink, DataSneakAddTag, {Form:sForm});
				break;
		}
	}
	
	DataSneak.prototype._addTag = function(sForm, iTag, sLabel) {
		if(isset(this.aForms[sForm]))
			this.aForms[sForm]._addTag(iTag, sLabel);
	}
	
	DataSneak.prototype._removeTag = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		var sField = oField.value;
		if(!this.aForms[sForm]) 
			this.aForms[sForm] = new DataSneakForm(sForm, null);
		this.aForms[sForm]._removeTag(sField);
	}
	
	DataSneak.prototype._focus = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		var sField = oField.name;
		if(aField = sField.match(reMultiField))
			sField = aField[1];
			
		this.aForms[sForm].sLastFocused = this.aForms[sForm].sFocused;
		this.aForms[sForm].sFocused = sField;
		if(isset(this.aForms[sForm].aFields[this.aForms[sForm].sLastFocused]))
			this.aForms[sForm].aFields[this.aForms[sForm].sLastFocused]._hideRules();
		if(isset(this.aForms[sForm].aFields[this.aForms[sForm].sFocused]))
			this.aForms[sForm].aFields[this.aForms[sForm].sFocused]._displayRules();
	}
	
	DataSneak.prototype._submit = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		if(!this.aForms[sForm]) {
			alert('Nothing has been changed. Failed to submit.');
			return(false);
		}
		this.aForms[sForm]._submit();
	}
	
	DataSneak.prototype._delete = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		if(!this.aForms[sForm]) 
			this.aForms[sForm] = new DataSneakForm(sForm, null);
		this.aForms[sForm]._delete();
	}
	
	DataSneak.prototype._AutoCompletePress = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		var sField = oField.name;
		this.aForms[sForm]._AutoCompletePress(sField, oEvent);
	}
	
	DataSneak.prototype._AutoCompleteFetch = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		var sField = oField.name;
		this.aForms[sForm]._AutoCompleteFetch(sField, oEvent);
	}
	
	DataSneak.prototype._AutoCompleteHide = function(oEvent) {
		oField = fGEOBJ(oEvent);
		var sForm  = oField.form.name;
		var sField = oField.name;
		this.aForms[sForm]._AutoCompleteHide(sField);
	}
	
function DataSneakForm(sFormName, sField) {
	this.oFormXmlHttp   = zXmlHttp.createRequest();
	this.sForm          = sFormName;
	this.oForm          = document.forms[this.sForm];
	this.bEdited        = false;
	this.aFields        = new Array();
	this.oFormElements  = new Array();
	this.iCheckInterval = null;
	var regExpInp = /[inp|frm]_.+/;
	for(i in this.oForm) {
		if(regExpInp.test(i)) {
			this.oFormElements[i] = this.oForm[i];
		}
	}
	
	this.iFormType      = parseInt(this.oFormElements['frm_type'].value);
	this.iFormAction    = this.oFormElements['frm_action'].value;
	this.iFormObjectId  = this.oFormElements['frm_object_id'].value;
	this.sSuccessAction = null;
	this.bFetchRules    = false;
	this.sFocused       = sField;
	this.sLastFocused   = null;
	
	this.aFieldChecks       = new Array();
	this.sCurrentFieldCheck = null;
	
	switch(this.iFormType) {
		case 0:
			this.sFormModel = this.oFormElements['inp_model'].value;
			break;
		case 1:
			this.iModule     = this.oFormElements['inp_module'].value;
			this.iObjectType = this.oFormElements['inp_obj_type'].value;
			break;
		case 2:
			break;
		case 3:
			this.iModule = this.oFormElements['frm_module'].value;
			this.iFormId = this.oFormElements['frm_form'].value;
			break;
	}
	
	this.aTagsCurrent = new Array();
	this.aTagsCurrentIndex = new Array();
	var aTagElems = fGEOBJLI('input', 'current_tags');
	for(i in aTagElems) {
		this.aTagsCurrent[aTagElems[i].value] = aTagElems[i].id;
		this.aTagsCurrentIndex[aTagElems[i].value] = aTagElems[i].id;
	}
	this.oTagsCurrent = document.getElementById('tags_current');
	this.bTagsCurrent = isset(this.oTagsCurrent);
	this.aTagsAdding  = new Array();
	this.oTagsAdding  = document.getElementById('tags_add');
	this.bTagsAdding  = isset(this.oTagsAdding);
	this.aTagsRemove  = new Array();
	this.oTagsRemove  = document.getElementById('tags_remove');
	this.bTagsRemove  = isset(this.oTagsRemove);
	
	this._createFields();
	this._fetchRules(this.iFormType);
}

	DataSneakForm.prototype._check = function(sField) {
		var reMultiField = /(inp_.+)\[(.*)\]/;
		if(aField = sField.match(reMultiField))
			sField = aField[1];
		
		this.bEdited = true;
		if(!this.aFieldChecks.in_array(sField))
			this.aFieldChecks.push(sField);
		
		var oSelf = this;
		clearInterval(this.iCheckInterval);
		this.iCheckInterval = setInterval(function() 
			{
				oSelf._processCheck();
				clearInterval(oSelf.iCheckInterval);
			}, 300);
		
		if(isset(this.aFields[sField].aImgSrc[0]))
			this.aFields[sField].oImgCheck.src = this.aFields[sField].aImgSrc[0] + 'validating.gif';
	}
	
	DataSneakForm.prototype._processCheck = function() {
		if(this.bFetchRules && !isset(this.sCurrentFieldCheck) && this.aFieldChecks.length > 0) {
			this.sCurrentFieldCheck = this.aFieldChecks.shift();
			
				if(isset(this.aFields[this.sCurrentFieldCheck].aImgSrc[0])) {
					if(DataSneakJudge.call(this.aFields[this.sCurrentFieldCheck])) {
						this.aFields[this.sCurrentFieldCheck].oImgCheck.src = this.aFields[this.sCurrentFieldCheck].aImgSrc[0] + 'valid.gif';
					} else {
						this.aFields[this.sCurrentFieldCheck].oImgCheck.src = this.aFields[this.sCurrentFieldCheck].aImgSrc[0] + 'invalid.gif';
					};
				};
				
				if(this.aFields[this.sCurrentFieldCheck].bDivCount)
					this.aFields[this.sCurrentFieldCheck].oDivCount.innerHTML = 'Characters: ' + this.aFields[this.sCurrentFieldCheck].aInputs[0].value.length;
				
				if(this.sCurrentFieldCheck == this.sFocused)
					this.aFields[this.sCurrentFieldCheck]._displayRules();
				
			this.sCurrentFieldCheck = null;
			this._processCheck();
		}
	}
	
	DataSneakForm.prototype._createFields = function() {
		var reFormField = /inp_.+/;
		var reMultiField = /(inp_.+)\[(.*)\]/;
		for(i in this.oFormElements) {
			if(reFormField.test(this.oFormElements[i].name)) {
					sField = this.oFormElements[i].name;
					sKey   = 0;
				if(aField = this.oFormElements[i].name.match(reMultiField)) {
					sField = aField[1];
					sKey   = aField[2];
				};
				if(!isset(this.aFields[sField]))
					this.aFields[sField] = new DataSneakField(sField);
				this.aFields[sField].addInput(this.oFormElements[i], sKey);
			}
		}
	}
	
	DataSneakForm.prototype._fetchRules = function(iType) {
		switch(this.iFormType) {
			case 0:
				var sLink = '?Form/rules/type:0/model:' + this.sFormModel + '/display:xontemp/';
				oTOwl.sget(sLink, this, this._parseRules);
				break;
			case 1: //Module
				var sLink = '?Form/rules/type:1/module:' + this.iModule + '/objtype:' + this.iObjectType + '/display:xontemp/';
				oTOwl.sget(sLink, this, this._parseRules);
				break;
			case 2: //Module Relationship Object
			
			case 3: //Module Form
			//var sLink = '?Form/rules/type:3/module:' + this.iModule + '/form:' + this.iFormId + '/display:xontemp/';
			//oTOwl.sget(sLink, this, this._parseRules);
			var sLink = '?Form/rules/type:3/module:' + this.iModule + '/form:' + this.iFormId + '/display:serphp/';
			oTOwl.sget(sLink, this, this._parseRules2);
		}
	}
	
	DataSneakForm.prototype._parseRules = function(sRules) {
		aRuleSets = sRules.split(';');
		var sRule = new String();
		for(i in aRuleSets) {
			sRule = new String(aRuleSets[i]);
			aFieldnRule = sRule.split(':');
			if(isset(aFieldnRule[0]) && isset(aFieldnRule[1])) {
				sField = aFieldnRule[0];
				aRules = aFieldnRule[1].match(/[0-9]+=[0-9]+/g);
				for(x in aRules) this.aFields[sField]._defineRule(aRules[x]);
			};
		}
		this.bFetchRules = true;
		if(isset(this.sFocused))
			this.aFields[this.sFocused]._displayRules();
		this._processCheck();
	}
	
	DataSneakForm.prototype._parseRules2 = function(sRules) {
		var a = PHP_Unserialize(sRules);
		for(sField in a) {
			if(reField.test(sField)) {
				if(isset(a[sField]['rules']))
					this.aFields[sField]._defineRules(a[sField]['rules']);
				if(typeof(a[sField]['behavior']) == 'object') {
					this.aFields[sField]._defineBehavior(a[sField]['behavior']);
				}
			}
		}
		this.bFetchRules = true;
		if(isset(this.sFocused))
			this.aFields[this.sFocused]._displayRules();
		this._processCheck();
	}
	
	DataSneakForm.prototype._addTag = function(iTag, sLabel) {
		this.bEdited = true;
		if(this.bTagsAdding && this.aTagsCurrentIndex.key_exists(iTag)) {
			this._removeTag(iTag);
			this.aTagsCurrent[iTag] = sLabel;
			this._displayTags();
			return(false);
		}
		if(this.bTagsAdding && !this.aTagsAdding.key_exists(iTag)) {
			this.aTagsAdding[iTag] = sLabel;
			this._displayTags();
			closeWrowser();
		}
	}
	
	DataSneakForm.prototype._removeTag = function(iTag) {
		if(this.bTagsRemove && this.aTagsRemove.key_exists(iTag)) {
			this.aTagsRemove.splice(iTag, 1);
		}
		if(this.bTagsAdding && this.aTagsAdding.key_exists(iTag)) {
			this.aTagsAdding.splice(iTag, 1);
		}
		if(this.bTagsCurrent && this.aTagsCurrent.key_exists(iTag)) {
			var sOld = this.aTagsCurrent.splice(iTag, 1);
			this.aTagsRemove[iTag] = sOld;
		}
		this._displayTags();
	}
	
	DataSneakForm.prototype._displayTags = function() {
		if(this.bTagsCurrent) {
			if(count(this.aTagsCurrent) > 0) {
				var sHtml = '<strong>Current Tags</strong><br />';
				var iAltBg = 1;
				for(i in this.aTagsCurrent) {
					if(isnumeric(i)) {
						sHtml += '<div class="page_content2 altbg_' + iAltBg + '"><input type="checkbox" name="tags_current" value="' + i + '" checked="checked" class="current_tags" id="' + this.aTagsRemove[i] + '">' + this.aTagsCurrent[i] + '</div>';
						iAltBg = iAltBg == 1 ? 2 : 1;
					};
				}
				this.oTagsCurrent.innerHTML = sHtml;
				oElems = fGEOBJLI('input', 'current_tags');
				for(i in oElems) {
					oElems[i].onclick = DataSneakRemoveTag;	
				}
			} else {
				this.oTagsCurrent.innerHTML = '';
			};
		};
		
		if(this.bTagsAdding) {
			if(count(this.aTagsAdding) > 0) {
				var sHtml = '<strong>Added Tags</strong><br />';
				var iAltBg = 1;
				for(i in this.aTagsAdding) {
					if(isnumeric(i)) {
						sHtml += '<div class="page_content2 altbg_' + iAltBg + '"><input type="checkbox" name="tags_add[]" value="' + i + '" checked="checked" class="added_tags" id="' + this.aTagsRemove[i] + '">' + this.aTagsAdding[i] + '</div>';
						iAltBg = iAltBg == 1 ? 2 : 1;
					};
				}
				this.oTagsAdding.innerHTML = sHtml;
				oElems = fGEOBJLI('input', 'added_tags');
				for(i in oElems) {
					oElems[i].onclick = DataSneakRemoveTag;	
				}
			} else {
				this.oTagsAdding.innerHTML = '';
			};
		};
		
		if(this.bTagsRemove) {
			if(count(this.aTagsRemove) > 0) {
				var sHtml = '<strong>Removed Tags</strong><br />';
				var iAltBg = 1;
				for(i in this.aTagsRemove) {
					if(isnumeric(i)) {
						sHtml += '<div class="page_content2 altbg_' + iAltBg + '"><input type="checkbox" name="tags_remove[]" value="' + i + '" checked="checked" class="removed_tags" id="' + this.aTagsRemove[i] + '">' + this.aTagsRemove[i] + '</div>';
						iAltBg = iAltBg == 1 ? 2 : 1;
					};
				}
				this.oTagsRemove.innerHTML = sHtml;
				oElems = fGEOBJLI('input', 'removed_tags');
				for(i in oElems) {
					oElems[i].onclick = DataSneakAddCurrentTag;	
				}
			} else {
				this.oTagsRemove.innerHTML = '';
			};
		};
	}
	
	DataSneakForm.prototype._submit = function() {
		this.oForm.submit();
	}
	
	DataSneakForm.prototype._delete = function() {
		this.oFormElements['frm_action'].value = 2;
		if(this.bTagsCurrent) {
			for(i in this.aTagsCurrent) {
				if(isnumeric(i))
					this._removeTag(i);
			}
			for(i in this.aTagsAdding) {
				if(isnumeric(i))
					this._removeTag(i);
			}
		}
		this.oForm.submit();
	}
	
	DataSneakForm.prototype._AutoCompletePress = function(sField, oEvent) {
		var reMultiField = /(inp_.+)\[(.*)\]/;
		aField = sField.match(reMultiField);
		this.aFields[aField[1]]._AutoCompletePress(oEvent);	
	}
	
	DataSneakForm.prototype._AutoCompleteFetch = function(sField, oEvent) {
		var reMultiField = /(inp_.+)\[(.*)\]/;
		aField = sField.match(reMultiField);
		this.aFields[aField[1]]._AutoCompleteFetch(oEvent);	
	}
	
	DataSneakForm.prototype._AutoCompleteHide = function(sField) {
		var reMultiField = /(inp_.+)\[(.*)\]/;
		aField = sField.match(reMultiField);
		this.aFields[aField[1]]._AutoCompleteHide();	
	}
	
function DataSneakField(sField) {
	this.sField         = sField;
	this.aInputs        = new Array();
	this.aInputKeys     = new Array();
	this.oDoubleCheck   = null;
	this.oAutoComplete  = null;
	this.aFieldRules    = new Array();
	this.aFieldInfo     = new Array();
	this.aCheckedFields = new Array();
	this.iSugInterval   = null;
	this.oImgCheck = document.getElementById(this.sField + '_check');
	this.bImgCheck = isset(this.oImgCheck);
	this.oDivRules = document.getElementById(this.sField + '_rules');
	this.bDivRules = isset(this.oDivRules);
	if(!this.bDivRules) this.oDivRules = {};
	this.oDivCount = document.getElementById(this.sField + '_characters');
	this.bDivCount = isset(this.oDivCount);
	if (this.bImgCheck) {
		this.aImgSrc = this.oImgCheck.src.match(/(.+\/icheck_)/);
	} else {
		this.aImgSrc = {};
	}
}

	DataSneakField.prototype.addInput = function(oInput, sKey) {
		oInput.onfocus = function(event) {oDataSneak._focus(event);};
		if(sKey == 'check') {
			this.oDoubleCheck = oInput;
		} else if(!isset(sKey)) {
			this.aInputs.push(oInput);
		} else {
			var i = this.aInputs.push(oInput);
			this.aInputKeys[sKey] = i;
		}
	}
	
	DataSneakField.prototype._defineRule = function(sRule) {
		var sRule = new String(sRule);
		var aRule = sRule.split('=');
		if(isset(aRule[0]) && isset(aRule[1])) this.aFieldRules[parseInt(aRule[0])] = parseInt(aRule[1]);
	}
	
	DataSneakField.prototype._defineRules = function(aRules) {
		for(i in aRules) {
			if(isnumeric(i)) {
				this.aFieldRules[i] = aRules[i]['value'];
				if(isset(aRules[i]['info']))
					this.aFieldInfo[i] = aRules[i]['info'];
			}
		}
	}
	
	DataSneakField.prototype._defineBehavior = function(aBehavior) {
		for(type in aBehavior) {
			switch(type) {
				case 'autocomplete':
					this.oAutoComplete = new DataSneakAutoComplete(this.aInputs[0]);
					for(cfg in aBehavior[type]) {
						switch(cfg) {
							case 'controller':
								this.oAutoComplete.controller(aBehavior[type][cfg]);
								break;
							case 'action':
								this.oAutoComplete.action(aBehavior[type][cfg]);
								break;
							case 'object':
								this.oAutoComplete.object(aBehavior[type][cfg]);
								break;
							case 'format':
								this.oAutoComplete.format(aBehavior[type][cfg]);
								break;
							case 'key':
								this.oAutoComplete.key(aBehavior[type][cfg]);
								break;
							case 'display':
								this.oAutoComplete.display(aBehavior[type][cfg]);
								break;
						}
					}
				break;
			};
		}
	}
	
	DataSneakField.prototype._displayRules = function() {
		var sRules = '<ul class="validate">';
		var sRule  = '';
		for(i in this.aFieldRules) {
			if(isnumeric(i)) {
				switch(parseInt(i)) {
					case IRULE_MIN_LENGTH:
						sRule = 'Min Length of ' + this.aFieldRules[i];
						break;
					case IRULE_MAX_LENGTH:
						sRule = 'Max Length of ' + this.aFieldRules[i];
						break;
					case IRULE_UNIQUE:
						sRule = 'Unique';
						break;
					case IRULE_DOUBLE_CHECK:
						sRule = 'Retype';
						break;
					case IRULE_FILETYPES:
						sRule = 'Accepted Filetypes: ' + this.aFieldRules[i];
						break;
					case IRULE_NUMBER:
						sRule = 'Number';
						break;
					case IRULE_FORMAT:
						if(isset(this.aFieldInfo[i]))
							sRule = this.aFieldInfo[i];
						break;
				};
				sRules += isset(this.aCheckedFields[i]) ? (this.aCheckedFields[i] ? '<li class="good">' + sRule + '</li> ' : '<li>' + sRule + '</li> ') : '<li class="bad">' + sRule + '</li> ';
			};
		};
		sRules += '</ul>';
		this.oDivRules.innerHTML = sRules;	
	}
	
	DataSneakField.prototype._hideRules = function() { 
		this.oDivRules.innerHTML = '';	
	}
	
	DataSneakField.prototype._setCheckResult = function(iRule, bGood) {
		
	}
	
	DataSneakField.prototype._AutoCompletePress = function(oEvent) {
		switch(oEvent.keyCode) {
			case 38: //Up Arrow
				this.oAutoComplete.clearIntervals();
				this.oAutoComplete.changeSuggestion(-1);
				oEvent.returnValue = false;
				if(oEvent.preventDefault) {
					oEvent.preventDefault();	
				}
				break;
			case 40: //Down Arrow
				this.oAutoComplete.clearIntervals();
				this.oAutoComplete.changeSuggestion(1);
				oEvent.returnValue = false;
				if(oEvent.preventDefault) {
					oEvent.preventDefault();	
				}
				break;
			case 27: //Escape
				oEvent.returnValue = false;
				if(oEvent.preventDefault) {
					oEvent.preventDefault();	
				}
				break;
			case 13: //Enter
				oEvent.returnValue = false;
				if(oEvent.preventDefault) {
					oEvent.preventDefault();	
				}
				break;
			
			case 9: //Enter
				break;
			
			default:
				this.oAutoComplete.clearIntervals();
				break;
		}
		
	}
	
	DataSneakField.prototype._AutoCompleteFetch = function(oEvent) {
		switch(oEvent.keyCode) {
			case 38: //Up Arrow
				
				this.oAutoComplete.getSuggestions();
				oEvent.returnValue = false;
				if(oEvent.preventDefault) {
					oEvent.preventDefault();	
				}
				break;
			case 40: //Down Arrow
				
				this.oAutoComplete.getSuggestions();
				oEvent.returnValue = false;
				if(oEvent.preventDefault) {
					oEvent.preventDefault();	
				}
				break;
			case 27: //Escape
				this.oAutoComplete.hideSuggestions();
				this.oAutoComplete.hideTypeAhead();
				break;
			case 13: //Enter
				this.oAutoComplete.hideSuggestions();
				this.oAutoComplete.enterTypeAhead();
				oEvent.returnValue = false;
				if(oEvent.preventDefault) {
					oEvent.preventDefault();	
				}
				break;
			default:
				this.oAutoComplete.getSuggestions();
				break;
		}
	}
	
	DataSneakField.prototype._AutoCompleteHide = function() {
		this.oAutoComplete.hideSuggestions();
	}
	
function DataSneakJudge() {
	var bIsGood = true;
	for(input in this.aInputs) {
		if(isnumeric(input)) for(i in this.aFieldRules) {
			this.aCheckedFields[i] = true;
			if(this.aInputs[input].value == '') {
				bIsGood = false;
				this.aCheckedFields[i] = false;
			};
	
			switch(parseInt(i)) {
				case IRULE_MIN_LENGTH:
					
					if(this.aInputs[input].value.length < this.aFieldRules[i]) {
						bIsGood = false;
						this.aCheckedFields[i] = false;
					};
					break;
				case IRULE_MAX_LENGTH:
					
					if(this.aInputs[input].value.length > this.aFieldRules[i]) {
						bIsGood = false;
						this.aCheckedFields[i] = false;
					};
					break;
				case IRULE_UNIQUE:
					
					break;
				case IRULE_DOUBLE_CHECK:
					if(isset(this.oDoubleCheck) && this.aInputs[input].value != this.oDoubleCheck.value) {
						bIsGood = false;
						this.aCheckedFields[i] = false;
					};
					break;
				case IRULE_FILETYPES:
					
					break;
				case IRULE_NUMBER:
					var regExp = /^[0-9]+$/;
					if(!regExp.test(this.aInputs[input].value)) {
						bIsGood = false;
						this.aCheckedFields[i] = false;
					}
					break;
				case IRULE_FORMAT:
					var regExp = this.aFieldRules[i];
					if(regExp.substr(0,1) == '/') regExp = regExp.substr(1);
					if(regExp.substr(regExp.length - 1,1) == '/') regExp = regExp.substr(0, regExp.length - 1);
					var sValue = new String(this.aInputs[input].value.toLowerCase());
					if(!sValue.match(regExp)) {
						bIsGood = false;
						this.aCheckedFields[i] = false;
					}
					break;
			};
		};
	};
	return(bIsGood);
}

function DataSneakAutoComplete(oField) {
	this.oField      = oField;
	this.sController = null;
	this.sAction     = null;
	this.sObject     = null;
	this.sFormat     = 'serphp';
	this.sKey        = null;
	this.sDisplay    = null;
	this.aKeys       = new Array();
	this.aResults    = new Array();
	this.aResultKeys = new Array();
	this.iResults    = 0;
	this.iCount      = 0;
	this.iLength     = 0;
	this.iSelected   = 0;
	this.iTAInterval = null;
	this.bTypeAhead  = false;
	this.bVisible    = true;
	var reMultiField = /(inp_.+)\[(.*)\]/;
	aField = oField.name.match(reMultiField);
	this.oSuggestionDiv = document.getElementById(aField[1] + '_autocomplete');
	addEvent('onkeydown', this.oField, DataSneakAutoCompletePress);
	addEvent('onkeyup', this.oField, DataSneakAutoCompleteFetch);
	addEvent('onblur', this.oField, DataSneakAutoCompleteHide);
}
	DataSneakAutoComplete.prototype.reDisplay = /##[^#]+##/g;
	DataSneakAutoComplete.prototype.reDisplayKey = /^##(.+)##$/;
	DataSneakAutoComplete.prototype.controller = function(s) {
		this.sController = s;
	}

	DataSneakAutoComplete.prototype.action = function(s) {
		this.sAction = s;
	}

	DataSneakAutoComplete.prototype.object = function(s) {
		this.sObject = s;
	}
	
	DataSneakAutoComplete.prototype.format = function(s) {
		
	}

	DataSneakAutoComplete.prototype.key = function(s) {
		this.sKey = s;
	}

	DataSneakAutoComplete.prototype.display = function(s) {
		this.sDisplay = s;
		var aMatches = s.match(this.reDisplay);
		for(i in aMatches) {
			if(isnumeric(i)) {
				if(a = aMatches[i].match(this.reDisplayKey))
					this.aKeys[a[1]] = aMatches[i];
			}
		}
	}
	
	DataSneakAutoComplete.prototype.changeSuggestion = function(value) {
		this.iSelected += value;
		if(this.iSelected < 0)
			this.iSelected = this.iCount;
		if(this.iSelected > this.iCount)
			this.iSelected = 0;
		jsdebug(this.iSelected);
		this.getSuggestions();
	}
	
	DataSneakAutoComplete.prototype.getSuggestions = function() {
		if(this.oField.value == '') {
			this.hideSuggestions();
			return(false);
		} else if(this.oField.value == this.sLastCheck) {
			
		}
		var key = this.aResultKeys.find_value(this.oField.value);
		this.sLastCheck = this.oField.value;
		this.iLength    = this.oField.value.length;
		this.bVisible   = true;
		if(key > -1) {
			this.showSuggestions(this.aResults[key]);
		} else {
			var sLink = '?' + this.sController + '/' + this.sAction + '/' + this.oField.value.replace(/\s/g, '_') + '/display:serphp';
			oTOwl.sget(sLink, this, this._parseSuggestions);
		};
	}
	
	DataSneakAutoComplete.prototype._parseSuggestions = function(sSuggestions) {
		var a = PHP_Unserialize(sSuggestions);
		var sQuery = a['info']['query'];
		var iCount = a['info']['results'];
		jsdebug(sQuery + ' returned');
		this.aResultKeys[this.iResults] = sQuery;
		this.aResults[this.iResults] = a;
		this.iCount = iCount - 1;
		this.iSelected = 0;
		this.showSuggestions(a);
		this.iResults++;
	}
	
	DataSneakAutoComplete.prototype.showSuggestions = function(a) {
		if(!this.bVisible) return(false);
		clearInterval(this.iTAInterval);
		this.iCount = a['info']['results'] - 1;
		var oSelf = this;
		this.oSuggestionDiv.style.display = "inline";
		this.oSuggestionDiv.innerHTML = '';
		var iCount = 0;
		if(a['result']) {
			for(sug in a['result']) {
				if(isnumeric(sug)) {
					//Call type ahead function with the first suggestion
					if(this.iSelected == iCount && this.sLastCheck.toLowerCase == a['result'][sug][this.sKey].substring(0, this.iLength).toLowerCase) {
						sSuggestion = a['result'][sug][this.sKey];
						this.iTAInterval = setInterval(function() 
							{
								oSelf.showTypeAhead(sSuggestion);
								clearInterval(oSelf.iTAInterval);
							}, 400);
					}
					//Draw suggestions
					var sDisplay = this.sDisplay;
					for(i in this.aKeys) {
						if(this.sKey == i && this.iSelected == iCount) {
							//Highlight Typed Letters
							sText = "<span class=\"highlight\">" + a['result'][sug][i].substring(0, this.iLength) + "</span>" + a['result'][sug][i].substring(this.iLength);
							sDisplay = sDisplay.replace(this.aKeys[i], sText);
						} else {
							sDisplay = sDisplay.replace(this.aKeys[i], a['result'][sug][i]);
						}
					}
					if(this.iSelected == iCount) {
						sDisplay = "<div class=\"suggestion current\">" + sDisplay + "</div>";
					} else {
						sDisplay = "<div class=\"suggestion\">" + sDisplay + "</div>";
					}
					this.oSuggestionDiv.innerHTML = this.oSuggestionDiv.innerHTML + sDisplay;
					iCount++;
				}
			}
		} else {
			this.oSuggestionDiv.innerHTML = "No results found";
		}
	}
	
	DataSneakAutoComplete.prototype.hideSuggestions = function() {
		this.bVisible = false;
		this.oSuggestionDiv.style.display = "none";
		this.oSuggestionDiv.innerHTML = '';
	}
	
	DataSneakAutoComplete.prototype.showTypeAhead = function(sSuggestion) {
		jsdebug(sSuggestion);
		if(this.bTypeAhead)
			return(false);
		if(this.oField.createTextRange || this.oField.setSelectionRange) {
			var iLen = this.oField.value.length;
			this.oField.value = sSuggestion;
			this.selectRange(iLen, sSuggestion.length);
			this.bTypeAhead = true;
		}
	}
	
	DataSneakAutoComplete.prototype.hideTypeAhead = function() {
		if(this.iLength != 0)
			this.oField.value = this.oField.value.substring(0, this.iLength);
		this.selectRange(this.iLength);
		this.bTypeAhead = false;
	}
	
	DataSneakAutoComplete.prototype.enterTypeAhead = function() {
		var sVal = this.oField.value;
		this.oField.value = '';
		this.oField.value = sVal;
		this.bTypeAhead = false;
	}
	
	DataSneakAutoComplete.prototype.selectRange = function(iS,iE) {
		if(this.oField.createTextRange) {
			var oRange = this.oField.createTextRange();
			oRange.moveStart("character", iS);
			oRange.moveEnd("character", iE - this.oField.value.length);
			oRange.select();
		} else if(this.oField.setSelectionRange) {
			if(this.oField.value.length > iS)
				this.oField.setSelectionRange(iS, iE);
		}
	}
	
	DataSneakAutoComplete.prototype.clearIntervals = function() {
		if(this.bTypeAhead)
			this.hideTypeAhead();
		clearInterval(this.iTAInterval);	
	}


function DataSneakCheck(oEvent) {
	oEvent = oEvent ? oEvent : event;
	oDataSneak._check(oEvent);	
}

function DataSneakSubmit(oEvent) {
	oDataSneak._submit(oEvent);
	return(false);
}

function DataSneakDelete(oEvent) {
	if(confirm('Are you sure you want to delete this record?'))
		oDataSneak._delete(oEvent);
	return(false);
}

function DataSneakTagger(oEvent) {
	oDataSneak._tagger(oEvent);
}

function DataSneakAddTag(oWrowserArgs, oDataSneakArgs) {
	if(isset(oDataSneakArgs.Form))
		oDataSneak._addTag(oDataSneakArgs.Form, oWrowserArgs.Tag, oWrowserArgs.Label);
}

function DataSneakAddCurrentTag(oEvent) {
	oField = fGEOBJ(oEvent);
	var sForm  = oField.form.name;
	var iTag = oField.value;
	var sLabel = oField.id;
	oDataSneak._addTag(sForm, iTag, sLabel);
}

function DataSneakRemoveTag(oEvent) {
	oDataSneak._removeTag(oEvent);
}

function DataSneakCheckem(oEvent) {
	oField  = fGEOBJ(oEvent);
	sForm   = oField.form.name;
	oForm   = document.forms[sForm];
	for(var i = 0;i<oForm.elements.length;i++) {
		var oEle = oForm.elements[i];
		if(oEle.type == 'checkbox')
			oEle.checked = oField.checked;
	}	
}

function DataSneakAutoCompletePress(oEvent) {
	oEvent = oEvent ? oEvent : event;
	oDataSneak._AutoCompletePress(oEvent);
}

function DataSneakAutoCompleteFetch(oEvent) {
	oEvent = oEvent ? oEvent : event;
	oDataSneak._AutoCompleteFetch(oEvent);
}

function DataSneakAutoCompleteHide(oEvent) {
	oDataSneak._AutoCompleteHide(oEvent);
}

function DataSneakInit() {
	DataSneakAddEvents(fGEOBJLI('input', 'unchecked'));
	DataSneakAddEvents(fGEOBJLI('textarea', 'unchecked'));
	DataSneakAddTagger(fGEOBJLI('input', 'tagger'));
	DataSneakCurrentTags(fGEOBJLI('input', 'current_tags'));
	DataSneakButtons(fGEOBJLI('input', 'form_button'));
	DataSneakCheckAll(fGEOBJLI('input', 'form_check_all'));
}

function DataSneakAddEvents(aElems) {
	for(i in aElems) {
    	aElems[i].onkeyup = DataSneakCheck;
		aElems[i].onblur  = DataSneakCheck;
	};
}

function DataSneakAddTagger(aElems) {
	for(i in aElems) {
    	aElems[i].onmousedown = DataSneakTagger;
	};
}

function DataSneakCurrentTags(aElems) {
	for(i in aElems) {
    	aElems[i].onclick = DataSneakRemoveTag;
	};
}

function DataSneakButtons(aElems) {
	for(i in aElems) {
		if(aElems[i].name == 'btn_submit')
    		aElems[i].onclick = DataSneakSubmit;
		if(aElems[i].name == 'btn_delete')
    		aElems[i].onclick = DataSneakDelete;
	};
}

function DataSneakCheckAll(aElems) {
	for(i in aElems) {
    	aElems[i].onclick = DataSneakCheckem;
	};	
}

var oDataSneak = new DataSneak();
WindowOnload(DataSneakInit);
