if (typeof DEBUG != 'function') {
	function DEBUG(message) {
		try {
			console.log(message);
		}
		catch (e) {}
	}
}



var Forms = function() {
	var _private = {
		/*-----------------------------------------------------------------------------------------
		 * hide all options, i.e. close all all selects
		 */
		hideAllOptions: function() {
			var selects = YAHOO.util.Dom.getElementsByClassName('boxSelect', 'div', 'containerContent');

			for (var i=0; i<selects.length; i++) {
				try {
					var button = YAHOO.util.Dom.getElementBy(function(elem) {
						return YAHOO.util.Dom.hasClass(elem, 'boxSelectButton');
					}, 'div', selects[i]);
					var boxOptions = YAHOO.util.Dom.getElementBy(function(elem) {
						return YAHOO.util.Dom.hasClass(elem, 'boxSelectOptions');
					}, 'div', selects[i]);
					var options = YAHOO.util.Dom.getElementsBy(function(elem) {
						return true;
					}, 'li', boxOptions);
					var border = YAHOO.util.Dom.getElementBy(function(elem) {
						return YAHOO.util.Dom.hasClass(elem, 'boxSelectBorder');
					}, 'div', selects[i]);

					YAHOO.util.Dom.removeClass(selects[i], 'open');
					selects[i].style.overflow = 'hidden';

					for (var j = 0; j < options.length; j++) {
						if (YAHOO.util.Dom.hasClass(options[j], 'liSelected')) {
							boxOptions.style.top = '-' + (j * 16) + 'px';
							break;
						}
					}
					button.style.backgroundPosition = '0 0';
					border.style.display = 'block';
				}
				catch (e) {
					// ignore misstructured selects
				}
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * add handlers to stylable replacement for <select> tag
		 *
		 * params:
		 *   select: reference to a <div> tag containing the structure to replace a <select> tag
		 */
		setSelectHandlers: function(select) {
			var button = YAHOO.util.Dom.getElementBy(function(elem) {
				return YAHOO.util.Dom.hasClass(elem, 'boxSelectButton');
			}, 'div', select);
			var boxOptions = YAHOO.util.Dom.getElementBy(function(elem) {
				return YAHOO.util.Dom.hasClass(elem, 'boxSelectOptions');
			}, 'div', select);
			var options = YAHOO.util.Dom.getElementsBy(function(elem) {
				return true;
			}, 'li', boxOptions);
			var border = YAHOO.util.Dom.getElementBy(function(elem) {
				return YAHOO.util.Dom.hasClass(elem, 'boxSelectBorder');
			}, 'div', select);

			// handle button click
			YAHOO.util.Event.addListener(button, 'click', function() {
				// call hideAllOptions() in any case, but evaluate the current state first
				if (select.style.overflow == 'visible') {
					_private.hideAllOptions();
				}
				else {
					_private.hideAllOptions();
					YAHOO.util.Dom.addClass(select, 'open');
					select.style.overflow = 'visible';
					boxOptions.style.top = '0';
					button.style.backgroundPosition = '0 100%';
					border.style.display = 'none';
				}
			});
			// handle option clicks
			YAHOO.util.Event.addListener(options, 'click', function() {
				YAHOO.util.Dom.removeClass(options, 'liSelected');
				YAHOO.util.Dom.addClass(this, 'liSelected');
				YAHOO.util.Dom.getElementBy(function(elem) {
					return true;
				}, 'input', select).value = YAHOO.util.Dom.getAttribute(this, 'id').replace(/^[^_]*_/, '').replace(/_/g, ' ');
				_private.hideAllOptions();
			});
			// handle "border" click
			YAHOO.util.Event.addListener(border, 'click', function() {
				// border div shows up if and only if select div is closed
				_private.hideAllOptions();
				YAHOO.util.Dom.addClass(select, 'open');
				select.style.overflow = 'visible';
				boxOptions.style.top = '0';
				button.style.backgroundPosition = '0 100%';
				border.style.display = 'none';
			});
		},
		/*-----------------------------------------------------------------------------------------
		 * set initial value of stylable replacement for <select> tag by getting the first option
		 * with class name "liSelected" or - if there is none - by getting the first option
		 *
		 * params:
		 *   select: reference to a <div> tag containing the structure to replace a <select> tag
		 */
		setSelectInitialValue: function(select) {
			var boxOptions = YAHOO.util.Dom.getElementBy(function(elem) {
				return YAHOO.util.Dom.hasClass(elem, 'boxSelectOptions');
			}, 'div', select);
			var options = YAHOO.util.Dom.getElementsBy(function(elem) {
				return true;
			}, 'li', boxOptions);

			if (   YAHOO.util.Dom.getElementsByClassName('liSelected', 'li', boxOptions).length == 0
			    && options.length > 0) {
				var value = YAHOO.util.Dom.getElementBy(function(elem) {
					return true;
				}, 'input', select).value;

				if (value) {
					// search the "selected" option and mark it as selected
					value = value.replace(/\ /g, '_');

					for (var i=0; i<options.length; i++) {
						if (YAHOO.util.Dom.getAttribute(options[i], 'id').replace(/^[^_]*_/, '') == value) {
							YAHOO.util.Dom.addClass(options[i], 'liSelected');
							boxOptions.style.top = '-' + (i * 16) + 'px';
							break;
						}
					}
				}
				else {
					// use the value of the first option
					YAHOO.util.Dom.addClass(options[0], 'liSelected');
					YAHOO.util.Dom.getElementBy(function(elem) {
						return true;
					}, 'input', select).value = YAHOO.util.Dom.getAttribute(options[0], 'id').replace(/^[^_]*_/, '').replace(/_/g, ' ');
				}
			}
			else if (option.length > 0) {
				// use the value of the first option marked as selected and reset all other options
				var foundSelection = false;

				for (var i=0; i<options.length; i++) {
					if (foundSelection) {
						YAHOO.util.Dom.removeClass(options[i], 'liSelected');
					}
					else if (YAHOO.util.Dom.hasClass(options[i], 'liSelected')) {
						foundSelection = $true;
						YAHOO.util.Dom.getElementBy(function(elem) {
							return true;
						}, 'input', select).value = YAHOO.util.Dom.getAttribute(options[i], 'id').replace(/[^_]*_/, '').replace(/_/g, ' ');
					}
				}
			}
		}
	};
	var _public = {
		/*-----------------------------------------------------------------------------------------
		 * render labels over input fields
		 */
		initOverLabels: function() {
			var labels;
			var id;
			var field;

			// set focus and blur handlers to hide and show labels with class name "overlabel"
			labels = document.getElementsByTagName('label');

			for (var i=0; i<labels.length; i++) {
				if (/\boverLabel\b/.test(labels[i].className)) {
					// skip labels that do not have a named association with another field
					id = labels[i].htmlFor || labels[i].getAttribute('for');
					if (!id || !(field = document.getElementById(id))) {
						continue;
					}
					// change the applied class to hover the label over the form field
					labels[i].className = labels[i].className.replace(/\boverLabel\b/g, 'overLabelApply');
					_public.toggleLabelDisplay(id, false);

					// hide any fields having an initial value
					if (field.value !== '') {
						_public.toggleLabelDisplay(field.getAttribute('id'), true);
					}
					// set handlers to show and hide labels
					field.onfocus = function () {
						_public.toggleLabelDisplay(this.getAttribute('id'), true);
					};
					field.onblur = function () {
						if (this.value === '') {
							_public.toggleLabelDisplay(this.getAttribute('id'), false);
						}
					};
					// handle clicks to label elements (for Safari)
					labels[i].onclick = function () {
						var id, field;
						id = this.getAttribute('for');
						if (id && (field = document.getElementById(id))) {
							field.focus();
						}
					};
				}
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * initialize stylable replacements for <select> tags
		 */
		initSelects: function() {
			var selects = YAHOO.util.Dom.getElementsByClassName('boxSelect', 'div', 'containerContent');
			var inputs = YAHOO.util.Dom.getElementsBy(function(elem) {
				return true;
			}, 'input'); // get all input fields (including login and search)

			for (var i=0; i<selects.length; i++) {
				try {
					var boxOptions = YAHOO.util.Dom.getElementBy(function(elem) {
						return YAHOO.util.Dom.hasClass(elem, 'boxSelectOptions');
					}, 'div', selects[i]);
					var options = YAHOO.util.Dom.getElementsBy(function(elem) {
						return true;
					}, 'li', boxOptions);

					boxOptions.style.height = '' + (options.length * 16 - 2) + 'px';
					_private.setSelectInitialValue(selects[i]);
					_private.setSelectHandlers(selects[i]);
				} 
				catch (e) {
					// ignore misstructured selects
				}
			}
			YAHOO.util.Event.addListener(inputs, 'click', function() {
				_private.hideAllOptions();
			});
		},
		/*-----------------------------------------------------------------------------------------
		 * reset form and rerender labels
		 *
		 * params:
		 *   form: reference or ID of the form to reset
		 */
		resetForm: function(form) {
			var labels;
			var id;
			var field;

			if (!form) {
				return;
			}
			labels = YAHOO.util.Dom.getElementsByClassName('overLabelApply', 'label', form);

			for (var i=0; i<labels.length; i++) {
				if (!(id = labels[i].htmlFor || labels[i].getAttribute('for'))) {
					continue;
				}
				if (id && (field = document.getElementById(id))) {
					field.value = '';
					_public.toggleLabelDisplay(id, false);
				}
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * toggle display of label
		 *
		 * params:
		 *   fieldID: ID of the corresponding form element
		 *   hide:    hide the label if this is set to true, show the label otherwise
		 */
		toggleLabelDisplay: function(fieldID, hide) {
			var field = document.getElementById(fieldID);

			if (!field) {
				return false;
			}
			if (hide) {
				//field.style.backgroundColor = '#ffffff';
				field.style.opacity = '1';
				field.style.filter = 'alpha(opacity:100)';
			}
			else {
				//field.style.backgroundColor = 'transparent';
				field.style.opacity = '0';
				field.style.filter = 'alpha(opacity:0)';
			}
			return true;
		}
	};
	return _public;
}();

YAHOO.util.Event.onDOMReady(function() {
	window.setTimeout(Forms.initOverLabels, 50);
	window.setTimeout(Forms.initSelects, 50);
});
if (typeof DEBUG != 'function') {
	function DEBUG(message) {
		try {
			console.log(message);
		}
		catch (e) {}
	}
}



var Basket = function() {
	var _private = {
		basketLight: null,
		cookie: PBEURL('').replace(/\?/, ''),
		xhrCount: 0,
		listenOnChange: function() {
			var count = document.getElementById('inputCount' + this.code).value;

			count = count.replace(/^\s*/, '');
			count = count.replace(/\s*$/, '');

			if (count == parseInt(count).toString() && parseInt(count) > 0) {
				Content.loadBasket('a-cFrontend_ShopBasketDetail-n_ChangeCount=' + count + '&a-cFrontend_ShopBasketDetail-sz_ERPCodeDel=' + this.code + '&button-cFrontend_ShopBasketDetail-changeBasket=');
			}
			else {
				Content.loadBasket();
			}
		},
		listenOnChangeFast: function() {
			var count = document.getElementById('inputCount' + this.code).value;

			count = count.replace(/^\s*/, '');
			count = count.replace(/\s*$/, '');

			if (count == parseInt(count).toString() && parseInt(count) > 0) {
				Content.loadBasketFast('a-cFrontend_ShopBasketDetail-n_ChangeCount=' + count + '&a-cFrontend_ShopBasketDetail-sz_ERPCodeDel=' + this.code + '&button-cFrontend_ShopBasketDetail-changeBasket=');
			}
			else {
				Content.loadBasketFast(_private.cookie);
			}
		},
		listenOnDelete: function() {
			Content.loadBasket('a-cFrontend_ShopBasketDetail-sz_ERPCodeDel=' + this.code + '&a-cFrontend_ShopBasketDetail-delFromBasket=x&button-cFrontend_ShopBasketDetail-changeBasket=');
		},
		listenOnDeleteFast: function() {
			Content.loadBasketFast('a-cFrontend_ShopBasketDetail-sz_ERPCodeDel=' + this.code + '&a-cFrontend_ShopBasketDetail-delFromBasket=x&button-cFrontend_ShopBasketDetail-changeBasket=');
		},
		listenOnShow: function() {
			Shop.showItemDetailBasket(this.code);
		},
		listenOnShowFast: function() {
			Shop.showItemDetailBasketFast(this.code);
		}
	};

	var _public = {
		getBasketLight: function() {
			if (!_private.basketLight) {
				_public.initBasketLight();
			}
			return _private.basketLight;
		},
		initBasketLight: function() {
			_private.basketLight = new YAHOO.widget.Module('basketLight', {
				visible: true
			});
			_private.basketLight.setHeader('');
			_private.basketLight.setBody('');
			_private.basketLight.render('boxBasketLight');
		},
		loadBasketLight: function() {
			var callback = {
				success: function(o) {
					if (!_private.basketLight) {
						_public.initBasketLight();
					}
					_private.basketLight.setBody(o.responseText);
					_private.basketLight.render('boxBasketLight');
					YAHOO.util.Event.removeListener(document.getElementById('boxBasketLight'));
					YAHOO.util.Event.addListener(document.getElementById('boxBasketLight'), 'click', Content.loadBasket);
					YAHOO.util.Event.removeListener(document.getElementById('aBasketLight'));
					YAHOO.util.Event.addListener(document.getElementById('aBasketLight'), 'click', Content.loadBasket);
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('loading basket light timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasketLight.html?button-oFrontend_ShopBasketLight-fillBasketLight=x&xhr=basket' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasketLight.html?button-oFrontend_ShopBasketLight-fillBasketLight=x&xhr=basket' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
		},
		modifyChangeLinks: function() {
			var links = YAHOO.util.Dom.getElementsByClassName('aChangeBasket', 'a', 'containerBasket');
			var code;

			YAHOO.util.Event.removeListener(links);

			for (var i=0; i<links.length; i++) {
				code  = links[i].getAttribute('id').replace(/aChangeBasket/, '');
				YAHOO.util.Event.addListener(links[i], 'click', _private.listenOnChange, {
					code: code
				}, true);
			}
		},
		modifyChangeLinksFast: function() {
			var links = YAHOO.util.Dom.getElementsByClassName('aChangeBasket', 'a', 'containerBasket');
			var code;

			YAHOO.util.Event.removeListener(links);

			for (var i=0; i<links.length; i++) {
				code  = links[i].getAttribute('id').replace(/aChangeBasket/, '');
				YAHOO.util.Event.addListener(links[i], 'click', _private.listenOnChangeFast, {
					code: code
				}, true);
			}
		},
		modifyDeleteLinks: function() {
			var links = YAHOO.util.Dom.getElementsByClassName('aDeleteBasket', 'a', 'containerBasket');
			var code;

			YAHOO.util.Event.removeListener(links);

			for (var i=0; i<links.length; i++) {
				code = links[i].getAttribute('id').replace(/aDeleteBasket/, '');
				YAHOO.util.Event.addListener(links[i], 'click', _private.listenOnDelete, {
					code: code
				}, true);
			}
		},
		modifyDeleteLinksFast: function() {
			var links = YAHOO.util.Dom.getElementsByClassName('aDeleteBasket', 'a', 'containerBasket');
			var code;

			YAHOO.util.Event.removeListener(links);

			for (var i=0; i<links.length; i++) {
				code = links[i].getAttribute('id').replace(/aDeleteBasket/, '');
				YAHOO.util.Event.addListener(links[i], 'click', _private.listenOnDeleteFast, {
					code: code
				}, true);
			}
		},
		modifyPagingLinks: function() {
			var shopLink = document.getElementById('aBackToShop');
			var orderLink = document.getElementById('aGoToOrder');

			YAHOO.util.Event.removeListener(shopLink);
			YAHOO.util.Event.addListener(shopLink, 'click', function() {
				if (Shop.getNodeId() >= 0) {
					Content.loadShop(Shop.getNodeId());
				}
				else if (Shop.getNodeId() == -1) {
					Content.loadShopFast();
				}
				else {
					window.location = '/bestellen';
				}
			});
			YAHOO.util.Event.removeListener(orderLink);
			YAHOO.util.Event.addListener(orderLink, 'click', function() {
				yuiLoader.show();
				Content.loadOrder();
			});
		},
		modifyPagingLinksFast: function() {
			var fastOrderLinks = YAHOO.util.Dom.getElementsByClassName('aBackToFastOrder', 'a', 'containerContent');
			var shopLink = document.getElementById('aBackToShop');
			var orderLink = document.getElementById('aGoToOrder');

			YAHOO.util.Event.removeListener(fastOrderLinks);

			for (var i=0; i<fastOrderLinks.length; i++) {
				YAHOO.util.Event.addListener(fastOrderLinks[i], 'click', function() {
					Content.loadShopFast();
				});
			}
			YAHOO.util.Event.removeListener(shopLink);
			YAHOO.util.Event.addListener(shopLink, 'click', function() {
				/*
				if (Shop.getNodeId() >= 0) {
					Content.loadShop(Shop.getNodeId());
				}
				else if (Shop.getNodeId() == -1) {
					Content.loadShopFast();
				}
				else {
					window.location = '/bestellen';
				}
				*/
				Content.loadShopFast();
			});
			YAHOO.util.Event.removeListener(orderLink);
			YAHOO.util.Event.addListener(orderLink, 'click', function() {
				yuiLoader.show();
				Content.loadOrderFast();
			});
		},
		modifyShowLinks: function() {
			var links = YAHOO.util.Dom.getElementsByClassName('aShowItem', 'a', 'containerBasket');
			var code;

			YAHOO.util.Event.removeListener(links);

			for (var i=0; i<links.length; i++) {
				code = links[i].innerHTML;
				YAHOO.util.Event.addListener(links[i], 'click', _private.listenOnShow, {
					code: code
				}, true);
			}
		},
		modifyShowLinksFast: function() {
			var links = YAHOO.util.Dom.getElementsByClassName('aShowItem', 'a', 'containerBasket');
			var code;

			YAHOO.util.Event.removeListener(links);

			for (var i=0; i<links.length; i++) {
				code = links[i].innerHTML;
				YAHOO.util.Event.addListener(links[i], 'click', _private.listenOnShowFast, {
					code: code
				}, true);
			}
		}
	};
	return _public;
}();



var Order = function() {
	var _private = {
		cookie: PBEURL('').replace(/\?/, '')
	};

	var _public = {
		modifyAddressLinks: function() {
			var addressLink = document.getElementById('aChangeAddress');
			var delAddressLink = document.getElementById('aChangeDelAddress');

			YAHOO.util.Event.removeListener(addressLink);
			YAHOO.util.Event.removeListener(delAddressLink);
			YAHOO.util.Event.addListener(addressLink, 'click', Content.loadProfile);
			YAHOO.util.Event.addListener(delAddressLink, 'click', Content.loadProfile);
		},
		modifyPagingLinks: function() {
			var basketLinks = YAHOO.util.Dom.getElementsByClassName('aBackToBasket', 'a', 'containerContent');
			var basketLink = document.getElementById('aBackToBasket');
			var replyLink = document.getElementById('aGoToReply');

			YAHOO.util.Event.removeListener(basketLinks);

			for (var i=0; i<basketLinks.length; i++) {
				YAHOO.util.Event.addListener(basketLinks[i], 'click', function() {
					Content.loadBasket();
				});
			}
			YAHOO.util.Event.removeListener(basketLink);
			YAHOO.util.Event.addListener(basketLink, 'click', function() {
				Content.loadBasket();
			});
			YAHOO.util.Event.removeListener(replyLink);
			YAHOO.util.Event.addListener(replyLink, 'click', function() {
				var orderName = document.getElementById('textareaOrderName').value;
				var orderComment = document.getElementById('textareaOrderComment').value;
				var getParams = 'a-cFrontend_ShopBasketDetail-sz_OrderName=' + orderName + '&a-cFrontend_ShopBasketDetail-sz_OrderComment=' + orderComment + '&button-cFrontend_ShopBasketDetail-orderItems=x&' + _private.cookie;

				YAHOO.util.Event.removeListener(replyLink);
				document.getElementById('formOrder').setAttribute('action', '/_shop/getReply.html?' + getParams);
				document.forms['cFrontend_ShopBasketDetail'].submit();
			});
		},
		modifyPagingLinksFast: function() {
			var basketLinks = YAHOO.util.Dom.getElementsByClassName('aBackToBasket', 'a', 'containerContent');
			var basketLink = document.getElementById('aBackToBasket');
			var replyLink = document.getElementById('aGoToReply');

			YAHOO.util.Event.removeListener(basketLinks);

			for (var i=0; i<basketLinks.length; i++) {
				YAHOO.util.Event.addListener(basketLinks[i], 'click', function() {
					Content.loadBasketFast();
				});
			}
			YAHOO.util.Event.removeListener(basketLink);
			YAHOO.util.Event.addListener(basketLink, 'click', function() {
				Content.loadBasketFast();
			});
			YAHOO.util.Event.removeListener(replyLink);
			YAHOO.util.Event.addListener(replyLink, 'click', function() {
				var orderName = document.getElementById('textareaOrderName').value;
				var orderComment = document.getElementById('textareaOrderComment').value;
				var getParams = 'a-cFrontend_ShopBasketDetail-sz_OrderName=' + orderName + '&a-cFrontend_ShopBasketDetail-sz_OrderComment=' + orderComment + '&button-cFrontend_ShopBasketDetail-orderItems=x&' + _private.cookie;

				YAHOO.util.Event.removeListener(replyLink);
				document.getElementById('formOrder').setAttribute('action', '/_shop/getReply.html?' + getParams);
				document.forms['cFrontend_ShopBasketDetail'].submit();
			});
		}
	};
	return _public;
}();



var Reply = function() {
	var _public = {
		modifyPrintLink: function() {
			var link = document.getElementById('aPrintOrder');
			
			YAHOO.util.Event.removeListener(link);
			YAHOO.util.Event.addListener(link, 'click', function() {
				window.print();
			});
		}
	};
	return _public;
}();
if (typeof DEBUG != 'function') {
	function DEBUG(message) {
		try {
			console.log(message);
		}
		catch (e) {}
	}
}



// initialize the temporary panel to display while waiting for external content to load
var yuiLoader = {
	hide: function() {},
	show: function() {}
};

YAHOO.util.Event.onContentReady('containerViani', function() {
	yuiLoader = new YAHOO.widget.Panel('boxYuiLoader', {
		autofillheight: 'body',
		constraintoviewport: true,
		fixedcenter: true,
		close: false,
		draggable: false,
		zindex: 100,
		modal: false,
		visible: false
	});
	yuiLoader.setBody('<img src="/_images/loading.gif"/>');
	yuiLoader.render(YAHOO.util.Dom.get('containerViani'));
});

// render textareas (order name, comment) of order form
YAHOO.util.Event.onContentReady('containerOrder', Forms.initOverLabels);



/**
 * \brief Replace the content in the main region with new content.
 */
var Content = function() {
	// private functions ==========================================================================
	var _private = {
		cookie: PBEURL('').replace(/\?/, ''),
		shopUrl: 'http://www1.viani.de',
		media: null,
		xhrCount: 0,
		addContent: function(contentNew) {
			content = document.getElementById('containerContentInner');

			if (typeof(contentNew) == 'object') {
				content.appendChild(contentNew);
			}
			else {
				content.innerHTML += contentNew;
			}
		},
		addPaging: function(paging) {
			content = document.getElementById('containerContentInner');

			if (!paging) {
				return;
			}
			if (typeof(paging) == 'object') {
				paging = paging.innerHTML;
			}
			content.innerHTML = paging + content.innerHTML + paging;
		},
		createChild: function(parentNode, tagName, className) {
			var child = document.createElement(tagName);

			if (className) {
				child.className = className;
			}
			if (parentNode) {
				parentNode.appendChild(child);
			}
			return child;
		},
		getCurrentFontSize: function() { /* ??? */
			var box = document.getElementById('fontSizeDetector');

			if (!box) {
				box = document.createElement('div');

				box.setAttribute('id', 'fontSizeDetector');
				box.style.position = 'absolute';
				box.style.top = '-100em';
				box.style.width = '100em';
				box.style.height = '1em';
				box.style.lineHeight = '1em';
				box.style.margin = '0';
				box.style.padding = '0';
				box.style.border = 'none';

				YAHOO.util.Dom.getLastChildBy(document.body, _private.isDiv).appendChild(box);
			}
			return box.offsetWidth / 100;
		},
		isDiv: function(elem) {
			return elem.tagName == 'div' || elem.tagName == 'DIV';
		},
		pagingBasket: function() {
			//console.log('click');
			_public.loadBasket(this.getParams);
		},
		pagingOrder: function() {
			_public.loadOrder(this.getParams);
		},
		removeContent: function() {
			var content = document.getElementById('containerContentInner');
			var parent;
			
			if (!content) {
				return;
			}
			parent = content.parentNode;
			parent.removeChild(content);
			content = document.createElement('div');
			content.className = 'containerLeftInner';
			content.setAttribute('id', 'containerContentInner');
			parent.appendChild(content);
		},
		/*-----------------------------------------------------------------------------------------
		 * remove class .selected from menu links starting at level 3 (and remove suffix
		 * ' (# Produkte)' from current commodity group in shop view)
		 */
		removeSelectedLinks: function() {
			var level = 3;
			var boxNaviLevel;
			var links;
			var index;

			while ((boxNaviLevel = document.getElementById('boxNaviLevel' + level))) {
				links = YAHOO.util.Dom.getElementsByClassName('selected', 'a', boxNaviLevel);

				for (var i=0; i<links.length; i++) {
					YAHOO.util.Dom.removeClass(links[i], 'selected');
	
					if ((links[i].innerHTML.lastIndexOf(' Produkte)')) >= 0) {
						index = links[i].innerHTML.lastIndexOf(' (');
						links[i].innerHTML = links[i].innerHTML.substring(0, index);
					}
				}
				level++;
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * mark currently selected item of personal navigation (and unmark other items)
		 *
		 * params:
		 *   id: HTML ID of the item selected (if not defined, all items will be unmarked)
		 */
		setPersNaviSelected: function(id) {
			var links = YAHOO.util.Dom.getElementsBy(function(elem) {
				return true;
			}, 'a', 'boxPersNavi');
			var link;

			for (var i=0; i<links.length; i++) {
				YAHOO.util.Dom.removeClass(links[i], 'selected');
			}
			if (id && (link = document.getElementById(id))) {
				YAHOO.util.Dom.addClass(link, 'selected');
			}
		}
	};
	
	// public functions ===========================================================================
	var _public = {
		loadBasket: function(getParams) {
			var code = this.code;
			var callback = {
				success: function(o) {
					_private.removeSelectedLinks();
					_public.replaceContent(o.responseText.replace(/\$NULL/g, ''));
					Basket.modifyShowLinks();
					Basket.modifyChangeLinks();
					Basket.modifyDeleteLinks();
					Basket.modifyPagingLinks();
					Basket.loadBasketLight();
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting basket timed out - retrying');

						if (typeof(getParams) == 'string') {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasket.html?a-oFrontend_FastOrderIndex-code=' + code + '&' + getParams + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
						else {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasket.html?button-cFrontend_ShopBasketDetail-fillBasketDetail=x&a-oFrontend_FastOrderIndex-code=' + code + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();

			if (typeof(getParams) == 'string') {
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasket.html?a-oFrontend_FastOrderIndex-code=' + code + '&' + getParams + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
			else {
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasket.html?button-cFrontend_ShopBasketDetail-fillBasketDetail=x&a-oFrontend_FastOrderIndex-code=' + code + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
			_private.setPersNaviSelected();
		},
		loadBasketFast: function(getParams) {
			var code = this.code ? this.code : '';
			var callback = {
				success: function(o) {
					_private.removeSelectedLinks();
					_public.replaceContent(o.responseText.replace(/\$NULL/g, ''));
					Basket.modifyShowLinksFast();
					Basket.modifyChangeLinksFast();
					Basket.modifyDeleteLinksFast();
					Basket.modifyPagingLinksFast();
					Basket.loadBasketLight();
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting basket timed out - retrying');
						
						if (typeof(getParams) == 'string') {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasketFast.html?a-oFrontend_FastOrderIndex-code=' + code + '&' + getParams + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
						else {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasketFast.html?button-cFrontend_ShopBasketDetail-fillBasketDetail=x&a-oFrontend_FastOrderIndex-code=' + code + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();

			if (typeof(getParams) == 'string') {
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasketFast.html?a-oFrontend_FastOrderIndex-code=' + code + '&' + getParams + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
			else {
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/getBasketFast.html?button-cFrontend_ShopBasketDetail-fillBasketDetail=x&a-oFrontend_FastOrderIndex-code=' + code + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
			_private.setPersNaviSelected();
		},
		loadFavorites: function() {
			var callback = {
				success: function(o) {
					_private.removeSelectedLinks();
					_public.replaceContent(o.responseText);
					YAHOO.util.Event.onContentReady('containerFavorites', Shop.showFavorites);
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting favorites timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/getFavorites.html?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/getFavorites.html?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			_private.setPersNaviSelected('aPersNaviFavorites');
		},
		loadNewsletter: function() {
			
			_private.setPersNaviSelected('aPersNaviNewsletter');
		},
		loadOrder: function(getParams) {
			var callback = {
				success: function(o) {
					_public.replaceContent(o.responseText.replace(/\$NULL/g, ''));
					Order.modifyAddressLinks();
					Order.modifyPagingLinks();
					Shop.preOrderAddListeners();

					try {
						Forms.initOverLabels();
					}
					catch (e) {}
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting order timed out - retrying');
						
						if (typeof(getParams) == 'string') {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrder.html?button-tFrontend_ShopOrderAddress-findAddress=x&' + getParams + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
						else {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrder.html?button-tFrontend_ShopOrderAddress-findAddress=&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();

			if (typeof(getParams) == 'string') {
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrder.html?button-tFrontend_ShopOrderAddress-findAddress=x&' + getParams + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
			else {
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrder.html?button-tFrontend_ShopOrderAddress-findAddress=&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
		},
		loadOrderFast: function(getParams) {
			var callback = {
				success: function(o) {
					_public.replaceContent(o.responseText.replace(/\$NULL/g, ''));
					Order.modifyAddressLinks();
					Order.modifyPagingLinksFast();
					Shop.preOrderAddListeners();

					try {
						Forms.initOverLabels();
					}
					catch (e) {}
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting order timed out - retrying');

						if (typeof(getParams) == 'string') {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrderFast.html?button-tFrontend_ShopOrderAddress-findAddress=&' + getParams + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
						else {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrderFast.html?button-tFrontend_ShopOrderAddress-findAddress=&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();

			if (typeof(getParams) == 'string') {
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrderFast.html?button-tFrontend_ShopOrderAddress-findAddress=&' + getParams + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
			else {
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrderFast.html?button-tFrontend_ShopOrderAddress-findAddress=&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
		},
		loadOrders: function() {
			var data;
			var callbackJSON = {
				success: function(o) {
					try {
						data = YAHOO.lang.JSON.parse(o.responseText);
					}
					catch (e) {
						DEBUG('failed to parse JSON file containing data of previous orders: ' + e.message);
						yuiLoader.hide();
						return;
					}
					YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrders.html?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callbackPage, null);
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting list of former orders timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/shopHistory.json?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callbackJSON, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}
			var callbackPage = {
				success: function(o) {
					_private.removeSelectedLinks();
					_public.replaceContent(o.responseText);
					Orders.displayOrders(data);
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting container page for list of former orders timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrders.html?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callbackPage, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_json/shopHistory.json?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callbackJSON, null);
			_private.setPersNaviSelected('aPersNaviOrders');
		},
		loadOrdersDetail: function(orderID) {
			var callback = {
				success: function(o) {
					//_private.removeSelectedLinks();
					_public.replaceContent(o.responseText);
					Orders.configureDetailPaging(orderID);
					Orders.modifyItemDetailLinks();
					Orders.modifyBasketDetailLinks();
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting details for order #' + orderID + ' timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrdersDetail.html?order_id=' + orderID + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			if (typeof orderID == 'undefined') {
				orderID = Orders.getLastViewedOrderID();
			}
			Orders.setLastViewedOrderID(parseInt(orderID));
			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/getOrdersDetail.html?order_id=' + orderID + '&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			//_private.setPersNaviSelected('aPersNaviOrders');
		},
		loadSearchResults: function(results) {
			var callback = {
				success: function(o) {
					_public.replaceContent(o.responseText);
					Shop.displaySearchResults();
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting shop timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/getShop.html?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/getShop.html?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			_private.setPersNaviSelected();
		},
		loadShop: function(nodeId) {
			var callback = {
				success: function(o) {
					_public.replaceContent(o.responseText);
					Shop.initShop(nodeId);
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting shop timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/getShop.html?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/getShop.html?xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			_private.setPersNaviSelected();
		},
		loadShopFast: function() {
			var callback = {
				success: function(o) {
					_public.replaceContent(o.responseText);
					Shop.fastOrder();
					Forms.initOverLabels();
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting fast order form timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/getShopFast.html?button-cFrontend_ShopBasketDetail-fillBasketDetail=x&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
				},
				timeout: 30000
			}

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/getShopFast.html?button-cFrontend_ShopBasketDetail-fillBasketDetail=x&xhr=content' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			_private.setPersNaviSelected();
		},
		replaceContent: function(contentNew) {
			if (!contentNew) {
				return;
			}
			_private.removeContent();
			_private.addContent(contentNew);
		}
	};
	return _public;
}();
if (typeof DEBUG != 'function') {
	function DEBUG(message) {
		try {
			console.log(message);
		}
		catch (e) {}
	}
}



var Favorites = function() {
	var _private = {
		cookie: PBEURL('').replace(/\?/, ''),
		xhrCount: 0
	};

	var _public = {
		deleteFavorite: function(code) {
			var callback = {
				success: function(o) {
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('deleting favorite timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_Favorite-sz_ERPCode=' + code + '&button-oFrontend_Favorite-deleteFavorite=x&xhr=favorites' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_Favorite-sz_ERPCode=' + code + '&button-oFrontend_Favorite-deleteFavorite=x&xhr=favorites' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
		},
		setFavorite: function(code) {
			var callback = {
				success: function(o) {
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('setting favorite timed out - retrying')
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_Favorite-sz_ERPCode=' + code + '&button-oFrontend_Favorite-setFavorite=x&xhr=favorites' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_Favorite-sz_ERPCode=' + code + '&button-oFrontend_Favorite-setFavorite=x&xhr=favorites' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
		}
	};
	return _public;
}();
if (typeof DEBUG != 'function') {
	function DEBUG(message) {
		try {
			console.log(message);
		}
		catch (e) {}
	}
}



var Images = function() {
	// private properties and functions ===========================================================
	var _private = {
		// properties -----------------------------------------------------------------------------
		media: {
			folder: '/blobs/',
			suffix: '.jpg',
			variantLarge: 4001,
			variantSmall: 4002,
			variantTiny: 4003
		},
		// functions ------------------------------------------------------------------------------
		descHide: function() {
			this.desc.style.display = 'none';
			
			if (this.link) {
				this.link.style.display = 'block';
			}
		},
		descShow: function() {
			this.desc.style.display = 'block';

			if (this.link) {
				this.link.style.display = 'none';
			}
		},
		displayImages: function() {
			var images = YAHOO.util.Dom.getElementsByClassName('boxImage');

			for (var i=0; i<images.length; i++) {
				images[i].style.display = 'block';
			}
		},
		getCurrentFontSize: function() { /* ??? */
			var box = document.getElementById('fontSizeDetector');

			if (!box) {
				box = document.createElement('div');

				box.setAttribute('id', 'fontSizeDetector');
				box.style.position = 'absolute';
				box.style.top = '-100em';
				box.style.width = '100em';
				box.style.height = '1em';
				box.style.lineHeight = '1em';
				box.style.margin = '0';
				box.style.padding = '0';
				box.style.border = 'none';

				document.body.appendChild(box);
			}
			return box.offsetWidth / 100;
		},
		isLink: function(elem) { /* ??? */
			return (elem.tagName == 'a' || elem.tagName == 'A');
		}
	};

	// public functions ===========================================================================
	var _public = {
		getSettings: function() {
			return _private.media;
		},
		initImages: function() {
			var shopBasketLinks = YAHOO.util.Dom.getElementsByClassName('boxShopBasketLink', 'div', 'containerContent');

			_private.displayImages();
			_public.onHoverHideDesc();

			for (var i=0; i<shopBasketLinks.length; i++) {
				shopBasketLinks[i].style.display = 'none';
			}
		},
		onHoverHideDesc: function() {
			var prodBoxes = YAHOO.util.Dom.getElementsByClassName('boxProdTeaser', 'div', 'containerContent');
			var descBoxes = YAHOO.util.Dom.getElementsByClassName('boxProdDesc', 'div', 'containerContent');
			var shopBasketLinks = YAHOO.util.Dom.getElementsByClassName('boxShopBasketLink', 'div', 'containerContent');

			if (prodBoxes.length != descBoxes.length) {
				return;
			}
			YAHOO.util.Event.removeListener(prodBoxes);

			for (var i=0; i<prodBoxes.length; i++) {
				var obj = new Object();

				obj.desc = descBoxes[i];
				obj.link = null;

				if (prodBoxes.length = shopBasketLinks.length) {
					obj.link = shopBasketLinks[i];
				}
				YAHOO.util.Event.addListener(prodBoxes[i], 'mouseover', _private.descHide, obj, true);
				YAHOO.util.Event.addListener(prodBoxes[i], 'mouseout', _private.descShow, obj, true);
			}
		},
		renderImages: function() {
			var images     = new Array();
			var imageSizes = new Array();
			var topOffsets = new Array();

			images[0] = YAHOO.util.Dom.getElementsByClassName('img2Col', 'img', 'containerContent');
			images[1] = YAHOO.util.Dom.getElementsByClassName('img1Col', 'img', 'containerContent');
			images[2] = YAHOO.util.Dom.getElementsByClassName('imgHalfCol', 'img', 'containerContent');

			// set maximum values (measured in em) ...
			if (navigator.userAgent.match(/MSIE/)) {
				// ... for Internet Explorer
				imageSizes[0] = 16.2650; /* 200px */
				topOffsets[0] =  1.4639; /*  18px */
				imageSizes[1] =  8.7831; /* 108px */
				topOffsets[1] =  0;      /*   0px */
				imageSizes[2] =  3.2530; /*  40px */
				topOffsets[2] =  0.3253; /*   4px */
			}
			else {
				// ... for other browsers
				imageSizes[0] = 16.6667; /* 200px */
				topOffsets[0] =  1.5000; /*  18px */
				imageSizes[1] =  9.0000; /* 108px */
				topOffsets[1] =  0;      /*   0px */
				imageSizes[2] =  3.3333; /*  40px */
				topOffsets[2] =  0.3333; /*   4px */
			}
			// set styles
			for (var i=0; i<images.length; i++) {
				for (var j=0; j<images[i].length; j++) {
					var width  = parseInt(YAHOO.util.Dom.getAttribute(images[i][j], 'width'));
					var height = parseInt(YAHOO.util.Dom.getAttribute(images[i][j], 'height'));
					var ratio;
					var top;

					if (navigator.userAgent.match('MSIE') && (i == 0)) {
						/*
						 * IE will return width and height depending on current styles. This is why
						 * upscaling of images will not work using the returned values.
						 */
						width = width * imageSizes[0] / imageSizes[1];
						height = height * imageSizes[0] / imageSizes[1];
					}
					if (width && height) {
						if (width > height) {
							ratio = height / width;
							width = width / 12.0;

							if (width > imageSizes[i]) {
								width = imageSizes[i];
							}
							height = width * ratio;
						}
						else {
							ratio = width / height;
							height = height / 12.0;

							if (height > imageSizes[i]) {
								height = imageSizes[i];
							}
							width = height * ratio;
						}
						top = (imageSizes[i] - height) / 2 + topOffsets[i];

						images[i][j].style.width    = '' + width + 'em';
						images[i][j].style.height   = '' + height + 'em';
						images[i][j].style.position = 'relative';
						images[i][j].style.top      = '' + top + 'em';
					}
				}
			}
		}
	};
	return _public;
}();

YAHOO.util.Event.onDOMReady(Images.initImages);
if (typeof DEBUG != 'function') {
	function DEBUG(message) {
		try {
			console.log(message);
		}
		catch (e) {}
	}
}



var Orders = function() {
	// private properties and functions
	var _private = {
		// properties
		cookie: PBEURL('').replace(/\?/, ''),
		lastViewedOrderID: -1, // ID of the last order viewed
		orders: [],            // order IDs
		xhrCount: 0,
		// functions
		/*-----------------------------------------------------------------------------------------
		 * configure back links, paging links, no. of current page, and maximum page no.
		 */
		configureDetailPaging: function(orderID) {
			var backLinks = YAHOO.util.Dom.getElementsByClassName('aBackToOverview', 'a', 'containerContent');
			var aFirstPages  = YAHOO.util.Dom.getElementsByClassName('aFirstPage', 'a', 'containerContent');
			var aPrevPages   = YAHOO.util.Dom.getElementsByClassName('aPrevPage', 'a', 'containerContent');
			var aNextPages   = YAHOO.util.Dom.getElementsByClassName('aNextPage', 'a', 'containerContent');
			var aLastPages   = YAHOO.util.Dom.getElementsByClassName('aLastPage', 'a', 'containerContent');
			var spanPageNos  = YAHOO.util.Dom.getElementsByClassName('spanPageNo', 'span', 'containerContent');
			var spanPageMaxs = YAHOO.util.Dom.getElementsByClassName('spanPageMax', 'span', 'containerContent');
			var pageNo  = _private.findValueInList(orderID, _private.orders) + 1;
			var pageMax = _private.orders.length;

			// back links
			for (var i=0; i<backLinks.length; i++) {
				YAHOO.util.Event.addListener(backLinks[i], 'click', Content.loadOrders);
			}
			// paging links, no. of current page, and maximum page no.
			for (var i=0; i<aFirstPages.length; i++) {
				// <<
				YAHOO.util.Event.addListener(aFirstPages[i], 'click', function() {
					if (pageNo > 1) {
						Content.loadOrdersDetail(_private.orders[0]);
					}
				});
				// <
				YAHOO.util.Event.addListener(aPrevPages[i], 'click', function() {
					if (pageNo > 1) {
						Content.loadOrdersDetail(_private.orders[pageNo-2]);
					}
				});
				// >
				YAHOO.util.Event.addListener(aNextPages[i], 'click', function() {
					if (pageNo < pageMax) {
						Content.loadOrdersDetail(_private.orders[pageNo]);
					}
				});
				// >>
				YAHOO.util.Event.addListener(aLastPages[i], 'click', function() {
					if (pageNo < pageMax) {
						Content.loadOrdersDetail(_private.orders[pageMax - 1]);
					}
				});
				spanPageNos[i].innerHTML = pageNo;
				spanPageMaxs[i].innerHTML = pageMax;
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * configure paging, so that no more than 10 previous orders are shown at a time
		 */
		configurePaging: function() {
			var aFirstPages  = YAHOO.util.Dom.getElementsByClassName('aFirstPage', 'a', 'containerContent');
			var aPrevPages   = YAHOO.util.Dom.getElementsByClassName('aPrevPage', 'a', 'containerContent');
			var aNextPages   = YAHOO.util.Dom.getElementsByClassName('aNextPage', 'a', 'containerContent');
			var aLastPages   = YAHOO.util.Dom.getElementsByClassName('aLastPage', 'a', 'containerContent');
			var spanPageMaxs = YAHOO.util.Dom.getElementsByClassName('spanPageMax', 'span', 'containerContent');
			var pageNo;
			var pageMax;
			var orders = YAHOO.util.Dom.getElementsByClassName('boxOrders', 'div', 'boxOrdersBd');

			pageMax = orders.length > 0 ? Math.ceil(orders.length / 10) : 1;

			for (var i=0; i<aFirstPages.length; i++) {
				// <<
				YAHOO.util.Event.addListener(aFirstPages[i], 'click', function() {
					var pageNo = parseInt(YAHOO.util.Dom.getElementsByClassName('spanPageNo', 'span', 'containerContent')[0].innerHTML);

					if (pageNo > 1) {
						_private.gotoPageNo(1);
					}
				});
				// <
				YAHOO.util.Event.addListener(aPrevPages[i], 'click', function() {
					var pageNo = parseInt(YAHOO.util.Dom.getElementsByClassName('spanPageNo', 'span', 'containerContent')[0].innerHTML);

					if (pageNo > 1) {
						_private.gotoPageNo(pageNo - 1);
					}
				});
				// >
				YAHOO.util.Event.addListener(aNextPages[i], 'click', function() {
					var pageNo = parseInt(YAHOO.util.Dom.getElementsByClassName('spanPageNo', 'span', 'containerContent')[0].innerHTML);

					if (pageNo < pageMax) {
						_private.gotoPageNo(pageNo + 1);
					}
				});
				// >>
				YAHOO.util.Event.addListener(aLastPages[i], 'click', function() {
					var pageNo = parseInt(YAHOO.util.Dom.getElementsByClassName('spanPageNo', 'span', 'containerContent')[0].innerHTML);

					if (pageNo < pageMax) {
						_private.gotoPageNo(pageMax);
					}
				});
				spanPageMaxs[i].innerHTML = pageMax;
			}
			_private.gotoPageNo(1);
		},
		/*-----------------------------------------------------------------------------------------
		 * find the index of a value in a list of values
		 * 
		 * params:
		 *   value: the value to search for
		 *   list: the list of values to search in
		 * return value:
		 *   index of the value if found, -1 otherwise
		 */
		findValueInList: function(value, list) {
			for (var i=0; i<list.length; i++) {
				if (value == list[i]) {
					return i;
				}
			}
			return -1;
		},
		/*-----------------------------------------------------------------------------------------
		 * switch to another page of orders
		 *
		 * params:
		 *   pageNo: the no. of the page to switch to
		 */
		gotoPageNo: function(pageNo) {
			var spanPageNos = YAHOO.util.Dom.getElementsByClassName('spanPageNo', 'span', 'containerContent');
			var orders      = YAHOO.util.Dom.getElementsByClassName('boxOrders', 'div', 'boxOrdersBd');

			for (var i=0; i<spanPageNos.length; i++) {
				spanPageNos[i].innerHTML = pageNo;
			}
			for (var i=0; i<orders.length; i++) {
				orders[i].style.display = 'none';
			}
			for (var i=10*(pageNo-1); i<orders.length && i<10*pageNo; i++) {
				orders[i].style.display = 'block';
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * add click listeners to cart spans enabling the user to put all items of a previous
		 * order still available to his/her basket
		 */
		modifyAddToBasketLinks: function() {
			YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('spanCart', 'span', 'boxOrdersBd'), 'click', function() {
				var orderID = YAHOO.util.Dom.getAncestorByClassName(this, 'boxOrders').getAttribute('id').replace(/^boxOrders/, '');
				var orderCodes = document.getElementById('hiddenCodes' + orderID).value.split(',');
				var orderCounts = document.getElementById('hiddenCounts' + orderID).value.split(',');
				var i = orderCodes.length - 1;
				var callback = {
					success: function(o) {
						if (--i >= 0) {
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + orderCounts[i] + '&a-oFrontend_FastOrder-code=' + orderCodes[i] + '&button-oFrontend_FastOrder-but_order=x&xhr=orders' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
						else {
							Basket.loadBasketLight();
							yuiLoader.hide();
						}
					},
					failure: function(o) {
						if (o.status == -1) {
							DEBUG('adding item to basket timed out - retrying');
							YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + orderCounts[i] + '&a-oFrontend_FastOrder-code=' + orderCodes[i] + '&button-oFrontend_FastOrder-but_order=x&xhr=orders' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
						else {
							Basket.loadBasketLight(); // there might have been items added to basket -> update basket light
							yuiLoader.hide();
						}
					},
					timeout: 30000
				};

				yuiLoader.show();
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + orderCounts[i] + '&a-oFrontend_FastOrder-code=' + orderCodes[i] + '&button-oFrontend_FastOrder-but_order=x&xhr=orders' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			})
		},
		/*-----------------------------------------------------------------------------------------
		 * add click listeners to the names of previous orders that will display more detailled
		 * information on those orders
		 */
		modifyOrderDetailLinks: function() {
			YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('aOrdersDetails', 'a', 'boxOrdersBd'), 'click', function() {
				var orderID = YAHOO.util.Dom.getAncestorByClassName(this, 'boxOrders').getAttribute('id').replace(/^boxOrders/, '');

				Content.loadOrdersDetail(orderID);
			})
		}
	};

	// public functions
	var _public = {
		/*-----------------------------------------------------------------------------------------
		 * wrapper for the private function with the same name
		 *
		 * param:
		 *   orderID: ID of the order currently viewed
		 */
		configureDetailPaging: function(orderID) {
			_private.configureDetailPaging(orderID);
		},
		/*-----------------------------------------------------------------------------------------
		 * display a list of all previous orders
		 *
		 * params:
		 *   data: an object containing order data - {orders: [id, date, name, items: [{code, count}]}
		 */
		displayOrders: function(data) {
			var container = document.getElementById('boxOrdersBd');
			var html;
			var codes;
			var counts;

			if (!container) {
				return;
			}
			// print orders in descending order, i.e. newest order first
			_private.orders.length = 0;

			for (var i=data.orders.length-1; i>=0; i--) {
				// add order ID to list of order IDs (required for detail paging)
				_private.orders[_private.orders.length] = data.orders[i].id;

				// add HTML code
				codes = '';
				counts = '';

				for (var j=0; j<data.orders[i].items.length; j++) {
					if (j > 0) {
						codes += ',';
						counts += ',';
					}
					codes += data.orders[i].items[j].code;
					counts += data.orders[i].items[j].count;
				}
				html  = '<div class="clearing"></div>';
				html += '<div class="boxOrders" id="boxOrders' + data.orders[i].id + '" style="display: none;">';
				html +=   '<div class="boxOrdersDate">';
				html +=     data.orders[i].date;
				html +=   '</div>';
				html +=   '<div class="boxOrdersName">';
				html +=     '<a class="aOrdersDetails">' + data.orders[i].name + '</a>';
				html +=   '</div>';
				html +=   '<div class="boxOrdersItemsAvailable">';
				html +=     data.orders[i].items.length;
				html +=   '</div>';
				html +=   '<div class="boxOrdersItemsOrdered">';
				html +=     data.orders[i].itemCount;
				html +=   '</div>';
				html +=   '<div class="boxOrdersToBasket">';
				
				if (data.orders[i].items.length > 0) {
					html += '<span title="Artikelliste in den Warenkorb" class="spanCart" id="spanCart' + data.orders[i].id + '"></span>';
					html += '<input type="hidden" value="' + codes + '" id="hiddenCodes' + data.orders[i].id + '">';
					html += '<input type="hidden" value="' + counts + '" id="hiddenCounts' + data.orders[i].id + '">';
				}
				html +=   '</div>';
				html += '</div>';
				html += '<div class="clearing"></div>';

				container.innerHTML += html;
			}
			_private.modifyOrderDetailLinks();
			_private.modifyAddToBasketLinks();
			_private.configurePaging();
		},
		/*-----------------------------------------------------------------------------------------
		 * get the ID of the order viewed last
		 *
		 * return value:
		 *   ID of the order last viewed, -1 if no order has been viewed yet
		 */
		getLastViewedOrderID: function() {
			return _private.lastViewedOrderID;
		},
		/*-----------------------------------------------------------------------------------------
		 * add click listeners to basket links
		 */
		modifyBasketDetailLinks: function() {
			var basketLinks = YAHOO.util.Dom.getElementsByClassName('spanCart', 'span', 'containerOrdersDetail');

			for (var i=0; i<basketLinks.length; i++) {
				YAHOO.util.Event.addListener(basketLinks[i], 'click', function() {
					var code = this.getAttribute('id').replace(/^spanCart/, '').replace(/_.*$/, '');
					var count = this.getAttribute('id').replace(/^spanCart.*_/, '');
					var callback = {
						success: function(o) {
							Basket.loadBasketLight();
							yuiLoader.hide();
						},
						failure: function(o) {
							if (o.status == -1) {
								DEBUG('adding item to basket timed out - retrying');
								YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + count + '&a-oFrontend_FastOrder-code=' + code + '&button-oFrontend_FastOrder-but_order=x&xhr=orders' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
							}
							else {
								yuiLoader.hide();
							}
						},
						timeout: 30000
					};

					yuiLoader.show();
					YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + count + '&a-oFrontend_FastOrder-code=' + code + '&button-oFrontend_FastOrder-but_order=x&xhr=orders' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
				});
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * add click listeners to the ERP codes of items in the detailled view of previous orders
		 */
		modifyItemDetailLinks: function() {
			YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('aShowItem', 'a', 'containerOrdersDetail'), 'click', function() {
				Shop.showItemDetailOrder(this.innerHTML);
			})
		},
		/*-----------------------------------------------------------------------------------------
		 * set the ID of the order viewed last
		 *
		 * params:
		 *   orderID: the ID of the order viewed last
		 */
		setLastViewedOrderID: function(orderID) {
			_private.lastViewedOrderID = orderID;
		}
	};
	return _public;
}();
if (typeof DEBUG != 'function') {
	function DEBUG(message) {
		try {
			console.log(message);
		}
		catch (e) {}
	}
}



/**
 * \brief Functions for rendering paging.
 * 
 * Handles options like number of items per page, image size, display of description text, and
 * paging. Active options will be written to a cookie, making them still available after the next
 * login.
 */
var Paging = function() {
	// private properties and functions ===========================================================
	var _private = {
		// properties
		cookieDomain: {
			//domain: 'viani.de',
			domain: location.hostname,
			path: '/'
		},
		noOfProds: 0,
		pageNo: 1,
		pageNoCMS: 0,
		pageMax: 0,
		settings: {
			largeImages: false,
			noOfProdsPerPage: 12,
			showDescs: true
		},
		settingsInitialized: false,
		// functions
		descHide: function() {
			var linksDescShow = YAHOO.util.Dom.getElementsByClassName('aDescShow', 'a', 'containerContent');
			var linksDescHide = YAHOO.util.Dom.getElementsByClassName('aDescHide', 'a', 'containerContent');

			for (var i=0; i<linksDescShow.length; i++) {
				YAHOO.util.Dom.removeClass(linksDescShow[i], 'current');
			}
			for (var i=0; i<linksDescHide.length; i++) {
				YAHOO.util.Dom.addClass(linksDescHide[i], 'current');
			}
			_private.settings.showDescs = false;
			_private.setCookie();
			_private.renderDescs();
		},
		descShow: function() {
			var linksDescShow = YAHOO.util.Dom.getElementsByClassName('aDescShow', 'a', 'containerContent');
			var linksDescHide = YAHOO.util.Dom.getElementsByClassName('aDescHide', 'a', 'containerContent');

			for (var i=0; i<linksDescShow.length; i++) {
				YAHOO.util.Dom.addClass(linksDescShow[i], 'current');
			}
			for (var i=0; i<linksDescHide.length; i++) {
				YAHOO.util.Dom.removeClass(linksDescHide[i], 'current');
			}
			_private.settings.showDescs = true;
			_private.setCookie();
			_private.renderDescs();
		},
		getProds: function() {
			var boxes = new Array();
			var prods = YAHOO.util.Dom.getElementsByClassName('boxProdTeaser');

			for (var i=0; i<prods.length; i++) {
				boxes[i] = prods[i].parentNode;
			}
			return boxes;
		},
		gotoFirstPage: function() {
			_private.gotoPageNo(1);
			_private.renderDescs();
		},
		gotoFirstPageCMS: function() {
			_private.gotoPageNoCMS(1);
			_private.renderDescs();
		},
		gotoLastPage: function() {
			_private.gotoPageNo(_private.pageMax);
			_private.renderDescs();
		},
		gotoLastPageCMS: function() {
			_private.gotoPageNoCMS(_private.pageMax);
			_private.renderDescs();
		},
		gotoNextPage: function() {
			_private.gotoPageNo(_private.pageNo + 1);
			_private.renderDescs();
		},
		gotoNextPageCMS: function() {
			_private.gotoPageNoCMS(_private.pageNoCMS + 1);
			_private.renderDescs();
		},
		gotoPageNo: function(no) {
			var prods;
			var prodOnDisplayFirst;
			var prodOnDisplayLast;

			if (no < 1) {
				no = 1;
			}
			if (no > _private.pageMax) {
				no = _private.pageMax;
			}
			if (no == _private.pageNo) {
				return;
			}
			prods = _private.getProds();
			prodOnDisplayFirst = (no - 1) * _private.settings.noOfProdsPerPage;
			prodOnDisplayLast  = no * _private.settings.noOfProdsPerPage - 1;

			for (var i=0; i<_private.noOfProds; i++) {
				if (i < prodOnDisplayFirst || i > prodOnDisplayLast) {
					prods[i].style.display = 'none';
				}
				else {
					prods[i].style.display = 'block';
				}
			}
			_private.pageNo = no;
			_private.renderPager();
		},
		gotoPageNoCMS: function(no) {
			var cookie = PBEURL('').replace(/\?/, '');
			var target = location.protocol + '//' + location.host + (location.port ? (':' + location.port) : '') + location.pathname + '?' + cookie + '&a-IndexBox_0-pbe_selected_row=';

			if (no < 1) {
				no = 1;
			}
			if (no > _private.pageMax) {
				no = _private.pageMax;
			}
			if (no == _private.pageNoCMS) {
				return;
			}
			target += (no - 1) * _private.settings.noOfProdsPerPage + 1;
			location = target;
		},
		gotoPrevPage: function() {
			_private.gotoPageNo(_private.pageNo - 1);
			_private.renderDescs();
		},
		gotoPrevPageCMS: function() {
			_private.gotoPageNoCMS(_private.pageNoCMS - 1);
			_private.renderDescs();
		},
		initSettings: function() {
			var settings = YAHOO.util.Cookie.getSubs('de.viani.paging');

			if (settings) {
				switch (settings.largeImages) {
					case 'true':
						_private.settings.largeImages = true;
						break;
					case 'false':
						_private.settings.largeImages = false;
						break;
					default:
						_private.settings.largeImages = false;
				}
				switch (settings.noOfProdsPerPage) {
					case '12':
					case '24':
					case '36':
					case '48':
						_private.settings.noOfProdsPerPage = parseInt(settings.noOfProdsPerPage);
						break;
					default:
						_private.settings.noOfProdsPerPage = 12;
				}
				switch (settings.showDescs) {
					case 'true':
						_private.settings.showDescs = true;
						break;
					case 'false':
						_private.settings.showDescs = false;
						break;
					default:
						_private.settings.showDescs = true;
				}
			}
			_private.settingsInitialized = true;
			_private.setCookie();

			// If user is not logged in, we also must set the current page no.
			if (typeof CMSNoOfProds != 'undefined') {
				var index = location.href.indexOf('a-IndexBox_0-pbe_selected_row=');

				if (index >= 0) {
					var no = location.href.substring(index + 30, location.href.length);
					
					no = no.replace(/&.*$/, '');
					no = parseInt(no);
					no = Math.ceil(no / _private.settings.noOfProdsPerPage);
					_private.pageNoCMS = no;
				}
				else {
					// this should only happen, if no of products per page has been changed
					_private.pageNoCMS = 1;
				}
				_private.renderPager();
			}
		},
		isH1: function(elem) {
			return elem.tagName == 'h1' || elem.tagName == 'H1';
		},
		isH2: function(elem) {
			return elem.tagName == 'h2' || elem.tagName == 'H2';
		},
		isProdImageDownsized: function(elem) {
			var isProdImage = YAHOO.util.Dom.hasClass(elem, 'img2Col') || YAHOO.util.Dom.hasClass(elem, 'img1Col');
			
			if (isProdImage) {
				var mediaSettings = Images.getSettings();
				var srcLarge = elem.getAttribute('src');
				var srcSmall;
				var start = srcLarge.lastIndexOf('.' + mediaSettings.variantLarge + '.');
				var newImage;

				if (start >= 0) {
					srcSmall = srcLarge.substring(0, start + 1)
					           + mediaSettings.variantSmall
					           + srcLarge.substring(start + mediaSettings.variantLarge.toString().length + 1, srcLarge.length);
					newImage = document.createElement('img');
					newImage.className = 'img1Col';
					newImage.setAttribute('src', srcSmall);
					newImage.setAttribute('alt', elem.getAttribute('alt'));
					newImage.setAttribute('title', elem.getAttribute('title'));
					newImage.setAttribute('width', elem.getAttribute('width'));
					newImage.setAttribute('height', elem.getAttribute('height'));
					newImage.setAttribute('id', elem.getAttribute('id'));
					elem.parentNode.appendChild(newImage);
					elem.parentNode.removeChild(elem);

					try {
						// get code and mode from image ID ('img/' + code + '/' + mode)
						var code = elem.getAttribute('id').replace(/^img\//, '').replace(/\/.+$/, '');
						var mode = elem.getAttribute('id').replace(/^.*\//, '');

						YAHOO.util.Event.addListener(newImage, 'click', function() {
							Shop.getItemDetail(code, mode);
						});
					}
					catch (e) {
						// ignore errors that occur when trying to add a click listener while not
						// being logged in (the image does not have an ID then)
					}
				}
			}
			return isProdImage;
		},
		isProdImageEnlarged: function(elem) {
			var isProdImage = YAHOO.util.Dom.hasClass(elem, 'img2Col') || YAHOO.util.Dom.hasClass(elem, 'img1Col');
			
			if (isProdImage) {
				var mediaSettings = Images.getSettings();
				var srcSmall = elem.getAttribute('src');
				var srcLarge;
				var start = srcSmall.lastIndexOf('.' + mediaSettings.variantSmall + '.');
				var newImage;

				if (start >= 0) {
					srcLarge = srcSmall.substring(0, start + 1)
				               + mediaSettings.variantLarge
							   + srcSmall.substring(start + mediaSettings.variantSmall.toString().length + 1, srcSmall.length);
					newImage = document.createElement('img');
					newImage.className = 'img2Col';
					newImage.setAttribute('src', srcLarge);
					newImage.setAttribute('alt', elem.getAttribute('alt'));
					newImage.setAttribute('title', elem.getAttribute('title'));
					newImage.setAttribute('width', elem.getAttribute('width'));
					newImage.setAttribute('height', elem.getAttribute('height'));
					newImage.setAttribute('id', elem.getAttribute('id'));
					elem.parentNode.appendChild(newImage);
					elem.parentNode.removeChild(elem);

					try {
						// get code and mode from image ID ('img/' + code + '/' + mode)
						var code = elem.getAttribute('id').replace(/^img\//, '').replace(/\/.+$/, '');
						var mode = elem.getAttribute('id').replace(/^.*\//, '');

						YAHOO.util.Event.addListener(newImage, 'click', function() {
							Shop.getItemDetail(code, mode);
						});
					}
					catch (e) {
						// ignore errors that occur when trying to add a click listener while not
						// being logged in (the image does not have an ID then)
					}
				}
			}
			return isProdImage;
		},
		isProdTeaser: function(elem) {
			if (elem) {
				var teasers = YAHOO.util.Dom.getElementsByClassName('boxProdTeaser', 'div', elem);

				if (teasers.length > 0) {
					return true;
				}
			}
			return false;
		},
		prodImageDownsize: function(elem) {
			return YAHOO.util.Dom.getElementsBy(_private.isProdImageDownsized, 'img', elem);
		},
		prodImageEnlarge: function(elem) {
			return YAHOO.util.Dom.getElementsBy(_private.isProdImageEnlarged, 'img', elem);
		},
		renderDescs: function() {
			var descs = YAHOO.util.Dom.getElementsByClassName('boxProdDescText', 'div', 'containerContent');
			var headline;

			if (_private.settings.showDescs) {
				if (_private.settings.largeImages) {
					for (var i=0; i<descs.length; i++) {
						descs[i].style.display = 'block';
						headline = YAHOO.util.Dom.getFirstChildBy(descs[i], _private.isH1);

						if (headline) {
							headline.style.display = 'block';
						}
						headline = YAHOO.util.Dom.getFirstChildBy(descs[i], _private.isH2);

						if (headline) {
							headline.style.display = 'block';
						}
					}
				}
				else {
					for (var i=0; i<descs.length; i++) {
						descs[i].style.display = 'block';
						headline = YAHOO.util.Dom.getFirstChildBy(descs[i], _private.isH1);

						if (headline) {
							headline.style.display = 'none';
						}
						headline = YAHOO.util.Dom.getFirstChildBy(descs[i], _private.isH2);

						if (headline) {
							headline.style.display = 'none';
						}
					}
				}
			}
			else {
				for (var i=0; i<descs.length; i++) {
					descs[i].style.display = 'none';
				}
			}
		},
		renderImagesLarge: function() {
			var linksLarge = YAHOO.util.Dom.getElementsByClassName('aImagesLarge', 'a', 'containerContent');
			var linksSmall = YAHOO.util.Dom.getElementsByClassName('aImagesSmall', 'a', 'containerContent');
			var linksNone  = YAHOO.util.Dom.getElementsByClassName('aImagesNone', 'a', 'containerContent');
			var boxes  = YAHOO.util.Dom.getElementsByClassName('box1Col', 'div', 'containerContent');
			var image;
			var imageSrc;

			for (var i=0; i<linksLarge.length; i++) {
				YAHOO.util.Dom.addClass(linksLarge[i], 'current');
			}
			for (var i=0; i<linksSmall.length; i++) {
				YAHOO.util.Dom.removeClass(linksSmall[i], 'current');
			}
			for (var i=0; i<linksNone.length; i++) {
				YAHOO.util.Dom.removeClass(linksNone[i], 'current');
			}
			for (var i=0; i<boxes.length; i++) {
				if (_private.isProdTeaser(boxes[i])) {
					image = _private.prodImageEnlarge(boxes[i]);
					YAHOO.util.Dom.replaceClass(image, 'img1Col', 'img2Col');
					YAHOO.util.Dom.replaceClass(boxes[i], 'box1Col', 'box2Col');
				}
			}
			_private.settings.largeImages = true;
			_private.setCookie();
			Images.renderImages();
			_private.renderDescs();
		},
		renderImagesSmall: function() {
			var linksLarge = YAHOO.util.Dom.getElementsByClassName('aImagesLarge', 'a', 'containerContent');
			var linksSmall = YAHOO.util.Dom.getElementsByClassName('aImagesSmall', 'a', 'containerContent');
			var linksNone  = YAHOO.util.Dom.getElementsByClassName('aImagesNone', 'a', 'containerContent');
			var boxes = YAHOO.util.Dom.getElementsByClassName('box2Col', 'div', 'containerContent');
			var image;
			var imageSrc;

			for (var i=0; i<linksLarge.length; i++) {
				YAHOO.util.Dom.removeClass(linksLarge[i], 'current');
			}
			for (var i=0; i<linksSmall.length; i++) {
				YAHOO.util.Dom.addClass(linksSmall[i], 'current');
			}
			for (var i=0; i<linksNone.length; i++) {
				YAHOO.util.Dom.removeClass(linksNone[i], 'current');
			}
			for (var i=0; i<boxes.length; i++) {
				if (_private.isProdTeaser(boxes[i])) {
					image = _private.prodImageDownsize(boxes[i]);
					YAHOO.util.Dom.replaceClass(image, 'img2Col', 'img1Col');
					YAHOO.util.Dom.replaceClass(boxes[i], 'box2Col', 'box1Col');
				}
			}
			_private.settings.largeImages = false;
			_private.setCookie();
			Images.renderImages();
			_private.renderDescs();
		},
		renderPager: function() {
			var spanPageNo  = YAHOO.util.Dom.getElementsByClassName('spanPageNo');
			var spanPageMax = YAHOO.util.Dom.getElementsByClassName('spanPageMax');

			if (spanPageNo.length != spanPageMax.length) {
				return;
			}
			_private.pageMax = Math.max(Math.ceil(_private.noOfProds / _private.settings.noOfProdsPerPage), 1);

			for (var i=0; i<spanPageNo.length; i++) {
				if (!_private.pageNoCMS) {
					spanPageNo[i].innerHTML = '' + _private.pageNo;
				}
				else {
					// if paging is CMS dependent, use _private.pageNoCMS
					spanPageNo[i].innerHTML = '' + _private.pageNoCMS;
				}
				spanPageMax[i].innerHTML = '' + _private.pageMax;
			}
		},
		setCookie: function() {
			YAHOO.util.Cookie.setSubs('de.viani.paging', _private.settings, {
				domain: _private.cookieDomain.domain,
				path: _private.cookieDomain.path,
				expires: new Date('December 31, 2099 23:59:59'),
				secure: false
			});
		},
		setNoOfProdsPerPage: function(no) {
			var links12;
			var links24;
			var links36;
			var links48;
			var links;
			var prods;
			var i;

			links12 = YAHOO.util.Dom.getElementsByClassName('a12ProdsPerPage', 'a', 'containerContent');
			links24 = YAHOO.util.Dom.getElementsByClassName('a24ProdsPerPage', 'a', 'containerContent');
			links36 = YAHOO.util.Dom.getElementsByClassName('a36ProdsPerPage', 'a', 'containerContent');
			links48 = YAHOO.util.Dom.getElementsByClassName('a48ProdsPerPage', 'a', 'containerContent');

			if (   (no!=12 && no!=24 && no!=36 && no!=48)
			    || links12.length!=links24.length
			    || links12.length!=links36.length
			    || links12.length!=links48.length) {
				return;
			}
			switch (no) {
				case 12:
					links = links12;
					break;
				case 24:
					links = links24;
					break;
				case 36:
					links = links36;
					break;
				case 48:
					links = links48;
					break;
			}
			for (i=0; i<links12.length; i++) {
				YAHOO.util.Dom.removeClass(links12[i], 'current');
				YAHOO.util.Dom.removeClass(links24[i], 'current');
				YAHOO.util.Dom.removeClass(links36[i], 'current');
				YAHOO.util.Dom.removeClass(links48[i], 'current');
				YAHOO.util.Dom.addClass(links[i], 'current');
			}
			if (typeof CMSNoOfProds == 'undefined') {
				// do this only if we have JavaScript generated content
				prods = _private.getProds();
	
				for (i=0; i<no && i<prods.length; i++) {
					prods[i].style.display = 'block';
				}
				for ( ; i<prods.length; i++) {
					prods[i].style.display = 'none';
				}
			}
			_private.settings.noOfProdsPerPage = no;
			_private.setCookie();
			_private.pageNo = 1;
			_private.renderPager();
		}
	};

	// public functions ===========================================================================
	var _public = {
		getSettings: function() {
			if (!_private.settingsInitialized) {
				_private.initSettings();
			}
			return _private.settings;
		},
		initPaging: function() {
			window.setTimeout(_public.renderPaging, 50);
		},
		renderPaging: function() {
			var oldPager;
			var prods;
			var images;
			var links12ProdsPerPage = YAHOO.util.Dom.getElementsByClassName('a12ProdsPerPage', 'a', 'containerContent');
			var links24ProdsPerPage = YAHOO.util.Dom.getElementsByClassName('a24ProdsPerPage', 'a', 'containerContent');
			var links36ProdsPerPage = YAHOO.util.Dom.getElementsByClassName('a36ProdsPerPage', 'a', 'containerContent');
			var links48ProdsPerPage = YAHOO.util.Dom.getElementsByClassName('a48ProdsPerPage', 'a', 'containerContent');
			var linksImagesLarge = YAHOO.util.Dom.getElementsByClassName('aImagesLarge', 'a', 'containerContent');
			var linksImagesSmall = YAHOO.util.Dom.getElementsByClassName('aImagesSmall', 'a', 'containerContent');
			var linksDescShow = YAHOO.util.Dom.getElementsByClassName('aDescShow', 'a', 'containerContent');
			var linksDescHide = YAHOO.util.Dom.getElementsByClassName('aDescHide', 'a', 'containerContent');
			var linksFirst = YAHOO.util.Dom.getElementsByClassName('aFirstPage', 'a', 'containerContent');
			var linksPrev  = YAHOO.util.Dom.getElementsByClassName('aPrevPage', 'a', 'containerContent');
			var linksNext  = YAHOO.util.Dom.getElementsByClassName('aNextPage', 'a', 'containerContent');
			var linksLast  = YAHOO.util.Dom.getElementsByClassName('aLastPage', 'a', 'containerContent');

			// create/read cookie
			_private.initSettings();
			// remove Ikebana paging
			oldPager = YAHOO.util.Dom.getElementsByClassName('navigate', 'div', 'containerContent');

			for (var i=0; i<oldPager.length; i++) {
				oldPager[i].parentNode.removeChild(oldPager[i]);
			}
			// display initially hidden images
			images = YAHOO.util.Dom.getElementsByClassName('boxImage', 'div', 'containerContent');

			for (var i=0; i<images.length; i++) {
				images[i].style.display = 'block';
			}
			// count products
			if (typeof CMSNoOfProds == 'undefined') {
				prods = YAHOO.util.Dom.getElementsByClassName('boxProdTeaser', 'div', 'containerContent');
				_private.noOfProds = prods.length;
			}
			else {
				// if the product teasers are CMS generated, use
				// the counter defined in the master template
				_private.noOfProds = CMSNoOfProds;
				_private.renderPager();
			}
			// set products per page handlers
			if (   links12ProdsPerPage.length == links24ProdsPerPage.length
			    && links12ProdsPerPage.length == links36ProdsPerPage.length
			    && links12ProdsPerPage.length == links48ProdsPerPage.length) {
				YAHOO.util.Event.removeListener(links12ProdsPerPage);
				YAHOO.util.Event.removeListener(links24ProdsPerPage);
				YAHOO.util.Event.removeListener(links36ProdsPerPage);
				YAHOO.util.Event.removeListener(links48ProdsPerPage);

				for (var i=0; i<links12ProdsPerPage.length; i++) {
					YAHOO.util.Event.addListener(links12ProdsPerPage[i], 'click', function() {
						_private.setNoOfProdsPerPage(12);
					});
					YAHOO.util.Event.addListener(links24ProdsPerPage[i], 'click', function() {
						_private.setNoOfProdsPerPage(24);
					});
					YAHOO.util.Event.addListener(links36ProdsPerPage[i], 'click', function() {
						_private.setNoOfProdsPerPage(36);
					});
					YAHOO.util.Event.addListener(links48ProdsPerPage[i], 'click', function() {
						_private.setNoOfProdsPerPage(48);
					});
				}
			}
			// set products per page
			_private.setNoOfProdsPerPage(_private.settings.noOfProdsPerPage);
			// set image size handlers
			if (linksImagesLarge.length == linksImagesSmall.length) {
				YAHOO.util.Event.removeListener(linksImagesLarge);
				YAHOO.util.Event.removeListener(linksImagesSmall);

				for (var i=0; i<linksImagesLarge.length; i++) {
					YAHOO.util.Event.addListener(linksImagesLarge[i], 'click', _private.renderImagesLarge);
					YAHOO.util.Event.addListener(linksImagesSmall[i], 'click', _private.renderImagesSmall);
				}
			}
			// set image size
			if (_private.settings.largeImages) {
				_private.renderImagesLarge();
			}
			else {
				_private.renderImagesSmall();
			}
			// set description display handlers
			if (linksDescShow.length == linksDescHide.length) {
				YAHOO.util.Event.removeListener(linksDescShow);
				YAHOO.util.Event.removeListener(linksDescHide);

				for (var i=0; i<linksDescShow.length; i++) {
					YAHOO.util.Event.addListener(linksDescShow[i], 'click', _private.descShow);
					YAHOO.util.Event.addListener(linksDescHide[i], 'click', _private.descHide);
				}
			}
			// set description display
			if (_private.settings.showDescs) {
				_private.descShow();
			}
			else {
				_private.descHide();
			}
			// set paging handlers
			if (   linksFirst.length == linksPrev.length
			    && linksFirst.length == linksNext.length
			    && linksFirst.length == linksLast.length) {
				YAHOO.util.Event.removeListener(linksFirst);
				YAHOO.util.Event.removeListener(linksPrev);
				YAHOO.util.Event.removeListener(linksNext);
				YAHOO.util.Event.removeListener(linksLast);

				for (var i=0; i<linksFirst.length; i++) {
					if (typeof CMSNoOfProds == 'undefined') {
						YAHOO.util.Event.addListener(linksFirst[i], 'click', _private.gotoFirstPage);
						YAHOO.util.Event.addListener(linksPrev[i], 'click', _private.gotoPrevPage);
						YAHOO.util.Event.addListener(linksNext[i], 'click', _private.gotoNextPage);
						YAHOO.util.Event.addListener(linksLast[i], 'click', _private.gotoLastPage);
					}
					else {
						// if the product teasers are CMS generated,
						// generate the link target in another way
						YAHOO.util.Event.addListener(linksFirst[i], 'click', _private.gotoFirstPageCMS);
						YAHOO.util.Event.addListener(linksPrev[i], 'click', _private.gotoPrevPageCMS);
						YAHOO.util.Event.addListener(linksNext[i], 'click', _private.gotoNextPageCMS);
						YAHOO.util.Event.addListener(linksLast[i], 'click', _private.gotoLastPageCMS);
					}
				}
			}
		}
	};
	return _public;
}();
if (typeof DEBUG != 'function') {
	function DEBUG(message) {
		try {
			console.log(message);
		}
		catch (e) {}
	}
}



/**
 * \brief Functions for creating and rendering shop menu and teasers of shop items.
 * 
 * Requires class Paging.
 */
var Shop = function() {
	// private properties and functions ===========================================================
	var _private = {
		cookie: PBEURL('').replace(/\?/, ''),
		// data of all shop items
		data: null,      // {items: [{CG: [nodeId], _*, ..., _*, code, VAT}], count}
		// selection of ERP codes used for detail paging
		ERPCodes: [],
		// data of shop items favored by the user
		favorites: null, // {items: [code], count}
		// some settings used for the output of images
		media: Images.getSettings(),
		// data used to generate the shop menu
		menu: null,      // {nodes:[{nodeId, parentNodeId, redirectNodeId, fsns, label, level}], depth, level, nodeId, parentNodeId}
		menuDepthAboveShop: 2,
		// number of products of the current node
		noOfProds: 0,
		// panel containing information on pre-ordering items
		preOrderPanel: {
			hide: function() {},
			show: function() {}
		},
		// data of shop items returned by the most recent search
		searchResults: [],
		xhrCount: 0,
		/*-----------------------------------------------------------------------------------------
		 * add a VE unit of a shop item to the basket
		 * 
		 * The data set of the current shop item works as context of the function.
		 */
		addToBasket: function() {
			var code = this.code;
			var count;
			var callback = {
				success: function(o) {
					Basket.loadBasketLight();
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('adding item to basket timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + count + '&a-oFrontend_FastOrder-code=' + code + '&button-oFrontend_FastOrder-but_order=x&xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};

			if (this.readInput) {
				try {
					count = document.getElementById('inputAddToBasket').value;
					count = count.replace(/^\s*/, '');
					count = count.replace(/\s*$/, '');
				}
				catch (e) {
					DEBUG('could not get amount: ' + e.message);
					return;
				}
				if (count != parseInt(count).toString() || parseInt(count) <= 0) {
					document.getElementById('inputAddToBasket').value = '1';
					return;
				}
			}
			else if (typeof this._78 != 'undefined') {
				// _78 -> VE
				count = this._78.toString();
			}
			else {
				count = 1;
			}
			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + count + '&a-oFrontend_FastOrder-code=' + code + '&button-oFrontend_FastOrder-but_order=x&xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
		},
		/*-----------------------------------------------------------------------------------------
		 * configure paging links (<<, <, >, >>) in item detail view
		 * 
		 * params:
		 *   code: ERP code of current item
		 *   mode: string ('shop', 'search', 'favorites', 'basket', 'basketFast', 'order')
		 */
		configureDetailPaging: function(code, mode) {
			var linksFirst = YAHOO.util.Dom.getElementsByClassName('aFirstPage', 'a', 'containerContent');
			var linksPrev  = YAHOO.util.Dom.getElementsByClassName('aPrevPage', 'a', 'containerContent');
			var linksNext  = YAHOO.util.Dom.getElementsByClassName('aNextPage', 'a', 'containerContent');
			var linksLast  = YAHOO.util.Dom.getElementsByClassName('aLastPage', 'a', 'containerContent');
			var pageNos  = YAHOO.util.Dom.getElementsByClassName('spanPageNo');
			var pageMaxs = YAHOO.util.Dom.getElementsByClassName('spanPageMax');
			var indexCurrent = _private.findValueInList(code, _private.ERPCodes);
			var first;
			var prev;
			var next;
			var last;
			var backLinks;

			if (   linksFirst.length != linksPrev.length
			    || linksFirst.length != linksNext.length
			    || linksFirst.length != linksLast.length
			    || linksFirst.length != pageNos.length
			    || linksFirst.length != pageMaxs.length
			    || indexCurrent < 0) {
				return;
			}
			first = _private.ERPCodes[0];
			last  = _private.ERPCodes[_private.ERPCodes.length - 1];

			if (indexCurrent > 0) {
				prev = _private.ERPCodes[indexCurrent - 1];
			}
			else {
				prev = first;
			}
			if (indexCurrent < _private.ERPCodes.length - 1) {
				next = _private.ERPCodes[indexCurrent + 1];
			}
			else {
				next = last;
			}
			YAHOO.util.Event.removeListener(linksFirst);
			YAHOO.util.Event.removeListener(linksPrev);
			YAHOO.util.Event.removeListener(linksNext);
			YAHOO.util.Event.removeListener(linksLast);

			for (var i=0; i<linksFirst.length; i++) {
				// links to first page (<<)
				YAHOO.util.Event.addListener(linksFirst[i], 'click', function() {
					_private.getItemDetail(first, mode);
				});
				// links to prev page (<)
				YAHOO.util.Event.addListener(linksPrev[i], 'click', function() {
					_private.getItemDetail(prev, mode);
				});
				// links to next page (>)
				YAHOO.util.Event.addListener(linksNext[i], 'click', function() {
					_private.getItemDetail(next, mode);
				});
				// links to last page (>>)
				YAHOO.util.Event.addListener(linksLast[i], 'click', function() {
					_private.getItemDetail(last, mode);
				});
				// page info
				pageNos[i].innerHTML  = (indexCurrent + 1).toString();
				pageMaxs[i].innerHTML = (_private.ERPCodes.length).toString();
			}
			// add back link
			backLinks = YAHOO.util.Dom.getElementsByClassName('aBackToOverview', 'a', 'containerContent');
			YAHOO.util.Event.removeListener(backLinks);

			for (var i=0; i<backLinks.length; i++) {
				switch (mode) {
					case 'shop':
						YAHOO.util.Event.addListener(backLinks[i], 'click', function() {
							_private.showNode(_private.menu.nodeId);
						});
						break;
					case 'search':
						YAHOO.util.Event.addListener(backLinks[i], 'click', function() {
							Content.loadSearchResults();
						});
						break;
					case 'favorites':
						YAHOO.util.Event.addListener(backLinks[i], 'click', function() {
							Content.loadFavorites();
						});
						break;
					case 'basket':
						YAHOO.util.Event.addListener(backLinks[i], 'click', function() {
							Content.loadBasket();
						});
						break;
					case 'basketFast':
						YAHOO.util.Event.addListener(backLinks[i], 'click', function() {
							Content.loadBasketFast();
						});
						break;
					case 'order':
						YAHOO.util.Event.addListener(backLinks[i], 'click', function() {
							Content.loadOrdersDetail();
						});
						break;
					default:
						DEBUG('warning: illegal value \'' + mode + '\' of parameter mode');
				}
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * generate a new node and append it to an existing node
		 *
		 * params:
		 *   parentNode: reference to node to which the new child is to be appended
		 *               (if this is null, the "child" will be created, but not appended)
		 *   tagName:    tag name of the node to be created
		 *   className:  class name(s) of the new node (optional)
		 * return value:
		 *   reference to the node created
		 *   null in case of error
		 */
		createChild: function(parentNode, tagName, className) {
			var child = document.createElement(tagName);

			if (className) {
				child.className = className;
			}
			if (parentNode) {
				parentNode.appendChild(child);
			}
			return child;
		},
		/*-----------------------------------------------------------------------------------------
		 * add listeners for input fields (item name, item count) of fast order form
		 */
		fastOrderAddFieldListeners: function() {
			var codes = YAHOO.util.Dom.getElementsByClassName('inputCode', 'input', 'boxFastOrderFields');
			var counts = YAHOO.util.Dom.getElementsByClassName('inputCount', 'input', 'boxFastOrderFields');
			var hiddenCounts = YAHOO.util.Dom.getElementsByClassName('hiddenCount', 'input', 'boxFastOrderFields');

			/*
			 * parse ERP codes:
			 *   Check if a valid ERP code has been entered. If this is the case, add the VE count,
			 *   the name of the item, its availability, and its VE price. Otherwise clear the
			 *   field.
			 */
			for (var i=0; i<codes.length; i++) {
				YAHOO.util.Event.removeListener(codes[i]);
				YAHOO.util.Event.addListener(codes[i], 'change', function() {
					var code  = _private.trim(this.input.value);
					var rowNo = this.input.getAttribute('id').replace(/^inputCode/, '');
					var index = -1;
					var noOfRows;
					var data;

					if (code) {
						// check if code is valid
						for (var i=0; i<_private.data.items.length; i++) {
							if (_private.data.items[i].code == code) {
								index = i;
								break;
							}
						}
						// mark valid code as invalid, if it has been added to this form before
						if (index >= 0) {
							noOfRows = YAHOO.util.Dom.getElementsByClassName('boxFastOrderRow', 'div', 'containerFastOrder').length;

							for (var i=0; i<noOfRows; i++) {
								if (i != rowNo && code == document.getElementById('inputCode' + i).value) {
									index = -1;
									break;
								}
							}
						}
					}
					if (!code || index < 0) {
						// invalid code -> clear row
						_private.fastOrderClearRow(rowNo);
					}
					else {
						// valid code -> auto-fill-in fields
						data = _private.data.items[index];
						this.input.value = code; // trimmed

						// _78 -> VE
						if (data._78) {
							document.getElementById('inputCount' + rowNo).value = data._78;
							document.getElementById('hiddenCount' + rowNo).value = data._78;
						}
						else {
							document.getElementById('inputCount' + rowNo).value = 1;
							document.getElementById('hiddenCount' + rowNo).value = 1;
						}
						//_30 -> Internetname1
						if (data._30) {
							document.getElementById('inputName' + rowNo).value = data._30;
						}
						else {
							document.getElementById('inputName' + rowNo).value = 'unbekannter Name';
						}
						//_57 -> Vorbestellung, _63 -> Verfuegbarkeit (_57 overrides _63)
						if (data._57 && data._57 == 'Ja') {
							document.getElementById('imgAvailability' + rowNo).setAttribute('src', '/_images/calendar.gif');
							document.getElementById('imgAvailability' + rowNo).setAttribute('alt', 'Vorbestellung');
							document.getElementById('imgAvailability' + rowNo).setAttribute('title', 'Vorbestellung');
							YAHOO.util.Dom.addClass('imgAvailability' + rowNo, 'aPreOrder');
							_public.preOrderAddListeners();
						}
						else if (typeof data._63 != 'undefined') {
							document.getElementById('imgAvailability' + rowNo).setAttribute('src', '/_images/availability' + data._63 + '.gif');
							document.getElementById('imgAvailability' + rowNo).setAttribute('alt', 'Verf\u00FCgbarkeit');
							document.getElementById('imgAvailability' + rowNo).setAttribute('title', 'Verf\u00FCgbarkeit');
							YAHOO.util.Dom.removeClass('imgAvailability' + rowNo, 'aPreOrder');
						}
						else {
							document.getElementById('imgAvailability' + rowNo).setAttribute('src', '/_images/spacer.gif');
							document.getElementById('imgAvailability' + rowNo).setAttribute('alt', '');
							document.getElementById('imgAvailability' + rowNo).setAttribute('title', '');
							YAHOO.util.Dom.removeClass('imgAvailability' + rowNo, 'aPreOrder');
						}
						//_79 -> VEPreis
						if (data._79) {
							document.getElementById('inputPrice' + rowNo).value = _private.priceToString(data._79) + ' \u20AC';
						}
						else if (data._79 == 0.00) {
							document.getElementById('inputPrice' + rowNo).value = 'Tagespreis';
						}
						else {
							document.getElementById('inputPrice' + rowNo).value = '?';
						}

						Forms.toggleLabelDisplay('inputCode' + rowNo, true);
						Forms.toggleLabelDisplay('inputCount' + rowNo, true);
						Forms.toggleLabelDisplay('inputName' + rowNo, true);
						Forms.toggleLabelDisplay('inputPrice' + rowNo, true);
					}
					_private.fastOrderTidyRows();
				}, {
					input: codes[i]
				}, true);
			}
			/*
			 * parse counters:
			 *   If there is no item name, remove the counter. Otherwise check if the counter is
			 *   valid, i.e. it must be a positive integer. In case the value is 0, the item will
			 *   be removed from the list.
			 */
			for (var i=0; i<counts.length; i++) {
				YAHOO.util.Event.removeListener(counts[i]);
				YAHOO.util.Event.addListener(counts[i], 'change', function() {
					var count = this.input.value;
					var rowNo = this.input.getAttribute('id').replace(/^inputCount/, '');
					var code  = _private.trim(this.code.value);

					count = count.replace(/^\s*/, '');
					count = count.replace(/\s*$/, '');

					if (!this.code) {
						this.input.value = '';
						this.hidden.value = '';
					}
					else if (count == parseInt(count).toString() && parseInt(count) > 0) {
						this.input.value = count;
						this.hidden.value = count;
					}
					else if (count == parseInt(count).toString() && parseInt(count) == 0) {
						_private.fastOrderClearRow(rowNo);
						_private.fastOrderTidyRows();
					}
					else {
						this.input.value = this.hidden.value;
					}
				}, {
					input: counts[i],
					hidden: hiddenCounts[i],
					code: codes[i]
				}, true);
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * add 10 new rows to fast order form
		 */
		fastOrderAddFields: function() {
			var boxFields = document.getElementById('boxFastOrderFields');
			var rows;

			if (boxFields) {
				rows = YAHOO.util.Dom.getElementsByClassName('hiddenCount', 'input', boxFields);

				for (var i=0; i<10; i++) {
					boxFields.appendChild(_private.fastOrderFields(rows.length + i));
				}
				Forms.initOverLabels();
				_private.fastOrderAddFieldListeners();
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * clear all field values of a given row, move up all rows after the row cleared
		 *
		 * params:
		 *   rowNo: the no. of the row to be cleared
		 */
		fastOrderClearRow: function(rowNo) {
			document.getElementById('inputCode' + rowNo).value = '';
			document.getElementById('inputCount' + rowNo).value = '';
			document.getElementById('hiddenCount' + rowNo).value = '';
			document.getElementById('inputName' + rowNo).value = 'Name';
			document.getElementById('imgAvailability' + rowNo).setAttribute('src', '/_images/spacer.gif');
			document.getElementById('imgAvailability' + rowNo).setAttribute('alt', '');
			document.getElementById('imgAvailability' + rowNo).setAttribute('title', '');
			document.getElementById('inputPrice' + rowNo).value = 'Preis';

			Forms.toggleLabelDisplay('inputCode' + rowNo, false);
			Forms.toggleLabelDisplay('inputCount' + rowNo, false);
			Forms.toggleLabelDisplay('inputName' + rowNo, false);
			Forms.toggleLabelDisplay('inputPrice' + rowNo, false);
		},
		/*-----------------------------------------------------------------------------------------
		 * create an HTML object for a new input row for the fast order form
		 *
		 * params:
		 *   rowNo: no. of the row to be added
		 */
		fastOrderFields: function(rowNo) {
			var html = '';
			var row = document.createElement('div');

			html += '<div class="box1Col">';
			html +=   '<div class="boxCombinedOuter">';
			html +=     '<div class="boxCombinedInner">';
			html +=       '<label for="inputCode' + rowNo + '" class="overLabel">Art.Nr.</label>';
			html +=       '<input type="text" name="inputFastOrderCode" value="" title="Art.Nr." tabindex="' + (10 * rowNo + 1) + '" class="text inputCode" id="inputCode' + rowNo + '">';
			html +=     '</div>';
			html +=   '</div>';
			html += '</div>';
			html += '<div class="box1Col">';
			html +=   '<div class="boxCombinedOuter">';
			html +=     '<div class="boxCombinedInner">';
			html +=       '<label for="inputCount' + rowNo + '" class="overLabel">Menge</label>';
			html +=       '<input type="text" name="inputFastOrderCount" value="" title="Menge" tabindex="' + (10 * rowNo + 2) + '" class="text inputCount" id="inputCount' + rowNo + '">';
			html +=       '<input type="hidden" name="hiddenFastOrderCount" value="" class="hiddenCount" id="hiddenCount' + rowNo + '">';
			html +=     '</div>';
			html +=   '</div>';
			html += '</div>';
			html += '<div class="box3Col">';
			html +=   '<div class="boxCombinedOuter">';
			html +=     '<div class="boxCombinedInner">';
			html +=       '<label for="inputName' + rowNo + '" class="overLabel">Name</label>';
			html +=       '<input type="text" name="inputFastOrderName" value="" title="Name" class="text inputName disabled" id="inputName' + rowNo + '" disabled>';
			html +=     '</div>';
			html +=   '</div>';
			html += '</div>';
			html += '<div class="boxAvailability" id="boxAvailability' + rowNo + '">';
			html +=   '<img src="/_images/spacer.gif" alt="" title="" class="imgAvailability" id="imgAvailability' + rowNo + '">';
			html += '</div>';
			html += '<div class="boxPrice" id="boxPrice' + rowNo + '">';
			html +=   '<div class="boxCombinedOuter">';
			html +=     '<div class="boxCombinedInner">';
			html +=       '<label for="inputPrice' + rowNo + '" class="overLabel">VE-Preis</label>';
			html +=       '<input type="text" name="inputFastOrderPrice" value="" title="VE-Preis" class="text inputPrice disabled" id="inputPrice' + rowNo + '" disabled>';
			html +=     '</div>';
			html +=   '</div>';
			html += '</div>';
			html += '<div class="clearing"></div>';

			row.className = 'boxFastOrderRow';
			row.setAttribute('id', 'boxFastOrderRow' + rowNo);
			row.innerHTML = html;

			return row;
		},
		/*-----------------------------------------------------------------------------------------
		 * update basket according to data in fast order form, then go to basket overview
		 */
		fastOrderGoToBasket: function() {
			var callback = {
				success: function(o) {
					index++;
					code = document.getElementById('inputCode' + index).value;
					
					if (code) {
						count = document.getElementById('inputCount' + index).value;
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + count + '&a-oFrontend_FastOrder-code=' + code + '&button-oFrontend_FastOrder-but_order=x&xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						Content.loadBasketFast();
					}
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('adding items to basket timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + count + '&a-oFrontend_FastOrder-code=' + code + '&button-oFrontend_FastOrder-but_order=x&xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};
			var noOfRows = YAHOO.util.Dom.getElementsByClassName('boxFastOrderRow', 'div', 'containerFastOrder').length;
			var code = document.getElementById('inputCode0').value;
			var count;
			var index = 0;

			if (code) {
				count = document.getElementById('inputCount0').value;
				yuiLoader.show();
				YAHOO.util.Connect.asyncRequest('GET', '/_shop/sendData.html?a-oFrontend_FastOrder-count=' + count + '&a-oFrontend_FastOrder-code=' + code + '&button-oFrontend_FastOrder-but_order=x&xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
			else {
				// remove the next line, if you don't want customers to go the
				// basket as long as they don't have items in the fast order form
				Content.loadBasketFast();
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * reset fast order form, remove all items from basket
		 */
		fastOrderResetForm: function() {
			Content.loadShopFast();
		},
		/*-----------------------------------------------------------------------------------------
		 * tidy rows by moving values up (in case there are empty rows before any filled-in rows)
		 */
		fastOrderTidyRows: function() {
			var noOfRows = YAHOO.util.Dom.getElementsByClassName('boxFastOrderRow', 'div', 'containerFastOrder').length;
			var noOfFirstEmptyRow = -1;
			var sourceFields;
			var targetFields;

			for (var i=0; i<noOfRows; i++) {
				if (document.getElementById('inputCode' + i).value) {
					if (noOfFirstEmptyRow >= 0 && noOfFirstEmptyRow < i) {
						// move up data
						sourceFields = YAHOO.util.Dom.getElementsBy(function(elem) {
							return true;
						}, 'input', 'boxFastOrderRow' + i);
						targetFields = YAHOO.util.Dom.getElementsBy(function(elem) {
							return true;
						}, 'input', 'boxFastOrderRow' + noOfFirstEmptyRow);

						for (var j=0; j<sourceFields.length; j++) {
							targetFields[j].value = sourceFields[j].value;
						}
						document.getElementById('imgAvailability' + noOfFirstEmptyRow).setAttribute('src', document.getElementById('imgAvailability' + i).getAttribute('src'));
						document.getElementById('imgAvailability' + noOfFirstEmptyRow).setAttribute('alt', 'Verf\u00FCgbarkeit');
						document.getElementById('imgAvailability' + noOfFirstEmptyRow).setAttribute('title', 'Verf\u00FCgbarkeit');

						Forms.toggleLabelDisplay('inputCode' + noOfFirstEmptyRow, true);
						Forms.toggleLabelDisplay('inputCount' + noOfFirstEmptyRow, true);
						Forms.toggleLabelDisplay('inputName' + noOfFirstEmptyRow, true);
						Forms.toggleLabelDisplay('inputPrice' + noOfFirstEmptyRow, true);

						_private.fastOrderClearRow(i);

						noOfFirstEmptyRow++;
					}
				}
				else if (noOfFirstEmptyRow < 0) {
					noOfFirstEmptyRow = i;
				}
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * find the index of a value in a list of values
		 * 
		 * params:
		 *   value: the value to search for
		 *   list: the list of values to search in
		 * return value:
		 *   index of the value if found, -1 otherwise
		 */
		findValueInList: function(value, list) {
			for (var i=0; i<list.length; i++) {
				if (value == list[i]) {
					return i;
				}
			}
			return -1;
		},
		/*-----------------------------------------------------------------------------------------
		 * generate list of favorites and add them to div#containerFavorites
		 *
		 * prerequisities:
		 *   * div#containerFavorites must exist
		 *   * _private.menu.data must contain data of shop items
		 */
		generateFavorites: function() {
			var favorites = document.getElementById('containerFavorites');
			var naviLevel;

			if (!favorites) {
				return;
			}
			while (favorites.hasChildNodes()) {
				favorites.removeChild(favorites.firstChild);
			}
			_private.ERPCodes.length = 0;

			// generate items
			for (var i=0; i<_private.favorites.count; i++) {
				var index = -1;
				var item;

				for (var j=0; j<_private.data.count; j++) {
					if (_private.favorites.items[i] == _private.data.items[j].code) {
						index = j;
						break;
					}
				}
				if (index >= 0) {
					// favorite found in item list
					item = _private.generateItem(_private.data.items[index], 'favorites');
				}
				else {
					// favorite previously removed from item list
					item = _private.generateItemRemovedFromShop(_private.favorites.items[i]);
				}
				favorites.appendChild(item);
			}
			Images.renderImages();
			Images.onHoverHideDesc();
			Paging.renderPaging();
		},
		/*-----------------------------------------------------------------------------------------
		 * generate DOM for a single shop item
		 *
		 * params:
		 *   data: an object containing a set of data for the shop item
		 *   mode: string ('shop', 'search', 'favorites', 'basket', 'basketFast', 'order')
		 * return value:
		 *   an HTML object of the item
		 */
		generateItem: function(data, mode) {
			/*
				<div class="box2Col">
					<div class="boxProdTeaser boxTeaser">
						<div class="boxProdUL boxUL">
							<div class="boxProdLR boxLR">
								<div class="boxProdDescOnImage">
									<div class="boxProdDesc">
										<div class="boxProdDescText">
											<h1><span>Preislistenname1</span></h1>
											<h2><span>Hersteller</span></h2>
											<span>Preis <img></span>
										</div>
									</div>
									<div class="boxShopBasketLink">
										<span class="spanShopBasketLink">
											Preis <img>
											<img>
										</span>
									</div>
									<div class="boxProdImage boxImage">
										<img class="img2Col">
									</div>
								</div>
							</div>
						</div>
					</div>
				</div>
			*/
			var item = _private.createChild(null, 'div', 'box1Col');
			var node;
			var boxProdDescOnImage;
			var boxProdDescText;
			var spanLinks;

			// .boxProdTeaser.boxTeaser
			node = _private.createChild(item, 'div', 'boxProdTeaser boxTeaser');
			// ... > .boxProdUL.boxUL
			node = _private.createChild(node, 'div', 'boxProdUL boxUL');
			// ... > ... > .boxProdLR.boxLR
			node = _private.createChild(node, 'div', 'boxProdLR boxLR');
			// ... > ... > ... > .boxProdDescOnImage
			boxProdDescOnImage = _private.createChild(node, 'div', 'boxProdDescOnImage');
			// ... > ... > ... > ... > .boxProdDesc
			node = _private.createChild(boxProdDescOnImage, 'div', 'boxProdDesc');
			// ... > ... > ... > ... > ... > .boxProdDescText
			boxProdDescText = _private.createChild(node, 'div', 'boxProdDescText');

			// _30 -> Internetname1, _31 -> Internetname2
			if (data._30 || data._31) {
				node = _private.createChild(boxProdDescText, 'h1');
				node = _private.createChild(node, 'span');
				
				if (data._30 && data._31) {
					node.appendChild(document.createTextNode(_private.trim(data._30) + ', ' + _private.trim(data._31)));
				}
				else if (data._30) {
					node.appendChild(document.createTextNode(_private.trim(data._30)));
				}
				else {
					node.appendChild(document.createTextNode(_private.trim(data._31)));
				}
			}
			// _32 -> Hersteller, _84 -> Region
			if (data._32 || data._84) {
				node = _private.createChild(boxProdDescText, 'h2');
				node = _private.createChild(node, 'span');

				if (data._32 && data._84) {
					node.appendChild(document.createTextNode(_private.trim(data._32) + ', ' + _private.trim(data._84)));
				}
				else if (data._32) {
					node.appendChild(document.createTextNode(_private.trim(data._32)));
				}
				else {
					node.appendChild(document.createTextNode(_private.trim(data._84)));
				}
			}
			// _79 -> VEPreis
			spanLinks = _private.createChild(boxProdDescText, 'span');

			if (data._79 || data._79 == 0.00) { // VEPreis vorhanden oder Tagespreis
				if (data._79) { // VEPreis vorhanden
					spanLinks.appendChild(document.createTextNode(data.code + ' \u00B7 ' + _private.priceToString(_private.trim(data._79)) + ' \u20AC\u00A0\u00A0\u00A0'));
				}
				else { // Tagespreis
					spanLinks.appendChild(document.createTextNode(data.code + ' \u00B7 Tagespreis\u00A0\u00A0\u00A0'));
				}
				node = _private.createChild(spanLinks, 'img', 'imgCart');
				node.setAttribute('src', '/_images/cart.gif');
			}
			// show "delete favorite" icon if required (the "real" link will follow below)
			if (mode == 'favorites') {
				if (data._79) {
					spanLinks.appendChild(document.createTextNode(' '));
				}
				node = _private.createChild(spanLinks, 'img', 'imgDelete');
				node.setAttribute('src', '/_images/delete.gif');
			}
			// ... > ... > ... > ... > .boxShopBasketLink
			node = _private.createChild(boxProdDescOnImage, 'div');
			node.className = 'boxShopBasketLink';
			node.style.display = 'none';
			// _79 -> VEPreis
			spanLinks = _private.createChild(node, 'span', 'spanShopBasketLink');

			if (data._79 || data._79 == 0.00) { // VEPreis vorhanden oder Tagespreis
				node = _private.createChild(spanLinks, 'span');
				// _78 -> VE
				if (data._78) {
					node.setAttribute('title', _private.trim(data._78) + ' in den Warenkorb');
				}
				else {
					node.setAttribute('title', 'in den Warenkorb');	
				}
				YAHOO.util.Event.addListener(node, 'click', _private.addToBasket, data, true);

				if (data._79) { // VEPreis vorhanden
					node.appendChild(document.createTextNode(data.code + ' \u00B7 ' + _private.priceToString(_private.trim(data._79)) + ' \u20AC\u00A0\u00A0\u00A0'));
				}
				else { // Tagespreis
					node.appendChild(document.createTextNode(data.code + ' Tagespreis\u00A0\u00A0\u00A0'));
				}
				node = _private.createChild(node, 'img', 'imgCart');
				node.setAttribute('src', '/_images/cart.gif');
			}
			// add "delete favorite" link if not required
			if (mode == 'favorites') {
				if (data._79) {
					spanLinks.appendChild(document.createTextNode(' '));
				}
				node = _private.createChild(spanLinks, 'span');
				node.setAttribute('title', 'diesen Favoriten l\u00F6schen');
				YAHOO.util.Event.addListener(node, 'click', function() {
					Favorites.deleteFavorite(data.code);
					_private.updateFavorites(data.code, false);
					_public.showFavorites();
				});
				node = _private.createChild(node, 'img', 'imgDelete');
				node.setAttribute('src', '/_images/delete.gif');
			}
			// ... > ... > ... > ... > .boxProdImage.boxImage
			node = _private.createChild(boxProdDescOnImage, 'div', 'boxProdImage boxImage');
			node = _private.createChild(node, 'img', 'img1Col');

			// _43 -> Artikelbild1, _43W -> Breite, _43H -> Hoehe
			if (data._43) {
				var mediaSettings  = Images.getSettings();
				var pagingSettings = Paging.getSettings();

				if (pagingSettings.largeImages) {
					node.setAttribute('src', mediaSettings.folder + data._43 + '.' + mediaSettings.variantLarge + mediaSettings.suffix);
				}
				else {
					node.setAttribute('src', mediaSettings.folder + data._43 + '.' + mediaSettings.variantSmall + mediaSettings.suffix);
				}
				node.setAttribute('width', data._43W);
				node.setAttribute('height', data._43H);
			}
			else {
				node.setAttribute('src', '/_images/spacer.gif');
				node.setAttribute('width', 240);
				node.setAttribute('height', 240);
			}
			if (data.code) {
				node.setAttribute('id', 'img/' + data.code + '/' + mode);
				YAHOO.util.Event.addListener(node, 'click', function() {
					_private.getItemDetail(data.code, mode);
				});
				_private.ERPCodes[_private.ERPCodes.length] = data.code;
			}
			// _31 -> Internetname2
			if (data._31 && data.code) {
				node.setAttribute('alt', _private.trim(data._31) + ' (Art.Nr. ' + data.code + ')');
				node.setAttribute('title', _private.trim(data._31) + ' (Art.Nr. ' + data.code + ')');
			}
			// 102 -> Internet-Rabatt
			if (data._102 && data._102 > 0) {
				node = _private.createChild(boxProdDescOnImage, 'div', 'boxRebate');
				node.innerHTML = _private.trim(data._102) + '%';
			}
			return item;
		},
		/*-----------------------------------------------------------------------------------------
		 * generate detail view of a single item
		 * 
		 * params:
		 *   data: an object containing information on the item to be generated
		 *   mode: string ('shop', 'search', 'favorites', 'basket', 'basketFast', 'order')
		 */
		generateItemDetail: function(data, mode) {
			/*
				<div class="box4Col">
					<div class="boxProdDetail boxDetail">
						<h1>Preislistenname1</h1>
						<h2>Hersteller</h2>

						Artikeltextkurz

						<b>Code</b> &middot; Massangabe &middot; BezeichnungEinheit
						STPreis [1] &middot; VEPreis [VE] &middot; MEPreis [ME]

						<img> Verfuegbarkeit

						...
					</div>
				</div>
				<div class="box2Col">
					<div class="boxProdDetail boxDetail">
						...
					</div>
				</div>
			*/
			var callback = {
				success: function(o) {
					var image;
					var imageNo = 1;
					var obj;
					var container;

					Content.replaceContent(o.responseText);

					// quit, if access denied page has been loaded ------------
					if (!document.getElementById('containerProdDetail')) {
						return;
					}
					// fill in left column ------------------------------------
					// _102 -> Internet-Rabatt
					if (!data._102 || data._102 <= 0) {
						var rebate = document.getElementById('boxRebateDetail');

						rebate.parentNode.removeChild(rebate);
					}
					else {
						var rebate = document.getElementById('boxRebateDetail');

						rebate.innerHTML = _private.trim(data._102) + '%';						
					}
					// _30 -> Internetname1, _31 -> Internetname2
					if (data._30 && data._31) {
						document.getElementById('JSON_H1').innerHTML = _private.trim(data._30) + ', ' + _private.trim(data._31);
					}
					else if (data._30) {
						document.getElementById('JSON_H1').innerHTML = _private.trim(data._30);
					}
					else if (data._31) {
						document.getElementById('JSON_H1').innerHTML = _private.trim(data._31);
					}
					// _32 -> Hersteller, _84 -> Region
					if (data._32 && data._84) {
						document.getElementById('JSON_H2').innerHTML = _private.trim(data._32) + ', ' + _private.trim(data._84);
					}
					else if (data._32) {
						document.getElementById('JSON_H2').innerHTML = _private.trim(data._32);
					}
					else if (data._84) {
						document.getElementById('JSON_H2').innerHTML = _private.trim(data._84);
					}
					// _34 -> Artikeltextkurz
					if (data._34) {
						document.getElementById('JSON_TEXT').innerHTML = _private.trim(data._34);
					}
					if (data.code) {
						document.getElementById('JSON_CODE').innerHTML = _private.trim(data.code);
					}
					// _42 -> Massangabe
					if (data._42) {
						document.getElementById('JSON_UNITSIZE').innerHTML = _private.trim(data._42);
					}
					// _55 -> BezeichnungEinheit
					if (data._55) {
						document.getElementById('JSON_UNITNAME').innerHTML = _private.trim(data._55);
					}
					/*-----------------------------------------------------------------------------
					 * The elements 'JSON_STPRICE', 'JSON_VEPRICE', 'JSON_VE', 'JSON_MEPRICE', and
					 * 'JSON_ME' have the same parent 'JSON_PRICES'. If all prices are 0.00 (this
					 * indicates a daily price), then the inner HTML of 'JSON_PRICES' will be
					 * overwritten. Thus be careful, when editing this code.
					 */
					// _77 -> STPreis
					if (data._77) {
						document.getElementById('JSON_STPRICE').innerHTML = _private.priceToString(_private.trim(data._77));
					}
					else if (data._77 == 0.00 && data._79 == 0.00 && data._81 == 0.00) {
						document.getElementById('JSON_PRICES').innerHTML = 'Tagespreis';
					}
					// _79 -> VEPreis
					if (data._79) {
						document.getElementById('JSON_VEPRICE').innerHTML = _private.priceToString(_private.trim(data._79));
					}
					// _78 -> VE
					if (data._79 && data._78) {
						document.getElementById('JSON_VE').innerHTML = _private.trim(data._78);
					}
					// _81 -> MEPreis
					if (data._81) {
						document.getElementById('JSON_MEPRICE').innerHTML = _private.priceToString(_private.trim(data._81));
					}
					// _80 -> ME
					if (data._81 && data._80) {
						document.getElementById('JSON_ME').innerHTML = _private.trim(data._80);
					}
					/* end of output of price information ---------------------------------------*/
					// _57 -> Vorbestellung, _63 -> Verfuegbarkeit (_57 overrides _63)
					if (data._57 && data._57 == 'Ja') {
						var image = document.getElementById('JSON_AVAILIMAGE');

						if (image) {
							image.parentNode.removeChild(image);
						}
						document.getElementById('JSON_AVAILTEXT').innerHTML = '<a class="aPreOrder"><img src="/_images/calendar.gif" alt="" title=""> Diesen Artikel k\u00F6nnen Sie vorbestellen.</a>';
						_public.preOrderAddListeners();
					}
					else if (typeof data._63 != 'undefined') {
						document.getElementById('JSON_AVAILIMAGE').setAttribute('src', '/_images/availability' + _private.trim(data._63) + '.gif');
						
						switch (data._63) {
							case 0:
								document.getElementById('JSON_AVAILTEXT').innerHTML = 'nicht verf&uuml;gbar';
								break;
							case 1:
								document.getElementById('JSON_AVAILTEXT').innerHTML = 'begrenzt verf&uuml;gbar';
								break;
							case 2:
								document.getElementById('JSON_AVAILTEXT').innerHTML = 'sofort verf&uuml;gbar';
								break;
						}
					}
					// add-to-basket-link
					if (data._78) {
						document.getElementById('ADD_TO_BASKET').innerHTML = '<input type="text" name="" value="' + _private.trim(data._78) + '" class="text" id="inputAddToBasket">';
					}
					else {
						document.getElementById('ADD_TO_BASKET').innerHTML = '<input type="text" name="" value="1" class="text" id="inputAddToBasket">';
					}
					YAHOO.util.Event.removeListener('aAddToBasket');
					YAHOO.util.Event.addListener('aAddToBasket', 'click', _private.addToBasket, {
						code: data.code,
						readInput: true
					}, true);
					// product functions
					if (_private.isFavorite(data.code)) {
						document.getElementById('FAV_TEXT').innerHTML = 'Produkt aus Favoritenliste entfernen';
						YAHOO.util.Event.removeListener('aProdFuncsFav');
						YAHOO.util.Event.addListener('aProdFuncsFav', 'click', function() {
							Favorites.deleteFavorite(data.code);
							_private.updateFavorites(data.code, false);

							switch (mode) {
								case 'shop':
								case 'search':
								case 'basket':
								case 'basketFast':
								case 'order':
									// if in shop/search/basket/basketFast/order view -> update item details
									_private.generateItemDetail(data, mode);
									break;
								case 'favorites':
									// if in favorites view -> return to favorite list after removal
									Content.loadFavorites();
									break;
								default:
									DEBUG('warning: illegal value \'' + mode + '\' of parameter mode');
							}
						});
					}
					else {
						document.getElementById('FAV_TEXT').innerHTML = 'Produkt als Favorit speichern';
						YAHOO.util.Event.removeListener('aProdFuncsFav');
						YAHOO.util.Event.addListener('aProdFuncsFav', 'click', function() {
							Favorites.setFavorite(data.code);
							_private.updateFavorites(data.code, true);
							_private.generateItemDetail(data, mode);
						});
					}

/*
					YAHOO.util.Event.removeListener('aProdFuncsFurther');
					YAHOO.util.Event.addListener('aProdFuncsFurther', 'click', function() {
						
					});
					YAHOO.util.Event.removeListener('aProdFuncsInfo');
					YAHOO.util.Event.addListener('aProdFuncsInfo', 'click', function() {
						
					});
*/
		
					// fill in right column -----------------------------------
					_private.media = Images.getSettings();

					// _43 -> Artikelbild1, _43W -> Breite, _43H -> Hoehe
					if (data._43 && data._43W && data._43H) {
						image = document.getElementById('JSON_IMAGE' + imageNo++);
						image.setAttribute('src', _private.media.folder + data._43 + '.' + _private.media.variantTiny + _private.media.suffix);
						image.setAttribute('width', data._43W);
						image.setAttribute('height', data._43H);
						container = YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol');
						YAHOO.util.Event.removeListener(container);
						YAHOO.util.Event.addListener(container, 'mouseover', function() {
							var links = YAHOO.util.Dom.getElementsByClassName('selected', 'div', YAHOO.util.Dom.getAncestorByClassName(this.container, 'boxVianiGallery'));

							for (var i=0; i<links.length; i++) {
								YAHOO.util.Dom.removeClass(links[i], 'selected');
							}
							YAHOO.util.Dom.addClass(this.link, 'selected');
							_private.showItemDetailImage({
								src: _private.media.folder + data._43 + '.' + _private.media.variantLarge + _private.media.suffix,
								width: data._43W,
								height: data._43H
							});
						}, {
							link: YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol')
						}, true);
					}
					// _47 -> Artikelbild2, _47W -> Breite, _47H -> Hoehe
					if (data._47 && data._47W && data._47H) {
						image = document.getElementById('JSON_IMAGE' + imageNo++);
						image.setAttribute('src', _private.media.folder + data._47 + '.' + _private.media.variantTiny + _private.media.suffix);
						image.setAttribute('width', data._47W);
						image.setAttribute('height', data._47H);
						container = YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol');
						YAHOO.util.Event.removeListener(container);
						YAHOO.util.Event.addListener(container, 'mouseover', function() {
							var links = YAHOO.util.Dom.getElementsByClassName('selected', 'div', YAHOO.util.Dom.getAncestorByClassName(this.container, 'boxVianiGallery'));

							for (var i=0; i<links.length; i++) {
								YAHOO.util.Dom.removeClass(links[i], 'selected');
							}
							YAHOO.util.Dom.addClass(this.link, 'selected');
							_private.showItemDetailImage({
								container: container,
								src: _private.media.folder + data._47 + '.' + _private.media.variantLarge + _private.media.suffix,
								width: data._47W,
								height: data._47H
							});
						}, {
							link: YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol')
						}, true);
					}
					// _49 -> Artikelbild3, _49W -> Breite, _49H -> Hoehe
					if (data._49 && data._49W && data._49H) {
						image = document.getElementById('JSON_IMAGE' + imageNo++);
						image.setAttribute('src', _private.media.folder + data._49 + '.' + _private.media.variantTiny + _private.media.suffix);
						image.setAttribute('width', data._49W);
						image.setAttribute('height', data._49H);
						container = YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol');
						YAHOO.util.Event.removeListener(container);
						YAHOO.util.Event.addListener(container, 'mouseover', function() {
							var links = YAHOO.util.Dom.getElementsByClassName('selected', 'div', YAHOO.util.Dom.getAncestorByClassName(this.container, 'boxVianiGallery'));

							for (var i=0; i<links.length; i++) {
								YAHOO.util.Dom.removeClass(links[i], 'selected');
							}
							YAHOO.util.Dom.addClass(this.link, 'selected');
							_private.showItemDetailImage({
								src: _private.media.folder + data._49 + '.' + _private.media.variantLarge + _private.media.suffix,
								width: data._49W,
								height: data._49H
							});
						}, {
							link: YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol')
						}, true);
					}
					// _51 -> Artikelbild4, _51W -> Breite, _51H -> Hoehe
					if (data._51 && data._51W && data._51H) {
						image = document.getElementById('JSON_IMAGE' + imageNo++);
						image.setAttribute('src', _private.media.folder + data._51 + '.' + _private.media.variantTiny + _private.media.suffix);
						image.setAttribute('width', data._51W);
						image.setAttribute('height', data._51H);
						container = YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol');
						YAHOO.util.Event.removeListener(container);
						YAHOO.util.Event.addListener(container, 'mouseover', function() {
							var links = YAHOO.util.Dom.getElementsByClassName('selected', 'div', YAHOO.util.Dom.getAncestorByClassName(this.container, 'boxVianiGallery'));

							for (var i=0; i<links.length; i++) {
								YAHOO.util.Dom.removeClass(links[i], 'selected');
							}
							YAHOO.util.Dom.addClass(this.link, 'selected');
							_private.showItemDetailImage({
								src: _private.media.folder + data._51 + '.' + _private.media.variantLarge + _private.media.suffix,
								width: data._51W,
								height: data._51H
							});
						}, {
							link: YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol')
						}, true);
					}
					// remove empty image containers
					for (var i=imageNo; i<=4; i++) {
						var toBeRemoved = document.getElementById('JSON_IMAGE' + i);

						toBeRemoved = YAHOO.util.Dom.getAncestorByClassName(toBeRemoved, 'boxHalfCol')
						toBeRemoved.parentNode.removeChild(toBeRemoved);
					}
					// add large image (or remove gallery, if there is no large image)
					image = document.getElementById('JSON_IMAGE1');

					if (image) {
						var src = image.getAttribute('src');
						var index = src.lastIndexOf('.' + _private.media.variantTiny + _private.media.suffix);

						_private.showItemDetailImage({
							src: src.substring(0, index) + '.' + _private.media.variantLarge + _private.media.suffix,
							width: image.getAttribute('width'),
							height: image.getAttribute('height')
						});
						YAHOO.util.Dom.addClass(YAHOO.util.Dom.getAncestorByClassName(image, 'boxHalfCol'), 'selected');
					}
					else {
						var toBeRemoved = document.getElementById('JSON_IMAGE');

						toBeRemoved = YAHOO.util.Dom.getAncestorByClassName(toBeRemoved, 'boxVianiGallery');
						toBeRemoved.parentNode.removeChild(toBeRemoved);
					}
					_private.configureDetailPaging(data.code, mode);
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting item detail template timed out - retrying');
						
						switch (mode) {
							case 'shop':
							case 'search':
							case 'favorites':
							case 'order':
								YAHOO.util.Connect.asyncRequest('GET', '/_shop/getItemDetail.html?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
								break;
							case 'basket':
							case 'basketFast':
								YAHOO.util.Connect.asyncRequest('GET', '/_shop/getItemDetailBasket.html?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			// replace content and render images ----------
			switch (mode) {
				case 'shop':
				case 'search':
				case 'favorites':
				case 'order':
					yuiLoader.show();
					YAHOO.util.Connect.asyncRequest('GET', '/_shop/getItemDetail.html?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					break;
				case 'basket':
				case 'basketFast':
					yuiLoader.show();
					YAHOO.util.Connect.asyncRequest('GET', '/_shop/getItemDetailBasket.html?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					break;
				default:
					DEBUG('warning: illegal value \'' + mode + '\' of parameter mode');
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * generate a place-holder item, if one of the user's favorites has been removed from the
		 * shop
		 *
		 * params:
		 *   code: the ERP code of the item removed from the shop
		 */
		generateItemRemovedFromShop: function(code) {
			var item = document.createElement('div');
			var html = '';
			var hint = 'Art.Nr. ' + code + ' f&uuml;hren wir nicht mehr.';

			html += '<div class="boxProdTeaser boxTeaser">';
			html +=   '<div class="boxProdUL boxUL">';
			html +=     '<div class="boxProdLR boxLR">';
			html +=       '<div class="boxProdDescOnImage">';
			html +=         '<div class="boxProdDesc">';
			html +=           '<div class="boxProdDescText">';
			html +=             '<span>' + hint + '</span>';
			html +=           '</div>';
			html +=         '</div>';
			html +=         '<div class="boxShopBasketLink">'                           // The span may be removed,
			html +=           '<span class="spanShopBasketLink">' + hint + '</span>';   // but the div is required
			html +=         '</div>';                                                   // anyway!
			html +=         '<div class="boxProdImage boxImage">';
			html +=           '<img src="/blobs/prodnotfound.' + _private.media.variantLarge + _private.media.suffix + '" ';
			html +=             'alt="' + hint + ' Klicken Sie hier zum L&ouml;schen dieses Favoriten." ';
			html +=             'title="' + hint + ' Klicken Sie hier zum L&ouml;schen dieses Favoriten." ';
			html +=             'width="200" height="200" class="img2Col" id="imgRemovedItem' + code + '">';
			html +=         '</div>';
			html +=       '</div>';
			html +=     '</div>';
			html +=   '</div>';
			html += '</div>';

			item.innerHTML = html;
			item.className = 'box2Col boxRemovedItem';

			YAHOO.util.Event.onContentReady('imgRemovedItem' + code, function() {
				var id = this.getAttribute('id');
				var code = id.substring(14, id.length); // remove prefix 'imgRemovedItem' from id

				YAHOO.util.Event.addListener(this, 'click', function() {
					Favorites.deleteFavorite(code);
					_private.updateFavorites(code, false);
					Content.loadFavorites();
				});
			});

			return item;
		},
		/*-----------------------------------------------------------------------------------------
		 * generate shop items linked to selected node
		 *
		 * params:
		 *   nodeId: ID of the node for which the list of items is to be generated
		 * return value:
		 *   number of items generated, -1 in case of an error
		 * preconditions:
		 *   variables _private.menu.parentNodeId and _private.menu.nodeId must be set
		 */
		generateItems: function(nodeId) {
			var containerShop = document.getElementById('containerShop');
			var node = null;
			var groups = [nodeId];
			var item;
			var count = 0;

			if (!containerShop || typeof nodeId != 'number' || nodeId < 0) {
				return -1;
			}
			// find the node with ID nodeId
			for (var i=0; i<_private.menu.nodes.length; i++) {
				if (_private.menu.nodes[i].nodeId == nodeId) {
					node = _private.menu.nodes[i];
					break;
				}
			}
			if (!node) {
				return -1;
			}
			// initialize the number of items on this node
			_private.ERPCodes.length = 0;

			// get list of commodity groups to be shown on this node
			if (node.fsns) {
				// looping nodes once is sufficient, since the list of nodes is pre-ordered
				for (var i=0; i<_private.menu.nodes.length; i++) {
					if (_private.findValueInList(_private.menu.nodes[i].parentNodeId, groups) >= 0) {
						groups[groups.length] = _private.menu.nodes[i].nodeId;
					}
				}
			}
			// generate items
			for (var i=0; i<_private.data.items.length; i++) {
				var show = false;

				if (_private.data.items[i].CG) {
					for (var j=0; j<groups.length; j++) {
						if (_private.findValueInList(groups[j], _private.data.items[i].CG) >= 0) {
							show = true;
						}
					}
					if (show) {
						item = _private.generateItem(_private.data.items[i], 'shop');
						containerShop.appendChild(item);
						count++;
					}
				}
			}
			Images.renderImages();
			Images.onHoverHideDesc();

			return count;
		},
		/*-----------------------------------------------------------------------------------------
		 * generate a single level of the navigation
		 *
		 * params:
		 *   level: level of the navigation
		 *   count: number of items mapped to current node
		 * preconditions:
		 *   variables _private.menu.level and _private.menu.nodeId must be set
		 *   div#boxNavi must exist
		 *   div#boxNaviLevel<level> must not exist
		 */
		generateNaviLevel: function(level, count) {
			/*
				<div id="boxNaviLevel<level>">
					{<a class="aNavi">...</a>}*
					<a class="aNavi selected">...</a>
					{<a class="aNavi">...</a>}*
				</div>
			*/
			var naviLevel;
			var newLink;
			var obj;

			// create navigation level
			naviLevel = document.createElement('div');
			naviLevel.setAttribute('id', 'boxNaviLevel' + level);
			document.getElementById('boxNavi').appendChild(naviLevel);

			for (var i=0; i<_private.menu.nodes.length; i++) {
				if (   _private.menu.nodes[i].level == level
				    && _private.isCurrentMenuNode(_private.menu.nodes[i])) {
					newLink = document.createElement('a');

					if (_private.isCurrentMenuNodeOnPath(_private.menu.nodes[i])) {
						newLink.className = 'aNavi selected';

						if (_private.menu.nodes[i].nodeId == _private.menu.nodeId) {
							newLink.appendChild(document.createTextNode(_private.menu.nodes[i].label + ' (' + count + (count == 1 ? 'Produkt' : ' Produkte') + ')'));
						}
						else {
							newLink.appendChild(document.createTextNode(_private.menu.nodes[i].label));
						}
					}
					else {
						newLink.className = 'aNavi';
						newLink.appendChild(document.createTextNode(_private.menu.nodes[i].label));
					}
					/*
					 * special nodes (id, German name, English name):
					 *
					 *   (1294, Neuheiten,    Innovations)
					 *   (1317, VianiSeasons, VianiSeasons)
					 */
					if (   _private.menu.nodes[i].nodeId == 1294
					    || _private.menu.nodes[i].nodeId == 1317) {
						YAHOO.util.Dom.addClass(newLink, 'aNaviSpecial');
					}
					obj = {
						id: _private.menu.nodes[i].nodeId
					}
					YAHOO.util.Event.addListener(newLink, 'click', _private.showNode, obj, true);
					naviLevel.appendChild(newLink);
					naviLevel.appendChild(document.createTextNode(' '));
				}
			}
			if (naviLevel.hasChildNodes()) {
				YAHOO.util.Dom.addClass(naviLevel.lastChild, 'last');
			}
			else {
				document.getElementById('boxNavi').removeChild(naviLevel);
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * get details of an item
		 *
		 * params:
		 *   code: ERP code of the item
		 *   mode: string ('shop', 'search', 'favorites', 'basket', 'basketFast', 'order')
		 */
		getItemDetail: function(code, mode) {
			var callback = {
				success: function(o) {
					var data;

					try {
						data = YAHOO.lang.JSON.parse(o.responseText);
					} 
					catch (e) {
						DEBUG('failed to parse item data: ' + e.message);
						yuiLoader.hide();
						return;
					}
					_private.generateItemDetail(data.item, mode);
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting item details timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/itemData.json?erp_code=' + code + '&xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			}

			yuiLoader.show();
			YAHOO.util.Connect.asyncRequest('GET', '/_json/itemData.json?erp_code=' + code + '&xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
		},
		/*-----------------------------------------------------------------------------------------
		 * get node object for a node with a given ID
		 * 
		 * params:
		 *   nodeId: ID of the node for which the object is to be retrieved
		 * return value:
		 *   an object containing node data, if a node with the given ID was found, null otherwise
		 */
		getNodeById: function(nodeId) {
			for (var i=0; i<_private.menu.nodes.length; i++) {
				if (nodeId == _private.menu.nodes[i].nodeId) {
					return _private.menu.nodes[i];
				}
			}
			return null;
		},
		/*-----------------------------------------------------------------------------------------
		 * check if a given node has subnodes
		 *
		 * params:
		 *   nodeId: ID of the node to check
		 * return value:
		 *   true, if the node has subnodes, false otherwise
		 */
		hasSubnodes: function(nodeId) {
			for (var i=0; i<_private.menu.nodes.length; i++) {
				if (_private.menu.nodes[i].parentNodeId == nodeId) {
					return true;
				}
			}
			return false;
		},
		/*-----------------------------------------------------------------------------------------
		 * init the shop by displaying the first commodity group and initializing the paging
		 *
		 * params:
		 *   nodeId (optional): ID of the node to be shown, if not given the first node, which is
		 *                      not the node for new items, will be shown
		 */
		initDisplay: function(nodeId) {
			if (nodeId && nodeId > 0) {
				_private.showNode(nodeId);
			}
			else {
				var id;

				for (i=0; i<_private.menu.nodes.length; i++) {
					if (_private.menu.nodes[i].label != 'Neuheiten') {
						id = _private.menu.nodes[i].nodeId;
						break;
					}
				}
				_private.showNode(id);
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * determine if a given node is to be shown in the current menu tree
		 * 
		 * params:
		 *   node: node to check
		 * return value:
		 *   true, if the node is to be shown, false otherwise
		 */
		isCurrentMenuNode: function(node) {
			if (!node) {
				return false;
			}
			if (node.parentNodeId == -1) {
				return true;
			}
			if (!(node = _private.getNodeById(node.parentNodeId))) {
				return false;
			}
			return _private.isCurrentMenuNodeOnPath(node);
		},
		/*-----------------------------------------------------------------------------------------
		 * determine if a given node is on the path to the current node
		 * 
		 * params:
		 *   node: node to check
		 * return value:
		 *   true, if the node is on the path to the current node, false otherwise
		 */
		isCurrentMenuNodeOnPath: function(node) {
			var pathNode = _private.getNodeById(_private.menu.nodeId);

			if (!node) {
				return false;
			}
			for (var i=_private.menu.level; pathNode && i>node.level; i--) {
				pathNode = _private.getNodeById(pathNode.parentNodeId);
			}
			return (pathNode && pathNode.nodeId == node.nodeId);
		},
		/*-----------------------------------------------------------------------------------------
		 * check if an item with a given ERP code is a member of the user's favorites
		 *
		 * params:
		 *   code: the ERP code of the item
		 * return value:
		 *   boolean indicating, if the item is a favorite or not
		 */
		isFavorite: function(code) {
			for (var i=0; i<_private.favorites.items.length; i++) {
				if (code == _private.favorites.items[i]) {
					return true;
				}
			}
			return false;
		},
		/*-----------------------------------------------------------------------------------------
		 * create a string like "<euro>,<cent>" with two digits to the right-hand-side of the comma
		 */
		priceToString: function(price) {
			var string;

			if (price.toString().indexOf('.') >= 0) {
				string = (price.toString().replace(/\./, ',') + '00');
				string = string.substring(0, string.indexOf(',') + 3);
			}
			else {
				string = price.toString() + ',00';
			}
			return string;
		},
		/*-----------------------------------------------------------------------------------------
		 * remove all navigations levels with a depth of 3 or more
		 */
		removeNavi: function() {
			var elem;
			var i = _private.menuDepthAboveShop + 1;
			
			while ((elem = document.getElementById('boxNaviLevel' + i))) {
				elem.parentNode.removeChild(elem);
				i++;
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * remove shop items
		 */
		removeItems: function() {
			var containerShop = document.getElementById('containerShop');

			if (!containerShop) {
				return;
			}
			while (containerShop.hasChildNodes()) {
				containerShop.removeChild(containerShop.firstChild);
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * set _private.menu.depth
		 *
		 * preconditions:
		 *   variables _private.menu.nodeId must be set
		 */
		setMenuDepth: function() {
			var depth = _private.menuDepthAboveShop;
			var node = _private.getNodeById(_private.menu.nodeId);

			if (node) {
				depth++;
			}
			// count menu levels above current node
			while (node && node.parentNodeId >= 0) {
				node = _private.getNodeById(node.parentNodeId);
				depth++;
			}
			_private.menu.level = depth;

/*
			// count menu levels below current node
			node = _private.getNodeById(_private.menu.nodeId);

			while (node && node.redirectNodeId >= 0) {
				node = _private.getNodeById(node.redirectNodeId);
				depth++;
			}
*/
			// check, if there are subnodes of the current node
			if (_private.hasSubnodes(_private.menu.nodeId)) {
				depth++;
			}
			_private.menu.depth = depth;
		},
		/*-----------------------------------------------------------------------------------------
		 * set variables _private.menu.parentNodeId and _private.menu.nodeId considering
		 * redirects
		 *
		 * params:
		 *   id: ID of node clicked by user
		 */
		setNodeIds: function(id) {
			for (var i=0; i<_private.menu.nodes.length; i++) {
				if (_private.menu.nodes[i].nodeId == id) {
					if (_private.menu.nodes[i].redirectNodeId >= 0) {
						// redirect -> recursion
						_private.setNodeIds(_private.menu.nodes[i].redirectNodeId);
					}
					else {
						// no redirect -> save IDs
						_private.menu.parentNodeId = _private.menu.nodes[i].parentNodeId;
						_private.menu.nodeId       = id;
						_private.setMenuDepth();
					}
					return;
				}
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * replace large image in product detail
		 *
		 * params:
		 *   obj: an object containing src, width, and height attributes of the image
		 */
		showItemDetailImage: function(obj) {
			var image = document.getElementById('JSON_IMAGE');
			var parent = image.parentNode;
			var newImage;

			if (image.getAttribute('src') != obj.src) {
				newImage = document.createElement('img');
				newImage.className = 'img2Col';
				newImage.setAttribute('id', 'JSON_IMAGE');
				newImage.setAttribute('src', obj.src);
				newImage.setAttribute('width', obj.width);
				newImage.setAttribute('height', obj.height);
				parent.removeChild(image);
				parent.appendChild(newImage);
				Images.renderImages();
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * initialize/update navigation and content
		 *
		 * params:
		 *   id: either numerical ID of node clicked by user or an object containing the ID (as
		 *       attribute .id)
		 */
		showNode: function(id) {
			// event handler passes an object, initial call passes numerical id
			if (typeof id == 'object') {
				id = this.id;
			}
			if (!document.getElementById('containerShop')) {
				Content.loadShop(id);
			}
			else {
				_private.setNodeIds(id);
				_private.removeNavi();
				_private.removeItems();
				_private.noOfProds = _private.generateItems(_private.menu.nodeId);

				for (var i=_private.menuDepthAboveShop+1; i<=_private.menu.depth; i++) {
					_private.generateNaviLevel(i, _private.noOfProds);
				}
				Paging.renderPaging();
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * remove leading and trailing white space from a string
		 *
		 * params:
		 *   string: the string to trim
		 */
		trim: function(string) {
			return string.toString().replace(/^\s*/, '').replace(/\s*$/, '');
		},
		/*-----------------------------------------------------------------------------------------
		 * update list of favorites and no. of favorites
		 *
		 * params:
		 *   code: ERP code of favorite to be added to/removed from list
		 *   add:  boolean (true: add favorite, false: remove favorite)
		 * prerequisities:
		 *   * the list of ERP codes of the favorites should be ordered ascendingly, otherwise one
		 *     might get double entries if trying to add an item, that is already a favorite
		 */
		updateFavorites: function(code, add) {
			if (add) {
				// add item to list of favorites
				if (_private.favorites.count > 0) {
					if (parseInt(code.replace(/^0*/, '')) > parseInt(_private.favorites.items[_private.favorites.count-1].replace(/^0*/, ''))) { // treat values as numbers
						_private.favorites.items[_private.favorites.count] = code;
						_private.favorites.count++;
					}
					else {
						for (var i=0; i<_private.favorites.count; i++) {
							if (parseInt(code.replace(/^0*/, '')) < parseInt(_private.favorites.items[i].replace(/^0*/, ''))) { // treat values as numbers
								for (var j=_private.favorites.count; j>i; j--) {
									_private.favorites.items[j] = _private.favorites.items[j-1];
								}
								_private.favorites.items[i] = code;
								_private.favorites.count++;
								break;
							}
							else if (code == _private.favorites.items[i]) {
								break;
							}
						}
					}
				}
				else {
					_private.favorites.items[0] = code;
					_private.favorites.count = 1;
				}
			}
			else {
				// remove item from list of favorites
				for (var i=0; i<_private.favorites.count; i++) {
					if (code == _private.favorites.items[i]) {
						for (var j=i; j<_private.favorites.count-1; j++) {
							_private.favorites.items[j] = _private.favorites.items[j+1];
						}
						_private.favorites.count--;
						_private.favorites.items.length--;
						break;
					}
				}
			}
			document.getElementById('spanNoOfFavorites').innerHTML = _private.favorites.count;
		}
	}

	// public functions ===========================================================================
	var _public = {
		/*-----------------------------------------------------------------------------------------
		 * display the items a product search returned
		 *
		 * params:
		 *   results: an array of item data objects
		 */
		displaySearchResults: function(results) {
			var shop = document.getElementById('containerShop');
			var selected;
			var text;

			// remove items, remove class selected from shop node links
			if (shop) {
				_private.removeItems();
			}
			for (var i=_private.menuDepthAboveShop+1; i<=_private.menu.depth; i++) {
				selected = YAHOO.util.Dom.getElementsByClassName('selected', 'a', 'boxNaviLevel' + i);

				for (var j=0; j<selected.length; j++) {
					YAHOO.util.Dom.removeClass(selected[j], 'selected');

					if ((text = selected[j].innerHTML.match(/ \(\d* Produkte\)$/))) {
						selected[j].innerHTML = selected[j].innerHTML.substring(0, selected[j].innerHTML.indexOf(text));
					}
				}
			}
			// display search results
			if (_private.searchResults.length == 0) {
				if (shop) {
					shop.innerHTML =
						'<div class="spacer"></div>'
						+ '<div class="box6Col">'
						+ '<h1>Leider konnten keine Produkte gefunden werden</h1>'
						+ 'Bitte beachten Sie, dass nur solche Produkte angezeigt werden, die alle '
						+ 'Suchbegriffe enthalten, die Sie angegeben haben.'
						+ '</div>'
						+ '<div class="doublespacer"></div>';
				}
			}
			else {
				for (var i=0; i<_private.searchResults.length; i++) {
					shop.appendChild(_private.generateItem(_private.searchResults[i], 'search'));
				}
				Images.renderImages();
				Images.onHoverHideDesc();
			}
			Paging.renderPaging();
		},
		/*-----------------------------------------------------------------------------------------
		 * initialize fast order display
		 */
		fastOrder: function() {
			if (!_private.data) {
				var callback = {
					success: function(o) {
						try {
							_private.data = YAHOO.lang.JSON.parse(o.responseText);
						} 
						catch (e) {
							DEBUG('failed to parse JSON file containing item data: ' + e.message);
							yuiLoader.hide();
							return;
						}
						_public.fastOrder(); // recall this function with _private.data set
						yuiLoader.hide();
					},
					failure: function(o) {
						if (o.status == -1) {
							DEBUG('reading JSON file containing item data timed out - retrying');
							YAHOO.util.Connect.asyncRequest('GET', '/_json/shopData.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
						}
						else {
							yuiLoader.hide();
						}
					},
					timeout: 30000
				};

				YAHOO.util.Connect.asyncRequest('GET', '/_json/shopData.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
			else {
				if (_private.menu) {
					// set system variables
					_private.menu.depth = _private.menuDepthAboveShop + 1;
					_private.menu.level = _private.menuDepthAboveShop + 1;
					_private.menu.nodeId = -1;
					_private.menu.parentNodeId = -1;
					_private.noOfProds = 0;

					// update navigation
					_private.removeNavi();
					_private.generateNaviLevel(_private.menuDepthAboveShop + 1);
				}
				// add handlers to input fields (item names, item counts)
				_private.fastOrderAddFieldListeners();
				
				// add handlers to links
				YAHOO.util.Event.addListener('aAddFields', 'click', _private.fastOrderAddFields);
				YAHOO.util.Event.addListener('aResetForm', 'click', _private.fastOrderResetForm);
				YAHOO.util.Event.addListener('aGoToBasket', 'click', _private.fastOrderGoToBasket);
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * wrapper for internal function: display detailled information on a given item
		 *
		 * params:
		 *   code: ERP code of the item
		 *   mode: shop mode ('shop', 'favorites')
		 */
		getItemDetail: function(code, mode) {
			_private.getItemDetail(code, mode);
		},
		/*-----------------------------------------------------------------------------------------
		 * get the ID of the current node
		 *
		 * return value:
		 *   the ID of the current node or -1 (if in fast order form), if the shop has been
		 *   initialized, -2 otherwise
		 */
		getNodeId: function() {
			return _private.menu ? _private.menu.nodeId : -2;
		},
		/*-----------------------------------------------------------------------------------------
		 * get JSON data, build array of items, and init shop display
		 *
		 * params:
		 *   nodeId (optional): ID of the node to be shown, if not given the first node, which is
		 *                      not the node for new items, will be shown
		 */
		initShop: function(nodeId) {
			var callbackMenu = {
				success: function(o) {
					try {
						_private.menu = YAHOO.lang.JSON.parse(o.responseText);
					}
					catch (e) {
						DEBUG('failed to parse JSON file containing menu data: ' + e.message);
						yuiLoader.hide();
						return;
					}
					YAHOO.util.Connect.asyncRequest('GET', '/_json/shopData.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackItems, null);
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('reading JSON file containing menu data timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/shopMenu.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackMenu, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};
			var callbackItems = {
				success: function(o) {
					try {
						_private.data = YAHOO.lang.JSON.parse(o.responseText);
					}
					catch (e) {
						DEBUG('failed to parse JSON file containing item data: ' + e.message);
						yuiLoader.hide();
						return;
					}
					//_private.initDisplay(); // initially load the first commodity group
					Content.loadShopFast(); // initially load the fast order form
					YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackFavorites, null);
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('reading JSON file containing item data timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/shopData.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackItems, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};
			var callbackFavorites = {
				success: function(o) {
					try {
						_private.favorites = YAHOO.lang.JSON.parse(o.responseText);
					}
					catch (e) {
						DEBUG('failed to parse JSON file containing favorites: ' + e.message);
						yuiLoader.hide();
						return;
					}
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting JSON file containing favorites timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackFavorites, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};

			if (document.getElementById('containerShop')) {
				yuiLoader.show();
				
				if (_private.menu) {
					if (nodeId) {
						_private.initDisplay(nodeId);
					}
					else {
						_private.initDisplay();
					}
					yuiLoader.hide();
				}
				else {
					YAHOO.util.Connect.asyncRequest('GET', '/_json/shopMenu.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackMenu, null);
				}
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * add event handlers to show/hide information on pre-ordering items
		 */
		preOrderAddListeners: function() {
			var links = YAHOO.util.Dom.getElementsByClassName('aPreOrder'); // Don't select by tagname!

			YAHOO.util.Event.removeListener(links);
			YAHOO.util.Event.addListener(links, 'click', function() {
				_private.preOrderPanel.show();
			});
		},
		/*-----------------------------------------------------------------------------------------
		 * show information on pre-ordering items
		 */
		preOrderPanelInit: function() {
			_private.preOrderPanel = new YAHOO.widget.Panel('boxPreOrderPanel', {
				width: '752px',
				autofillheight: 'body',
				constraintoviewport: true,
				fixedcenter: true,
				close: false,
				visible: false,
				draggable: false,
				modal: true,
				zindex: 50
			});
			_private.preOrderPanel.setBody(
				'<h1>Vorbestellung</h1>'

				+ '<h2>Tr&uuml;ffeln, K&auml;se, Pasta und Brot</h2>'
/*
				+ '<h3>Tr&uuml;ffeln:</h3>'
				+ 'F&uuml;r frische Tr&uuml;ffeln gelten Tagespreise. Bitte erfragen Sie diese'
				+ ' telefonisch oder per E-Mail in der Abteilung <a href="/bestellannahme_verkauf"'
				+ ' target="_blank">&#132;Verkauf, Beratung"</a>.'
*/
				+ '<h3>Tr&uuml;ffeln:</h3>'
				+ 'F&uuml;r frische Tr&uuml;ffeln gelten Tagespreise. Bitte erfragen Sie diese'
				+ ' telefonisch oder per E-Mail in der Abteilung &#132;Verkauf, Beratung".'

				+ '<h3>K&auml;se:</h3>'
				+ 'Einige K&auml;se (vor allem von Guffanti, Agrilanga, Alain Michel und Michel'
				+ ' Beroud) werden bei uns nur auf Vorbestellung geliefert. Wir disponieren'
				+ ' K&auml;se im w&ouml;chentlichen, teilweise im zweiw&ouml;chentlichen Rhythmus.'
				+ ' F&uuml;r Sie gilt dabei die Formel: bis Dienstag (12.00 Uhr) bestellt, ab'
				+ ' Dienstag der kommenden Woche wird geliefert.'

				+ '<h3>Brot:</h3>'
				+ 'Unsere Bestellungen f&uuml;r Brot nehmen wir bis Montagmittag entgegen, das'
				+ ' frische Brot kann dann ab Mittwoch mit Ihrer Lagerware versandt werden.'

				+ '<h3>Pasta:</h3>'
				+ 'Unsere Pasta trifft w&ouml;chentlich frisch bei uns ein. Bestellen Sie bitte'
				+ ' bis Dienstag, Lieferung ab kommende Woche Mittwoch.'

				+ '<h3>ECM-Espressomaschinen:</h3>'
				+ 'ECM-Espressomaschinen und Zubeh&ouml;r sind nicht ab Lager G&ouml;ttingen,'
				+ ' jedoch kurzfristig lieferbar. Bitte haben Sie Verst&auml;ndnis, dass die'
				+ ' K&ouml;nigin der Espressomaschinen separat geliefert wird.'
  			);
			_private.preOrderPanel.setFooter('<a id="aPreOrderPanelClose">Fenster schließen</a>');
			_private.preOrderPanel.render(YAHOO.util.Dom.get('containerViani'));
			YAHOO.util.Event.addListener('aPreOrderPanelClose', 'click', function() {
				_private.preOrderPanel.hide();
			});
		},
		/*-----------------------------------------------------------------------------------------
		 * execute an AND search for shop items
		 */
		searchItems: function() {
			var patterns = document.getElementById('inputSearchItem').value.toLowerCase().split(/\s+/);
			var count = 0;
			var found;

			if (   !_private.data
				|| !patterns.length
			    || (patterns.length == 1 && !patterns[0])
				|| (patterns.length == 2 && !patterns[0] && !patterns[1])) {
				return;
			}
			_private.searchResults.length = 0;
			_private.ERPCodes.length = 0;

			for (var i=0; i<_private.data.items.length; i++) {
				found = true;

				for (var j=0; j<patterns.length; j++) {
					if (   (!_private.data.items[i]._30 || _private.data.items[i]._30.toLowerCase().indexOf(patterns[j]) < 0)   // _30 -> Internetname1
					    && (!_private.data.items[i]._31 || _private.data.items[i]._31.toLowerCase().indexOf(patterns[j]) < 0)   // _31 -> Internetname2
					    && (!_private.data.items[i]._32 || _private.data.items[i]._32.toLowerCase().indexOf(patterns[j]) < 0)   // _32 -> Hersteller
					    && (!_private.data.items[i].code || _private.data.items[i].code.toLowerCase().indexOf(patterns[j]) < 0)) {
						found = false;
						break;
					}
				}
				if (found) {
					_private.searchResults[count++] = _private.data.items[i];
				}
			}
			Content.loadSearchResults();
		},
		/*-----------------------------------------------------------------------------------------
		 * display favorites instead of all shop items
		 *
		 * Since this function may be called from any node once a user is logged in, _private.data
		 * and _private.favorites are not necessarily set. Thus these values must be evaluated and
		 * set to adequate values if they are not set.
		 */
		showFavorites: function() {
			var callbackFavorites = {
				success: function(o) {
					try {
						_private.favorites = YAHOO.lang.JSON.parse(o.responseText);
					}
					catch (e) {
						DEBUG('failed to parse JSON file containing favorites: ' + e.message);
						yuiLoader.hide();
						return;
					}
					if (_private.data) {
						_private.generateFavorites();
						yuiLoader.hide();
					}
					else {
						YAHOO.util.Connect.asyncRequest('GET', '/_json/shopData.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackItems, null);
					}
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting JSON file containing favorites timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackFavorites, null);
					}
				},
				timeout: 30000
			};
			var callbackItems = {
				success: function(o) {
					try {
						_private.data = YAHOO.lang.JSON.parse(o.responseText);
					} 
					catch (e) {
						DEBUG('failed to parse JSON file containing item data: ' + e.message);
						yuiLoader.hide();
						return;
					}
					//_private.initDisplay();
					_private.generateFavorites();
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('reading JSON file containing item data timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/shopData.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackItems, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};

			yuiLoader.show();

			if (_private.favorites) {
				if (_private.data) {
					_private.generateFavorites();
					yuiLoader.hide();
				}
				else {
					YAHOO.util.Connect.asyncRequest('GET', '/_json/shopData.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackItems, null);
				}
			}
			else {
				YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callbackFavorites, null);
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * show details of an item in the basket
		 *
		 * params:
		 *   code: the ERP code of the item to be shown
		 */
		showItemDetailBasket: function(code) {
			var links = YAHOO.util.Dom.getElementsByClassName('aShowItem', 'a', 'containerBasket');
			var callback = {
				success: function(o) {
					try {
						_private.favorites = YAHOO.lang.JSON.parse(o.responseText);
					}
					catch (e) {
						DEBUG('failed to parse JSON file containing favorites: ' + e.message);
						yuiLoader.hide();
						return;
					}
					_private.getItemDetail(code, 'basket');
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting JSON file containing favorites timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};

			yuiLoader.show();
			_private.ERPCodes.length = 0;

			for (var i=0; i<links.length; i++) {
				_private.ERPCodes[i] = links[i].innerHTML;
				
			}
			if (_private.favorites) {
				_private.getItemDetail(code, 'basket');
				yuiLoader.hide();
			}
			else {
				YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * show details of an item in the basket of a fast order process
		 *
		 * params:
		 *   code: the ERP code of the item to be shown
		 */
		showItemDetailBasketFast: function(code) {
			var links = YAHOO.util.Dom.getElementsByClassName('aShowItem', 'a', 'containerBasket');
			var callback = {
				success: function(o) {
					try {
						_private.favorites = YAHOO.lang.JSON.parse(o.responseText);
					}
					catch (e) {
						DEBUG('failed to parse JSON file containing favorites: ' + e.message);
						yuiLoader.hide();
						return;
					}
					_private.getItemDetail(code, 'basketFast');
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting JSON file containing favorites timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};

			yuiLoader.show();
			_private.ERPCodes.length = 0;

			for (var i=0; i<links.length; i++) {
				_private.ERPCodes[i] = links[i].innerHTML;
				
			}
			if (_private.favorites) {
				_private.getItemDetail(code, 'basketFast');
				yuiLoader.hide();
			}
			else {
				YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
		},
		/*-----------------------------------------------------------------------------------------
		 * show details of an item previously ordered
		 *
		 * params:
		 *   code: the ERP code of the item to be shown
		 */
		showItemDetailOrder: function(code) {
			var links = YAHOO.util.Dom.getElementsByClassName('aShowItem', 'a', 'containerOrdersDetail');
			var callback = {
				success: function(o) {
					try {
						_private.favorites = YAHOO.lang.JSON.parse(o.responseText);
					}
					catch (e) {
						DEBUG('failed to parse JSON file containing favorites: ' + e.message);
						yuiLoader.hide();
						return;
					}
					_private.getItemDetail(code, 'order');
					yuiLoader.hide();
				},
				failure: function(o) {
					if (o.status == -1) {
						DEBUG('getting JSON file containing favorites timed out - retrying');
						YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
					}
					else {
						yuiLoader.hide();
					}
				},
				timeout: 30000
			};

			yuiLoader.show();
			_private.ERPCodes.length = 0;

			for (var i=0; i<links.length; i++) {
				_private.ERPCodes[i] = links[i].innerHTML;
				
			}
			if (_private.favorites) {
				_private.getItemDetail(code, 'order');
				yuiLoader.hide();
			}
			else {
				YAHOO.util.Connect.asyncRequest('GET', '/_json/favorites.json?xhr=shop' + (++_private.xhrCount) + '&' + _private.cookie, callback, null);
			}
		}
	}
	return _public;
}();

YAHOO.util.Event.onContentReady('containerShop', Shop.initShop);
YAHOO.util.Event.onDOMReady(Shop.preOrderPanelInit);
