/**
 * General purpose event constructor.
 * Allows multiple event handlers to listen for the event.
 *
 * @return  void
 */
function CustomEvent() {
	// list of registered event handlers
	this._handlers = [];
} // end: function CustomEvent

/**
 * Register a callback function for the event (function name is also allowed).
 * Optionally an object can be passed which will be the object the function
 * is applied on.
 * If the callback function returns `false` (means 'interrupt') then the
 * remaining callback functions will not be called.
 *
 * @param   function|string  function   The event handling callback function.
 * @param   obj              object     The object the callback function shall
 *                                      be applied on.
 * @return  void
 */
CustomEvent.prototype.addHandler = function(func, obj) {
	if (typeof func == 'string') {
		func = window[func];
	} // end: if

	if (!obj) {
		obj = null;
	} // end: if

	if (typeof func == 'function') {
		this._handlers.push([func, obj]);
	} // end: if
}; // end: function CustomEvent.prototype.addHandler

/**
 * Trigger the event. Pass any arguments you like. Will passed to the
 * event handlers.
 *
 * @param   *                *          Variable list of arguments.
 *                                      be applied on.
 * @return  null|false                  Returns `false` if any event handler
 *                                      has interrupted the process, otherwise `null`.
 */
CustomEvent.prototype.trigger = function(_someArgs_) {
	var retVal = null;

	// Call each registered handler.
	for (var i = 0; i < this._handlers.length;  ++i) {
		var handler = this._handlers[i];
		var func = handler[0];
		var obj = handler[1];

		// Interrupt on return value `false`.
		if (func.apply(obj, arguments) === false) {
			retVal = false;
			break;
		} // end: if
	} // end: if

	return retVal;
}; // end: function CustomEvent.prototype.trigger

/**
 * Returns an array of the names of all own properties of a given object,
 * without the properties inherited from its prototype.
 *
 * @param   object  obj  Object in question
 * @return  array
 */
function getOwnProperties(obj) {
	var returnValue = [];

	if (obj) {
		for (var prop in obj) {
			if (obj.hasOwnProperty(prop)) {
				returnValue.push(prop);
			} // end: if
		} // end: for
	} // end: if

	return returnValue;
} // end: function getOwnProperties

/**
 * Converts a value to an integer value.
 * If the value is numeric then its rounded value will be returned, otherwise 0.
 *
 * @param   mixed  val  Value in question
 * @return  integer
 */
function toInteger(val) {
	var returnValue = Math.round(val);

	if (isNaN(returnValue) || !isFinite(returnValue)) {
		returnValue = 0;
	} // end: if

	return returnValue;
} // end: function toInteger

/**
 * Converts a value to an integer value or null if not numeric.
 * If the value is numeric then its rounded value will be returned, otherwise null.
 *
 * @param   mixed  val  Value in question
 * @return  integer
 */
function toIntegerOrNull(val) {
	var returnValue = Math.round(val);

	if (isNaN(returnValue) || !isFinite(returnValue)) {
		returnValue = null;
	} // end: if

	return returnValue;
} // end: function toIntegerOrNull

/**
 * Converts a value to an number value.
 * If the value is numeric then its number value will be returned, otherwise 0.
 *
 * @param   mixed  val  Value in question
 * @return  number
 */
function toNumber(val) {
	var returnValue = parseFloat(val);

	if (isNaN(returnValue) || !isFinite(returnValue)) {
		returnValue = 0;
	} // end: if

	return returnValue;
} // end: function toNumber

/**
 * Converts a value to an float value or null if not numeric.
 * If the value is numeric then its number value will be returned, otherwise null.
 *
 * @param   mixed  val  Value in question
 * @return  number
 */
function toNumberOrNull(val) {
	var returnValue = parseFloat(val);

	if (isNaN(returnValue) || !isFinite(returnValue)) {
		returnValue = null;
	} // end: if

	return returnValue;
} // end: function toNumberOrNull

/**
* toggles a image between two states
* call like this: onMouseOver="gfxToogle(this, 'active.gif', 'inactive.gif')" onMouseOut="gfxToogle(this, 'active.gif', 'inactive.gif')"
* image paths and current state are determined automatically.
*
* @access	public
* @param	object		gfx			a DOM object with a .src parameter
* @param	string		active		the filename (no path!) to the active-state image
* @param	string		inactive	the filename (no path!) to the inactive-state image
* @return	void
*/
function gfxToggle(gfx, active, inactive) {

	if (typeof gfx == 'object' && gfx.src) {

		var matches = gfx.src.match(/^(.*)\/([^\/]+)$/);

		switch (matches[2]) {
			case active:
				gfx.src = matches[1] + '/' + inactive;
				break;

			case inactive:
				gfx.src = matches[1] + '/' + active;
				break;

			default:
		} /* end: switch */
	} /* end: if */
}

/**
* toggles visibility of an object
* call like this:
* // for making an object visible
* showHideObject('objctId', true)
*
* // for making an object invisible
* showHideObject('objctId', false)
*
* // for making an object flexible to a checkbox
* // if checkbox checked than show else hide
* <input type="checkbox" onChange="showHideObject('objctId', this.checked)">
*
* @access	public
* @param	string		objectid	of the element to be shown or hidden
* @param	boolean		visibility	of the element to be shown or hidden
* @return	void
*/
function showHideObject(objId, visibility) {

	if (objId) {
		var object = document.getElementById(objId);

		if (object) {

			switch (visibility) {
				case false:
					object.style.visibility = 'hidden';
					object.style.display = 'none';
					break;

				case true:
					object.style.visibility = 'visible';
					object.style.display = 'block';
					break;
			} // end: switch

		} /* end: if */


	} /* end: if */
}
/**
 *	Function to skip some inputs automatically
 *
*/
function nextField(e, source, dest, fieldlen) {
 	if (!e) var e = window.event;

 	// Keine Controlchars
 	if (e.keyCode > 32)
 	{
 		if (source.value.length == fieldlen)
 		{
 			dest.value='';
 			dest.focus();
 		}
 	}
} //function

/**
 *	Function to reset forms
 *
*/
function resetForm(url) {
	window.location.href=url;
}

/**
 * Function to open a layer window containing an iframe
 * that loads a given URL.
 * One and only argument is a property object that contains
 * all properties necessary to build the layer window.
 *
 * Allowed properties are:
 * - url: The URL to load in iframe.
 * - width: Width of the iframe.
 * - height: Height of the iframe.
 * - left: Left position of the layer window.
 * - top: Top position of the layer window.
 * - textClose: Text that shall be shown with the link that closes the layer.
 * - scrollable: Script that indicates whether iframe shall be scrollable.
 * - className: CSS class name of the layer window.
 * - id: ID of the layer window.
 * - onlyOncePerSession: Flag that indicates that this layer window will be
 *                       only once per browser session. If cookies are disabled
 *                       the layer window won't be opened.
 *
 * @param  object  props  Properties of layer window
 */
function openLayerWindow(props) {
	if (typeof props == 'object' && props.url && document.body && document.createElement) {
		// Read attribute from object 'props'.
		var url = props.url;
		var id = props.id;
		var width = parseInt(props.width);
		var height = parseInt(props.height);
		var left = parseInt(props.left);
		var top = parseInt(props.top);
		var textClose = props.textClose;
		var className = props.className;
		var scrollable = !!props.scrollable;
		var onlyOncePerSession = !!props.onlyOncePerSession;

		// Normalize attributes.
		if (typeof id != 'string') {
			id = '';
		} // end: if

		if (typeof textClose != 'string') {
			textClose = '';
		} // end: if

		if (isNaN(width) || width <= 0) {
			width = 400;
		} // end: if

		if (isNaN(height) || height <= 0) {
			height = 300;
		} // end: if

		if (isNaN(left) || left < 0) {
			left = 40;
		} // end: if

		if (isNaN(top) || top < 0) {
			top = 30;
		} // end: if

		if (typeof className != 'string') {
			className = 'layerWindow';
		} // end: if

		// Check whether layer window shall really been shown depending
		// on cookies.
		var showWindow = true;

		if (onlyOncePerSession) {
			if (!navigator.cookieEnabled) {
				showWindow = false;
			} else {
				var cookieName = 'layerWindowHasAlreadyBeenOpened';

				if (id !== '') {
					cookieName += '_' + id;
				} // end: if

				if (document.cookie.indexOf(cookieName + '=true') >= 0) {
					showWindow = false;
				} // end: if
			} // end: if
		} // end: if

		if (showWindow) {
			if (onlyOncePerSession) {
				document.cookie = cookieName + '=true';
			} // end: if

			// Create necessary DOM elements and build layer window.
			var container = document.createElement('div');
			container.style.display = 'none';
			container.id = id;
			container.className = className;
			container.style.position = 'absolute';
			container.style.left = left + 'px';
			container.style.top = top + 'px';

			var pane = document.createElement('div');
			pane.className = className + '_pane';
			container.appendChild(pane);

			var content = document.createElement('div');
			content.className = className + '_content';
			pane.appendChild(content);

			var header = document.createElement('div');
			header.className = className + '_header';
			content.appendChild(header);

			var closeLink = document.createElement('a');
			closeLink.href = '#';
			closeLink.className = className + '_closeLink';
			closeLink.innerHTML = textClose;
			closeLink.style.display = 'block';
			header.appendChild(closeLink);

			closeLink.onclick = function() {
				document.body.removeChild(container);
			} // end: if

			var iframe = document.createElement('iframe');
			iframe.src = url;
			iframe.className = className + '_iframe';
			iframe.frameBorder = '0';
			iframe.marginWidth = '0';
			iframe.marginHeight = '0';
			iframe.style.border = 'none';
			iframe.style.width = width + 'px';
			iframe.style.height = height + 'px';
			iframe.scrolling = (scrollable ? 'yes' : 'no');

			// Show layer window as soon as iframe has loaded.
			iframe.onload = iframe.onreadystatechange = function() {
				if (!iframe.readyState || iframe.readyState == 'complete') {
					container.style.display = 'block';
				} // end: if
			} // end: if

			content.appendChild(iframe);

			// Append layer window delayed to body to prevent freezing.
			setTimeout(function() {
				document.body.appendChild(container);
			}, 0);
		} // end: if
	} // end: if
} // end: function openLayerWindow

/**
 * Add Javascript behavior for collabsable containers (containing header and
 * content DOM element - where content element will be shown or hidden).
 *
 * Argument 'props' is an property object with the following props:
 *   - selectorContainer: jQuery selector for the container box
 *   - selectorHeader: jQuery selector for the header element within the container box
 *   - selectorContent: jQuery selector for the content element within the container box
 *   - classForOpenState: CSS class for the container box if expanded
 *   - classForClosedState: CSS class for the container box if collapsed
 */
function automatizeBoxToggling(props) {
	var $ = jQuery;

	$(function() {
		// Read css selectors for involved DOM elements from argument 'props'.
		var selectorContainer = $.trim(props.selectorContainer);
		var selectorHeader = $.trim(props.selectorHeader);
		var selectorContent = $.trim(props.selectorContent);

		// Read classes for open and close state of container DOM element.
		var classForOpenState = $.trim(props.classForOpenState);
		var classForClosedState = $.trim(props.classForClosedState);

		if (selectorContainer !== '' && selectorHeader !== '' && selectorContent !== '') {
			var containers = $(selectorContainer);

			// Finds out whether a container is collapsed or expanded, sets
			// display style properly and updates CSS class names.
			// If second argument 'toggle' is true then the visibility of the
			// container will be toggled.
			function updateContainer(container, toggle) {
				var content = container.find(selectorContent);
				var hide = (content.css('display') == 'none'
						|| container.hasClass(classForClosedState));

				if (toggle) {
					hide = !hide;
				} // end: if

				if (hide) {
					content.slideUp();
					container.removeClass(classForOpenState);
					container.addClass(classForClosedState);
				} else {
					content.slideDown();
					container.removeClass(classForClosedState);
					container.addClass(classForOpenState);
				} // end: if
			} // end: local function updateContainer

			// Updated container content visibility and add Javascript
			// event handlers for box toggling.
			containers.each(function(index, elem) {
				var container = $(elem);
				var header = container.find(selectorHeader);
				var content = container.find(selectorContent);
				updateContainer(container);
				header.click(function() {updateContainer(container, true)});
			});
		} // end: if
	});
} // end function: automatizeBoxToggling

// --- Direct logic  -----------------------------------------------------------

// Suppress multiple submits on forms.
// To enable this functionality assign the form CSS class 'singleSubmitForm'
// and make sure that the form is NOT submitted via Javascript's
// form.submit function without event onsubmit being involved.
if (typeof jQuery == 'function') {
	jQuery(function() {
		var $ = jQuery;

		// Callback function of onsubmit event that ensures that form can only
		// be submitted once.
		var doOnSubmit = function() {
			var returnValue = null;

			if ($(this).hasClass('formAlreadySubmitted')) {
				returnValue = false;
			} else {
				$(this).addClass('formAlreadySubmitted');
			} // end: if

			return returnValue;
		} // end: local function doOnSubmit

    	$('form.singleSubmitForm').submit(doOnSubmit);
	});
}

// Make info boxes collapsable for selected brands.
if (window.config && config.brandId == 7) {
	automatizeBoxToggling({
			selectorContainer: '.infobox',
			selectorHeader: 'h1',
			selectorContent: 'p',
			classForOpenState: 'open',
			classForClosedState: 'close'
		});
} // end: if

/**
 * Function to find out the type of the popup window
 * a) if its created normally using 'window.open', close window by using 'window.close'
 * b) if is created by thickbox, close the thickbox iframe.
 */
function closeWindow() {
	if (window.opener) {
		// Close the normal popup window.
		window.close();
	} else if (parent && typeof parent.tb_remove == 'function') {
		// Close the thickbox.
		parent.tb_remove();
	} // end: if

	return true;
} // end function: closeWindow
