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

	init: function(settings) {
		tx_ohform.settings = settings;
			// Setup event listeners:
		this.forEachFormField(function(element) {
			Event.observe(element, 'focus', tx_ohform.onFocusHandler);
			Event.observe(element, 'blur', tx_ohform.onBlurHandler);
			if (tx_ohform.settings.prices && tx_ohform.settings.prices[tx_ohform.getShortIdOfElement(element)]) {
				Event.observe(element, 'change', tx_ohform.onChangeHandler);
			}
			tx_ohform.createTooltip(element);
		});
			// Show price summary (useful when form was reloaded and form values were not resetted):
		if (tx_ohform.settings.prices) {
			tx_ohform.calculatePriceSummary();
		}
	},

	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) {
			tx_ohform.evaluateField(element, { shake: true, mark: true });
			tx_ohform.calculatePriceSummaryTrigger(element);
			if (tx_ohform.tooltips[element.id] && typeof tx_ohform.tooltips[element.id]!='undefined') {
				Element.hide(tx_ohform.tooltips[element.id]);
			}
		}
	},

	onChangeHandler: function(event) {
		var element = Event.element(event);
		if (element && element.id) {
			tx_ohform.calculatePriceSummaryTrigger(element);
		}
	},

	/********************************************************************************************************
	 * 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.cumulativeOffset(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 error = false;
		var firstError = null;
		tx_ohform.forEachField(function(field) {
			var element = tx_ohform.getElementByField(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 = tx_ohform.getShortIdOfElement(element);
		var fieldNeedsEvaluation = (fieldName && tx_ohform.settings.fields && tx_ohform.settings.fields[fieldName]);

		if (fieldNeedsEvaluation) {
				// 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':
					// use same regexp as typo
					result = (fieldValue.match(/^[A-Za-z0-9\._-]+[@][A-Za-z0-9\._-]+[\.].[A-Za-z0-9]+$/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 'ajax':
					result = 0;
					params = {}
					params[element.name] = fieldValue;
					if (settings.url && settings.method) {
						request = new Ajax.Request(settings.url, {
							method: 'post',
							parameters: params,
							asynchronous: false,
							onSuccess: function(transport) {
								result = parseInt(transport.responseText);
							}.bind(this)
						});
					}
					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 (fieldNeedsEvaluation && 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;
	},

	/********************************************************************************************************
	 * Section: Price Calculation
	 ********************************************************************************************************/

	calculatePriceSummaryTrigger: function(element) {
		element = $(element);
		var fieldName = tx_ohform.getShortIdOfElement(element);
		if (tx_ohform.settings.prices && tx_ohform.settings.prices[fieldName]) {
			tx_ohform.calculatePriceSummary();
		}
	},

	calculatePriceSummary: function() {
		var value = 0, intValue, floatValue;
		var summaryElement = $('tx_ohform_pi1__summary');
		if (Object.isElement(summaryElement) && tx_ohform.settings.prices) {
			$H(tx_ohform.settings.prices).each(function(selectorElement) {
				var element = tx_ohform.getElementByField(selectorElement.key);
				value += (element.type=='checkbox' ? element.checked : element.value)*selectorElement.value;
			});
			intValue = Math.floor(value);
			floatValue = (value-intValue).toFixed(2)*100;
			summaryElement.innerHTML = intValue+','+floatValue.toPaddedString(2);
		}
	},

	/********************************************************************************************************
	 * Section: Helpers
	 ********************************************************************************************************/

	getShortIdOfElement: function(element) {
		return element.id.substr(14);
	},

	getElementByShortId: function(shortId) {
		var result = null;
		if (tx_ohform.settings.config.prefix && shortId) {
			result = tx_ohform.getElementByField(shortId);
		}
		return result;
	},

	trimElementValue: function(element, ignoreConfig) {
		element = $(element);
		var fieldValue = $F(element);
		if (fieldValue==null) {
			fieldValue = '';
		} else 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) {
		element = $(element);
		while (element && element.parentNode && !Element.hasClassName(element, className)) {
			element = element.parentNode;
		}
		return element;
	},

	forEachElement: function(elements, callback) {
		elements.each(function(field) {
			callback(field);
		});
	},

	forEachFormField: function(callback) {
		this.forEachElement(Form.getElements('tx_ohform_pi1_form'), callback);
	},

	forEachField: function(callback) {
		if (tx_ohform.settings.fields && tx_ohform.settings.config && tx_ohform.settings.config.prefix) {
			this.forEachElement($H(tx_ohform.settings.fields).keys(), callback);
		}
	},

	getElementByField: function(field) {
		return $(tx_ohform.settings.config.prefix+'_'+field);
	}
};