var tx_ohform = {
	settings: {},
	tooltips: {},

	init: function(settings) {
		tx_ohform.settings = settings;
			// Setup event listeners:
		var prefix = tx_ohform.settings.config.prefix;
		this.forEachField(function(field) {
			var element = prefix+'_'+field;
			if ($(element)) {
				Event.observe(element, 'focus', tx_ohform.onFocusHandler);
				Event.observe(element, 'blur', tx_ohform.onBlurHandler);
				tx_ohform.createTooltip(element);
			}
		});
	},
	
	onFocusHandler: function(event) {
		var element = Event.element(event);
		if (element && element.id) {
			Element.removeClassName(element, 'error');
			if (tx_ohform.tooltips[element.id] && typeof tx_ohform.tooltips[element.id]!='undefined') {
				Element.show(tx_ohform.tooltips[element.id]);
			}
		}
	},

	onBlurHandler: function(event) {
		var element = Event.element(event);
		if (element && element.id) {
			var result = tx_ohform.evaluateField(element, { shake: true, mark: true });
			if (tx_ohform.tooltips[element.id] && typeof tx_ohform.tooltips[element.id]!='undefined') {
				Element.hide(tx_ohform.tooltips[element.id]);
			}
		}
	},
	
	/********************************************************************************************************
	 * Section: Tooltip/Help
	 ********************************************************************************************************/
	
	createTooltip: function(element) {
		element = $(element);
		if (element && element.id && element.title) {
			var tooltipId = element.id+'_'+'tooltip';
			var tooltip = tx_ohform.createTooltipLayout(element, tooltipId);
			document.body.appendChild(tooltip);
			tx_ohform.setTooltipPosition(element, tooltip);
			tx_ohform.tooltips[element.id] = tooltipId;
		}
	},
	
	createTooltipLayout: function(element, tooltipId) {
		var tooltip = document.createElement('div');
		var tooltipLeft = document.createElement('div');
		var tooltipRight = document.createElement('div');
		
		tooltip.id = tooltipId;
		tooltip.style.display = 'none';
		Element.addClassName(tooltip, 'tx-ohform-pi1 tooltip clearfix');

		Element.addClassName(tooltipRight, 'inner');
		tooltipRight.innerHTML = element.title;

		tooltip.appendChild(tooltipLeft);
		tooltip.appendChild(tooltipRight);

		return tooltip;
	},

	setTooltipPosition: function(element, tooltip) {
		var elOffset = Element.positionedOffset(element);
		var elDimensions = Element.getDimensions(element);
		var ttDimentions = Element.getDimensions(tooltip);
		
		
		Element.setStyle(tooltip, {
			'position': 'absolute',
			'left': (elOffset.left+elDimensions.width)+'px',
			'top': (elOffset.top-Math.round((ttDimentions.height-elDimensions.height)/2))+'px'
		});
	},

	/********************************************************************************************************
	 * Section: Evaluation
	 ********************************************************************************************************/

	evaluateAllFields: function(form) {
		form = $(form);
		var prefix = tx_ohform.settings.config.prefix;
		var error = false;
		var firstError = null;
		tx_ohform.forEachField(function(field) {
			var element = $(prefix+'_'+field);
			if (!tx_ohform.evaluateField(element, { mark: true })) {
				if (!error) {
					firstError = element;
					error = true;
				}
			}
		});
		if (!error && form) {
			form.submit();
		}
		if (error && firstError) {
			firstError.focus();
		}
	},

	evaluateField: function(element, options, settings) {
		element = $(element);
		var settingsCase, tempValue, tempCaseValue, tempElement, tempRegExp, tempRequired=false;
		var result = 1;
		var fieldName = element.id.substr(element.id.lastIndexOf('_')+1);
		if (fieldName && tx_ohform.settings.fields && tx_ohform.settings.fields[fieldName]) {
				// If there are settings which override the regular behaviour, merge them:
			if (settings) {
				if (tx_ohform.settings.fields[fieldName].required || settings.isRequired) {
					settings.required = true;
				}
				// Use the regular behaviour settings:
			} else {
				settings = tx_ohform.settings.fields[fieldName];
			}
			var fieldValue = tx_ohform.trimElementValue(element);
			if (settings.stripSpaces) {
				fieldValue = fieldValue.replace(/\s/g, '');
				element.value = fieldValue;
			}
			switch(settings.type) {
				case 'email':
					result = (fieldValue.match(/^\w[\w\.-]*\@([a-z][\w-]*\.)+[a-z]{2,}$/i) ? 1 : 0);
					break;
				case 'int':
					result = (parseInt(fieldValue)==fieldValue ? 1 : 0);
					if (settings.data) {
						switch(settings.data) {
							case 'pos':
								result = (result && fieldValue>0 ? 1 : 0);
								break;
							case 'empty':
								result = (result || !fieldValue.length ? 1 : 0);
								break;
							case 'posempty':
							case 'emptypos':
								result = (result && fieldValue>0 || !fieldValue.length ? 1 : 0);
								break;
						}
					}
					break;
				case 'emptyint':
					result = (!fieldValue.length || parseInt(fieldValue)===fieldValue ? 1 : 0);
					break;
				case 'posint':
					result = (parseInt(fieldValue)>1 ? 1 : 0);
					break;
				case 'phone':
					tempValue = fieldValue.replace(/\s+/g, '');
					result = (tempValue.match(/^(\+\d+)?(\/|\.|-)?\d{2,}((\/|\.|-)?(\w|\d)+)+$/) ? 1 : 0);
					break;
				case 'regexp':
					if (settings.data) {
						tempRegExp = settings.data.replace(/^\/|\/$/g, '');
						result = (fieldValue.match(new RegExp(tempRegExp)) ? 1 : 0);
					}
					break;
				case 'equal':
					if (settings.data) {
						tempValue = tx_ohform.trimElementValue(
							tx_ohform.getElementByShortId(settings.data)
						);
						result = (tempValue==fieldValue ? 1 : 0);
					}
					break;
				case 'case':
					if (settings.data && settings['case']) {
						settingsCase = settings['case'];
						tempValue = tx_ohform.trimElementValue(
							tx_ohform.getElementByShortId(settings.data)
						);
						if (settingsCase[tempValue] || settingsCase['default']) {
							tempCaseValue = (settingsCase[tempValue] ? tempValue : 'default');
							tempRequired = (settingsCase[tempCaseValue].isRequired ? true : false);
							result = tx_ohform.evaluateField(element, null, settingsCase[tempCaseValue]);
						} else {
							result = 1;
						}
					} else {
						result = 0;
					}
					break;
				default:
					result = (fieldValue.length>0 ? 1 : 0);
					break;
			}
				// Fix the "false-negatives", has to be done here because of the temporary required possibility:
			if (!result && !settings.required && !tempRequired && !(tx_ohform.settings.config.evalIfFilled && fieldValue.length)) {
				result = 1
			}
		}
			// Visualization of the error by style and effect:
		if (options) {
			if (!result && options.shake) {
				tx_ohform.shakeElement(element, 2, 2);
			}
			if (options.mark) {
				Element[result ? 'removeClassName' : 'addClassName'](
					tx_ohform.getParentElementByClassName(element, 'container'),
					'error'
				);
			}
		}
		return result;
	},
	
	getElementByShortId: function(shortId) {
		var result = null;
		if (tx_ohform.settings.config.prefix && shortId) {
			result = $(tx_ohform.settings.config.prefix+'_'+shortId);
		}
		return result;
	},

	trimElementValue: function(element, ignoreConfig) {
		element = $(element);
		var fieldValue = $F(element);
		if (tx_ohform.settings.config.trimFields || ignoreConfig) {
			fieldValue = fieldValue.replace(/^\s+|\s+$/g, '');
			if (fieldValue!=$F(element)) {
				element.value = fieldValue;
			}
		}
		return fieldValue;
	},
	
	shakeElement: function(element, xvar, yvar) {
		element = $(element);
		if (!xvar) { xvar = 0; }
		if (!yvar) { yvar = 0; }
		var oldStyle = {
			top: element.getStyle('top'),
			left: element.getStyle('left')
		};
		return new Effect.Move(element, 
			{ x:  xvar, y: yvar, duration: 0.05, afterFinishInternal: function(effect) {
			new Effect.Move(effect.element,
			{ x: -xvar*2, y: -yvar*2, duration: 0.1,  afterFinishInternal: function(effect) {
			new Effect.Move(effect.element,
			{ x:  xvar*2, y: yvar*2, duration: 0.1,  afterFinishInternal: function(effect) {
			new Effect.Move(effect.element,
			{ x: -xvar*2, y: -yvar*2, duration: 0.05, afterFinishInternal: function(effect) {
			effect.element.undoPositioned().setStyle(oldStyle);
			}}) }}) }}) }}
		);
	},

	getParentElementByClassName: function(element, className) {
		var originalElementId, classNameFound=false;
		element = $(element);
		originalElementId = element.id;
		while (element && element.parentNode) {
			element = element.parentNode;
			if (element.className && Element.hasClassName(element, className)) {
				classNameFound = true;
				break;
			}
		}
		if (!classNameFound) {
			element = $(originalElementId);
		}
		return element;
	},
	
	forEachField: function(callback) {
		if (tx_ohform.settings.fields && tx_ohform.settings.config && tx_ohform.settings.config.prefix) {
			var fields = $H(tx_ohform.settings.fields).keys();
			$A(fields).each(function(field) {
				callback(field);
			});
		}
	}
};