// -----------------------------------------------------------------------------------
//
//	Lightbox v2.04
//	by Lokesh Dhakar - http://www.lokeshdhakar.com
//	Last Modification: 2/9/08
//
//	For more information, visit:
//	http://lokeshdhakar.com/projects/lightbox2/
//
//	Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
//  	- Free for use in both personal and commercial projects
//		- Attribution requires leaving author name, author link, and the license info intact.
//	
//  Thanks: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), and Thomas Fuchs(mir.aculo.us) for ideas, libs, and snippets.
//  		Artemy Tregubenko (arty.name) for cleanup and help in updating to latest ver of proto-aculous.
//
// -----------------------------------------------------------------------------------
/*

    Table of Contents
    -----------------
    Configuration

    Lightbox Class Declaration
    - initialize()
    - updateImageList()
    - start()
    - changeImage()
    - resizeImageContainer()
    - showImage()
    - updateDetails()
    - updateNav()
    - enableKeyboardNav()
    - disableKeyboardNav()
    - keyboardAction()
    - preloadNeighborImages()
    - end()
    
    Function Calls
    - document.observe()
   
*/
// -----------------------------------------------------------------------------------

//
//  Configurationl
//
LightboxOptions = Object.extend({
    fileLoadingImage:        'Pictures/Lightbox/loading.gif',     
    fileBottomNavCloseImage: 'Pictures/Lightbox/closelabel.gif',

    overlayOpacity: 0.8,   // controls transparency of shadow overlay

    animate: true,         // toggles resizing animations
    resizeSpeed: 7,        // controls the speed of the image resizing animations (1=slowest and 10=fastest)

    borderSize: 10,         //if you adjust the padding in the CSS, you will need to update this variable

	// When grouping images this is used to write: Image # of #.
	// Change it for non-english localization
	labelImage: "Image",
	labelOf: "of"
}, window.LightboxOptions || {});

// -----------------------------------------------------------------------------------

var Lightbox = Class.create();

Lightbox.prototype = {
    imageArray: [],
    activeImage: undefined,
    
    // initialize()
    // Constructor runs on completion of the DOM loading. Calls updateImageList and then
    // the function inserts html at the bottom of the page which is used to display the shadow 
    // overlay and the image container.
    //
    initialize: function() {    
        
        this.updateImageList();
        
        this.keyboardAction = this.keyboardAction.bindAsEventListener(this);

        if (LightboxOptions.resizeSpeed > 10) LightboxOptions.resizeSpeed = 10;
        if (LightboxOptions.resizeSpeed < 1)  LightboxOptions.resizeSpeed = 1;

	    this.resizeDuration = LightboxOptions.animate ? ((11 - LightboxOptions.resizeSpeed) * 0.15) : 0;
	    this.overlayDuration = LightboxOptions.animate ? 0.2 : 0;  // shadow fade in/out duration

        // When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
        // If animations are turned off, it will be hidden as to prevent a flicker of a
        // white 250 by 250 box.
        var size = (LightboxOptions.animate ? 250 : 1) + 'px';
        

        // Code inserts html at the bottom of the page that looks similar to this:
        //
        //  <div id="overlay"></div>
        //  <div id="lightbox">
        //      <div id="outerImageContainer">
        //          <div id="imageContainer">
        //              <img id="lightboxImage">
        //              <div style="" id="hoverNav">
        //                  <a href="#" id="prevLink"></a>
        //                  <a href="#" id="nextLink"></a>
        //              </div>
        //              <div id="loading">
        //                  <a href="#" id="loadingLink">
        //                      <img src="images/loading.gif">
        //                  </a>
        //              </div>
        //          </div>
        //      </div>
        //      <div id="imageDataContainer">
        //          <div id="imageData">
        //              <div id="imageDetails">
        //                  <span id="caption"></span>
        //                  <span id="numberDisplay"></span>
        //              </div>
        //              <div id="bottomNav">
        //                  <a href="#" id="bottomNavClose">
        //                      <img src="images/close.gif">
        //                  </a>
        //              </div>
        //          </div>
        //      </div>
        //  </div>


        var objBody = $$('body')[0];

		objBody.appendChild(Builder.node('div',{id:'overlay'}));
	
        objBody.appendChild(Builder.node('div',{id:'lightbox'}, [
            Builder.node('div',{id:'outerImageContainer'}, 
                Builder.node('div',{id:'imageContainer'}, [
                    Builder.node('img',{id:'lightboxImage'}), 
                    Builder.node('div',{id:'hoverNav'}, [
                        Builder.node('a',{id:'prevLink', href: '#' }),
                        Builder.node('a',{id:'nextLink', href: '#' })
                    ]),
                    Builder.node('div',{id:'loading'}, 
                        Builder.node('a',{id:'loadingLink', href: '#' }, 
                            Builder.node('img', {src: LightboxOptions.fileLoadingImage})
                        )
                    )
                ])
            ),
            Builder.node('div', {id:'imageDataContainer'},
                Builder.node('div',{id:'imageData'}, [
                    Builder.node('div',{id:'imageDetails'}, [
                        Builder.node('span',{id:'caption'}),
                        Builder.node('span',{id:'numberDisplay'})
                    ]),
                    Builder.node('div',{id:'bottomNav'},
                        Builder.node('a',{id:'bottomNavClose', href: '#' },
                            Builder.node('img', { src: LightboxOptions.fileBottomNavCloseImage })
                        )
                    )
                ])
            )
        ]));


		$('overlay').hide().observe('click', (function() { this.end(); }).bind(this));
		$('lightbox').hide().observe('click', (function(event) { if (event.element().id == 'lightbox') this.end(); }).bind(this));
		$('outerImageContainer').setStyle({ width: size, height: size });
		$('prevLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this));
		$('nextLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this));
		$('loadingLink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
		$('bottomNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));

        var th = this;
        (function(){
            var ids = 
                'overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading loadingLink ' + 
                'imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose';   
            $w(ids).each(function(id){ th[id] = $(id); });
        }).defer();
    },

    //
    // updateImageList()
    // Loops through anchor tags looking for 'lightbox' references and applies onclick
    // events to appropriate links. You can rerun after dynamically adding images w/ajax.
    //
    updateImageList: function() {   
        this.updateImageList = Prototype.emptyFunction;

        document.observe('click', (function(event){
            var target = event.findElement('a[rel^=lightbox]') || event.findElement('area[rel^=lightbox]');
            if (target) {
                event.stop();
                this.start(target);
            }
        }).bind(this));
    },
    
    //
    //  start()
    //  Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
    //
    start: function(imageLink) {    

        $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });

        // stretch overlay to fill page and fade in
        var arrayPageSize = this.getPageSize();
        $('overlay').setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });

        new Effect.Appear(this.overlay, { duration: this.overlayDuration, from: 0.0, to: LightboxOptions.overlayOpacity });

        this.imageArray = [];
        var imageNum = 0;       

        if ((imageLink.rel == 'lightbox')){
            // if image is NOT part of a set, add single image to imageArray
            this.imageArray.push([imageLink.href, imageLink.title]);         
        } else {
            // if image is part of a set..
            this.imageArray = 
                $$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]').
                collect(function(anchor){ return [anchor.href, anchor.title]; }).
                uniq();
            
            while (this.imageArray[imageNum][0] != imageLink.href) { imageNum++; }
        }

        // calculate top and left offset for the lightbox 
        var arrayPageScroll = document.viewport.getScrollOffsets();
        var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
        var lightboxLeft = arrayPageScroll[0];
        this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
        
        this.changeImage(imageNum);
    },

    //
    //  changeImage()
    //  Hide most elements and preload image in preparation for resizing image container.
    //
    changeImage: function(imageNum) {   
        
        this.activeImage = imageNum; // update global var

        // hide elements during transition
        if (LightboxOptions.animate) this.loading.show();
        this.lightboxImage.hide();
        this.hoverNav.hide();
        this.prevLink.hide();
        this.nextLink.hide();
		// HACK: Opera9 does not currently support scriptaculous opacity and appear fx
        this.imageDataContainer.setStyle({opacity: .0001});
        this.numberDisplay.hide();      
        
        var imgPreloader = new Image();
        
        // once image is preloaded, resize image container


        imgPreloader.onload = (function(){
            this.lightboxImage.src = this.imageArray[this.activeImage][0];
            this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
        }).bind(this);
        imgPreloader.src = this.imageArray[this.activeImage][0];
    },

    //
    //  resizeImageContainer()
    //
    resizeImageContainer: function(imgWidth, imgHeight) {

        // get current width and height
        var widthCurrent  = this.outerImageContainer.getWidth();
        var heightCurrent = this.outerImageContainer.getHeight();

        // get new width and height
        var widthNew  = (imgWidth  + LightboxOptions.borderSize * 2);
        var heightNew = (imgHeight + LightboxOptions.borderSize * 2);

        // scalars based on change from old to new
        var xScale = (widthNew  / widthCurrent)  * 100;
        var yScale = (heightNew / heightCurrent) * 100;

        // calculate size difference between new and old image, and resize if necessary
        var wDiff = widthCurrent - widthNew;
        var hDiff = heightCurrent - heightNew;

        if (hDiff != 0) new Effect.Scale(this.outerImageContainer, yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'}); 
        if (wDiff != 0) new Effect.Scale(this.outerImageContainer, xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration}); 

        // if new and old image are same size and no scaling transition is necessary, 
        // do a quick pause to prevent image flicker.
        var timeout = 0;
        if ((hDiff == 0) && (wDiff == 0)){
            timeout = 100;
            if (Prototype.Browser.IE) timeout = 250;   
        }

        (function(){
            this.prevLink.setStyle({ height: imgHeight + 'px' });
            this.nextLink.setStyle({ height: imgHeight + 'px' });
            this.imageDataContainer.setStyle({ width: widthNew + 'px' });

            this.showImage();
        }).bind(this).delay(timeout / 1000);
    },
    
    //
    //  showImage()
    //  Display image and begin preloading neighbors.
    //
    showImage: function(){
        this.loading.hide();
        new Effect.Appear(this.lightboxImage, { 
            duration: this.resizeDuration, 
            queue: 'end', 
            afterFinish: (function(){ this.updateDetails(); }).bind(this) 
        });
        this.preloadNeighborImages();
    },

    //
    //  updateDetails()
    //  Display caption, image number, and bottom nav.
    //
    updateDetails: function() {
    
        // if caption is not null
        if (this.imageArray[this.activeImage][1] != ""){
            this.caption.update(this.imageArray[this.activeImage][1]).show();
        }
        
        // if image is part of set display 'Image x of x' 
        if (this.imageArray.length > 1){
            this.numberDisplay.update( LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + '  ' + this.imageArray.length).show();
        }

        new Effect.Parallel(
            [ 
                new Effect.SlideDown(this.imageDataContainer, { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }), 
                new Effect.Appear(this.imageDataContainer, { sync: true, duration: this.resizeDuration }) 
            ], 
            { 
                duration: this.resizeDuration, 
                afterFinish: (function() {
	                // update overlay size and update nav
	                var arrayPageSize = this.getPageSize();
	                this.overlay.setStyle({ height: arrayPageSize[1] + 'px' });
	                this.updateNav();
                }).bind(this)
            } 
        );
    },

    //
    //  updateNav()
    //  Display appropriate previous and next hover navigation.
    //
    updateNav: function() {

        this.hoverNav.show();               

        // if not first image in set, display prev image button
        if (this.activeImage > 0) this.prevLink.show();

        // if not last image in set, display next image button
        if (this.activeImage < (this.imageArray.length - 1)) this.nextLink.show();
        
        this.enableKeyboardNav();
    },

    //
    //  enableKeyboardNav()
    //
    enableKeyboardNav: function() {
        document.observe('keydown', this.keyboardAction); 
    },

    //
    //  disableKeyboardNav()
    //
    disableKeyboardNav: function() {
        document.stopObserving('keydown', this.keyboardAction); 
    },

    //
    //  keyboardAction()
    //
    keyboardAction: function(event) {
        var keycode = event.keyCode;

        var escapeKey;
        if (event.DOM_VK_ESCAPE) {  // mozilla
            escapeKey = event.DOM_VK_ESCAPE;
        } else { // ie
            escapeKey = 27;
        }

        var key = String.fromCharCode(keycode).toLowerCase();
        
        if (key.match(/x|o|c/) || (keycode == escapeKey)){ // close lightbox
            this.end();
        } else if ((key == 'p') || (keycode == 37)){ // display previous image
            if (this.activeImage != 0){
                this.disableKeyboardNav();
                this.changeImage(this.activeImage - 1);
            }
        } else if ((key == 'n') || (keycode == 39)){ // display next image
            if (this.activeImage != (this.imageArray.length - 1)){
                this.disableKeyboardNav();
                this.changeImage(this.activeImage + 1);
            }
        }
    },

    //
    //  preloadNeighborImages()
    //  Preload previous and next images.
    //
    preloadNeighborImages: function(){
        var preloadNextImage, preloadPrevImage;
        if (this.imageArray.length > this.activeImage + 1){
            preloadNextImage = new Image();
            preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
        }
        if (this.activeImage > 0){
            preloadPrevImage = new Image();
            preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
        }
    
    },

    //
    //  end()
    //
    end: function() {
        this.disableKeyboardNav();
        this.lightbox.hide();
        new Effect.Fade(this.overlay, { duration: this.overlayDuration });
        $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });
    },

    //
    //  getPageSize()
    //
    getPageSize: function() {
	        
	     var xScroll, yScroll;
		
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = window.innerWidth + window.scrollMaxX;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}
		
		var windowWidth, windowHeight;
		
		if (self.innerHeight) {	// all except Explorer
			if(document.documentElement.clientWidth){
				windowWidth = document.documentElement.clientWidth; 
			} else {
				windowWidth = self.innerWidth;
			}
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	
		
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}
	
		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = xScroll;		
		} else {
			pageWidth = windowWidth;
		}

		return [pageWidth,pageHeight];
	}
}

document.observe('dom:loaded', function () { new Lightbox(); });

function addToWatchList(itemId) { watchList(itemId, true); }

function removeFromWatchList(itemId) { watchList(itemId, false); }

var isIE = undefined;

function isInternetExplorer()
{
	if (isIE == undefined) { isIE = navigator.appName == 'Microsoft Internet Explorer'; }
	return isIE;
}


function watchList(itemId, add)
{
	var parameters = add ? { addItemId: itemId } : { removeItemId: itemId };

	var addLink = $('addToWatchListLink_' + itemId);
	var removeLink = $('removeFromWatchListLink_' + itemId);
	var flag = $('inWatchListFlag_' + itemId);

	cursorIcon.show('loading');

	new Ajax.Request('watchlist.html', {
		method: 'get',
		parameters: parameters,
		onSuccess: function(transport) {
			cursorIcon.hide('loading');
			if (transport.responseText.empty()) {
				if (add)
				{
					flag.show();
					addLink.hide();
					removeLink.show();
				}
				else
				{
					flag.hide();
					addLink.show();
					removeLink.hide();
				}
			}
			else
			{
				messages.showError('There has been a problem: '+ transport.responseText);
			}
		},
		onFailure: function() {
			messages.showError('Something went wrong');
		}
	});

	if (addLink && removeLink)
	{
		if (add)
		{
			addLink.hide();
			removeLink.show();
		}
		else
		{
			addLink.show();
			removeLink.hide();
		}
	};
}



function castVote(itemId, rating, elementId)
{

	cursorIcon.show('loading');

	new Ajax.Request('castVote.html', {
		method: 'get',
		parameters: { itemId: itemId, rating: rating },
		onSuccess: function(transport) {
			cursorIcon.hide('loading');
			var infos = {};
			try
			{
				if (infos = transport.responseText.evalJSON())
				{
					messages.showSuccess('Thank you for voting.');
					setNewRating(elementId, infos.rating / 100);
				}
			}
			catch (e)
			{
				messages.showError(transport.responseText);
			}
		},
		onFailure: function() {
			messages.showError('Something went wrong');
		}
	});

}

function createVoteLinks(elementId, itemId)
{
	var element = $(elementId);
	var dimensions = $(element).getDimensions();

	var linkWidth = Math.round(dimensions.width / 5);

	for (var i = 0; i < 5; i++)
	{
		var link = $(element).appendChild(Builder.node('div', { className: 'voteLink' }));
		link.setStyle({ width: linkWidth + 'px', height: dimensions.height + 'px', cursor: 'pointer', left: (linkWidth * i) + 'px' });
		link.observe('click', function(ii) { return function()
			{
				castVote(itemId, ii+1, elementId);
				$(element).getElementsBySelector('.voteLink').each(function(theElement) { theElement.remove(); });
			} }(i));
	}

}

function setNewRating(elementId, rating)
{
	$(elementId).getElementsBySelector('.filler').each(function(element)
		{
			var starWidth = parseInt($(elementId).getElementsBySelector('.starWidth')[0].innerHTML);
			var starSpacer = parseInt($(elementId).getElementsBySelector('.starSpacer')[0].innerHTML);
			var offset = parseInt($(elementId).getElementsBySelector('.offset')[0].innerHTML);
			var newWidth = Math.round(rating*starWidth + offset + Math.floor(rating)*starSpacer);
			$(element).setStyle({ width: newWidth + 'px' });
			var theValue = $(elementId + '_value');
			if (theValue) { theValue.update(rating); }
		});
}



function redirect(url)
{
	window.location = url;
}


function toggleOrderDetails(orderId, type)
{
	var orderDetails = $('orderDetails_'+orderId);
	if (!orderDetails.visible()) { showOrderDetails(orderId, type); }
	else { hideOrderDetails(orderId); }

}
function showOrderDetails(orderId, type)
{
	var orderDetails = $('orderDetails_'+orderId);

	var imgElement = $('order_' + orderId).getElementsBySelector('.detailsLink img')[0];
	imgElement.removeClassName('open');
	imgElement.addClassName('close');

	if (orderDetails.innerHTML.strip().empty())
	{
		orderDetails.update('loading');
		loadOrderDetails(orderId, type);
	}

	orderDetails.show();
}
function hideOrderDetails(orderId)
{
	var orderDetails = $('orderDetails_'+orderId);

	var imgElement = $('order_' + orderId).getElementsBySelector('.detailsLink img')[0];
	imgElement.removeClassName('close');
	imgElement.addClassName('open');

	orderDetails.hide();
}

function loadOrderDetails(orderId, type)
{
	new Ajax.Request('orderDetails.html', {
		method: 'get',
		parameters: { orderId: orderId, orderType: type },
		onSuccess: function(transport) {
			try
			{
				var orderDetails = $('orderDetails_'+orderId);
				var infos = transport.responseText.evalJSON();


				orderDetails.update('');

				orderDetails.appendChild(Builder.node('div', { className: 'billingAddress' }, 'Billing Address: '   + infos.billingAddress.fullName + ', ' + infos.billingAddress.street1 + ', ' + infos.billingAddress.zipCode + ', ' + infos.billingAddress.city ));
				orderDetails.appendChild(Builder.node('div', { className: 'shippingAddress' }, 'Shipping Address: '  + infos.shippingAddress.fullName + ', ' + infos.shippingAddress.street1 + ', ' + infos.shippingAddress.zipCode + ', ' + infos.shippingAddress.city));

				infos.companies.each(function(company) {
					var companyElement = orderDetails.appendChild(Builder.node('div', { className: 'company' }));
					companyElement.appendChild(Builder.node('div', { className: 'name' }, company.name));
					companyElement.appendChild(Builder.node('div', { className: 'address' }, company.address));
					companyElement.appendChild(Builder.node('div', { className: 'orderId' }, 'Auftragsnummer.: '   + company.orderId ));
					var companyItems = companyElement.appendChild(Builder.node('div', { className: 'items' }));
					var companyItems = companyItems.appendChild(Builder.node('table', { width: '100%' })).appendChild(Builder.node('tbody'));
					var row = companyItems.appendChild(Builder.node('tr', { className: 'labels' }));
					row.appendChild(Builder.node('td', { className: 'label' }, 'Name'));
					row.appendChild(Builder.node('td', { className: 'label' }, 'VPE'));
					row.appendChild(Builder.node('td', { className: 'label' }, 'Anzahl'));
					row.appendChild(Builder.node('td', { className: 'label' }, 'Einzelpreis'));
					row.appendChild(Builder.node('td', { className: 'label' }, 'Gesamtpreis'));
					company.items.each(function(item)
					{
						var row = companyItems.appendChild(Builder.node('tr', { className: 'item' }));
						row.appendChild(Builder.node('td', { className: 'name' }, item.name));
						row.appendChild(Builder.node('td', { className: 'packagingUnit' }, item.packagingUnit));
						row.appendChild(Builder.node('td', { className: 'amount' }, item.amount));
						row.appendChild(Builder.node('td', { className: 'price' }, item.price / 100));
						row.appendChild(Builder.node('td', { className: 'priceSum' }, item.priceSum / 100));
					});
				});

			}
			catch (e)
			{
				messages.showError('Something went wrong: ' + e);
			}
		},
		onFailure: function() {
			messages.showError('Something went wrong');
		}
	});
}






var mousePosition = { x: 0, y: 0 };
var setMousePosition = function(event)
{
	mousePosition.x = Event.pointerX(event);
	mousePosition.y = Event.pointerY(event);
};
document.observe('mousemove', setMousePosition);




Element.addMethods(['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'OPTION'], { getParentForm: function(element)
{
	element = $(element);

	while (parentElement = element.parentNode)
	{
		if (parentElement.tagName == 'FORM') { return parentElement; }
		element = parentElement;
	}
	return undefined;
}});

Element.addMethods(['INPUT', 'TEXTAREA'], {
	setComment: function(element, comment, dontClearOnSubmit) {
		element = $(element);
		comment = comment.strip();

		var className = 'empty';

		setCommentIfEmpty(element, comment, className);
		element.observe('change', function() { setCommentIfEmpty(element, comment, className); });
		element.observe('blur',   function() { setCommentIfEmpty(element, comment, className); });
		element.observe('focus',  function() { removeEmptyFillerAndClass(element, comment, className); });

		var parentForm = element.getParentForm();
		if (parentForm && !dontClearOnSubmit)
		{
			parentForm.observe('submit', function() { clearIfEmpty(element, comment); });
		}

		return element;
	}
});



function setCommentIfEmpty(element, comment, className)
{
	element = $(element);

	var elementValue = element.getValue().strip();
	if (elementValue.empty() || elementValue == comment)
	{
		element.addClassName(className);
		element.value = comment;
	}
	else { element.removeClassName(className); }
}
function removeEmptyFillerAndClass(element, comment, className)
{
	element.removeClassName(className);
	clearIfEmpty(element, comment);
}
function clearIfEmpty(element, comment)
{
	var elementValue = element.getValue().strip();
	if (elementValue == comment) { element.clear(); }
}


if (!window.console || !console.firebug)
{
    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

    window.console = {};
    for (var i = 0; i < names.length; ++i)
        window.console[names[i]] = function() {}
}

var CursorIcon = function()
{

	this.element = false;
	this.icons = {};

	this.xOffset = 10;
	this.yOffset = 15;


	var self = this;
	this.static = {};
	this.static.setPosition = function(event) { self.setPosition(event); }



	this.setPosition = function()
	{
		if (this.element)
		{
			this.element.setStyle({left: mousePosition.x + this.xOffset + 'px', top: mousePosition.y + this.yOffset + 'px'});
		}
	};


	this.createElements = function()
	{
		this.element = $(document.body.appendChild(Builder.node('div', { className: 'cursorIcons' })));

	};


	this.allShowing = 0;
	this.showing = {};

	this.show = function(iconName)
	{
		if (!this.element) { this.createElements(); }
		if (!this.showing[iconName]) { this.showing[iconName] = 0; }


		this.showing[iconName] ++;
		this.allShowing ++;
		if (this.icons[iconName]) { return; }

		this.icons[iconName] = this.element.appendChild($(Builder.node('img', { className: 'icon ' + ('icon-' + iconName).camelize(), src: 'Pictures/spacer.gif'})));

		this.setPosition();
		document.observe('mousemove', this.static.setPosition);
	};
	this.hide = function(iconName)
	{
		if (this.icons[iconName])
		{
			this.showing[iconName] = Math.max(0, this.showing[iconName] - 1);
			this.allShowing = Math.max(0, this.allShowing - 1);
			if (this.showing[iconName] == 0)
			{
				this.icons[iconName].remove();
				this.icons[iconName] = false;
			}
		}
		if (this.allShowing == 0)
		{
			document.stopObserving('mousemove', this.static.setPosition);
		}
	};



};


var cursorIcon = new CursorIcon();

/**
 * Sets a Cookie with the given name and value.
 *
 * name            Name of the cookie
 * value           Value of the cookie
 * [expiresHours]  The number of hours until expiration date. (default: end of current session)
 * [path]          Path where the cookie is valid (default: path of calling document)
 * [domain]        Domain where the cookie is valid
 *                   (default: domain of calling document)
 * [secure]        Boolean value indicating if the cookie transmission requires a
 *                   secure transmission
 */
 
function Cookie()
{

	this.set = function(name, value, expireDays, path, domain, secure)
	{
		if (expireDays)
		{
			var expires = new Date()
			expires.setDate(expires.getDate() + expireDays);
		}

		document.cookie = name + "=" + escape(value) +
			((expires) ? "; expires=" + expires.toGMTString() : "") +
			((path) ? "; path=" + path : "") +
			((domain) ? "; domain=" + domain : "") +
			((secure) ? "; secure" : "");
	
	}
	
	
	/**
	 * Gets the value of the specified cookie.
	 *
	 * name  Name of the desired cookie.
	 *
	 * Returns a string containing value of specified cookie,
	 *   or null if cookie does not exist.
	 */
	this.get = function(name)
	{
	    var dc = document.cookie;
	    var prefix = name + "=";
	    var begin = dc.indexOf("; " + prefix);
	    if (begin == -1)
	    {
	        begin = dc.indexOf(prefix);
	        if (begin != 0) return null;
	    }
	    else
	    {
	        begin += 2;
	    }
	    var end = document.cookie.indexOf(";", begin);
	    if (end == -1)
	    {
	        end = dc.length;
	    }
	    return unescape(dc.substring(begin + prefix.length, end));
	}
	
	/**
	 * Deletes the specified cookie.
	 *
	 * name      name of the cookie
	 * [path]    path of the cookie (must be same as path used to create cookie)
	 * [domain]  domain of the cookie (must be same as domain used to create cookie)
	 */
	this.unset = function(name, path, domain)
	{
	    if (this.get(name))
	    {
	        document.cookie = name + "=" + 
	            ((path) ? "; path=" + path : "") +
	            ((domain) ? "; domain=" + domain : "") +
	            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
	    }
	}
}


var cookie = new Cookie();


function EnsureValue()
{


	this.defaultValues = { min:1, max:999999, maxLength:1000, defaultValue:0 };



	this.validateParameters = function(p)
	{
		if (!p) { p = { }; }
		if (p.defaultValue === undefined) { p.defaultValue = this.defaultValues.defaultValue; } // for all
		if (p.min === undefined)          { p.min = this.defaultValues.min; } // for ints and floats
		if (p.max === undefined)          { p.max = this.defaultValues.max; } // for ints and floats
		if (p.maxLength === undefined)    { p.maxLengt = this.defaultValues.maxLength; } // for strings
		return p;
	};

	this.integer = function(object, parameters)
	{
		parameters = this.validateParameters(parameters);

		var number = parseInt(object.value);
		
		if (isNaN(number)) { number = parameters.defaultValue; }
		
		if (number < parameters.min) { number = parameters.min; }
		else if (number > parameters.max) { number = parameters.max; }
		object.value = number;
	};


	this.float = function(object, parameters)
	{
		this.validateParameters(parameters);

		var number = parseFloat(object.value);
		
		if (isNaN(number)) { number = parameters.defaultValue; }
		
		if (number < parameters.min) { number = parameters.min; }
		else if (number > parameters.max) { number = parameters.max; }
		object.value = number;
	};


	this.string = function(object, parameters)
	{
		messages.shorError('ensureValue.string not implemented yet;');
	};


}

var ensureValue = new EnsureValue();

function SelectorClass(groups, displayElement, targetUrl)
{

	this.groups = groups;



	this.displayElement = displayElement.hide();
	this.targetUrl = targetUrl;


	this.selectedGroup = false;

	this.isShown = false;


	var self = this;
	this.staticHide = function() { self.hide(); }

	this.show = function()
	{
		document.observe('click', this.staticHide);
		this.displayElement.show();
		this.isShown = true;
		this.draw();
	};

	this.hide = function()
	{
		this.displayElement.hide();
		this.isShown = false;
		document.stopObserving('click', this.staticHide);
	};

	this.reset = function()
	{
		this.selectedGroup = false;
		this.draw();
	};

	this.select = function(groupId)
	{
		this.selectedGroup = groupId;
		this.show();
	};

	this.draw = function()
	{
		if (this.isShown)
		{
			if (this.selectedGroup === false)
			{
				this.drawGroups();
			}
			else
			{
				this.drawChoices();
			}
		}
	};

	this.submitChoice = function(choiceId)
	{
		window.location = this.targetUrl + '&' + this.groups[this.selectedGroup].GETName + '=' + this.groups[this.selectedGroup].choices[choiceId].v;
	};

	this.drawGroups = function()
	{
		var self = this;
		this.clear();
		this.displayElement.appendChild(this.getCloseButton());
		this.groups.each(function(group, i) {
			var groupElement = $(Builder.node('div', { className: 'group' }, group.name));

			groupElement.observe('mouseover', function(event) { groupElement.addClassName('onmouseover'); });
			groupElement.observe('mouseout',  function(event) { groupElement.removeClassName('onmouseover'); });
			groupElement.observe('click',     function(event) { Event.stop(event); self.select(i); });

			this.displayElement.appendChild(groupElement);
		}, this);
	};

	this.drawChoices = function()
	{
		this.clear();
		var self = this;
		this.displayElement.appendChild(this.getCloseButton());
		this.groups[this.selectedGroup].choices.each(function(choice, i) {
			var choiceElement =  $(Builder.node('div', { className: 'choice' }, choice.n));
			choiceElement.onmouseover = function() { this.className = 'choice onmouseover'; };
			choiceElement.onmouseout = function() { this.className = 'choice'; };

			choiceElement.observe('mouseover', function(event) { this.addClassName('onmouseover'); });
			choiceElement.observe('mouseout',  function(event) { this.removeClassName('onmouseover'); });
			choiceElement.observe('click',     function(event) { Event.stop(event); self.submitChoice(i); });

			this.displayElement.appendChild(choiceElement);
		}, this);
	};

	this.getCloseButton = function()
	{
		var self = this;

		var buttonImg =  Builder.node('img', { src: 'Pictures/spacer.gif' });

		buttonImg.onclick = function() { self.hide(); self.reset(); };

		var button =  Builder.node('div', { className: 'close' }, [buttonImg]);

		return button;
	};

	this.clear = function()
	{
		this.displayElement.innerHTML = '';
	};

}




var ItemBubble = function()
{

	this.element = false;
	this.contentElement = false;

	this.show = function(itemId)
	{
		if (!this.element) { this.createElements(); }

		this.contentElement.update('');

		var row = this.contentElement.appendChild(Builder.node('table')).appendChild(Builder.node('tbody')).appendChild(Builder.node('tr'));;

		var left = row.appendChild(Builder.node('td'));
		var right = row.appendChild(Builder.node('td'));

		
		var theImg = $(left.appendChild(Builder.node('img', { alt:'', src: 'Pictures/spacer.gif' } )));
		theImg.setStyle({ backgroundImage: 'url('+$('itemImageSrc'+itemId).innerHTML.unescapeHTML()+')', width: '205px', height: '205px'});
		
		$(right.appendChild(Builder.node('h3', $('itemName'+itemId).innerHTML)));
		var links = $(right.appendChild(Builder.node('div', {className:'links'})));

		links.appendChild(Builder.node('a', {href:'javascript:addToWatchList('+itemId+');' }, 'Merken'));
		links.appendChild(Builder.node('span', ' | '));
		links.appendChild(Builder.node('a', {href:'./?element=Item&itemId=' + itemId }, 'Details'));
		$(right.appendChild(Builder.node('div', $('itemDescription'+itemId).innerHTML)));

		this.element.show();
		document.observe('click', this.staticHide);
	};

	var self = this;
	this.staticHide = function()
	{
		self.hide();
	};
	this.hide = function()
	{
		if (!this.element) { this.createElements(); }
		this.element.hide();
	};

	this.createElements = function()
	{
		var container = $(Builder.node('div', { id: 'itemInfo' } ));

		var header         = $(container.appendChild(Builder.node('div', { className: 'header ' } )));
		var contentElement = $(container.appendChild(Builder.node('div', { className: 'content' } )));
		var footer         = $(container.appendChild(Builder.node('div', { className: 'footer ' } )));


		this.element = container;
		this.contentElement = contentElement;

		$('container').appendChild(container);

	};


};

var itemBubble = new ItemBubble();


var ColumnSelector = function()
{
	this.columnChoicesAddress = 'getColumnChoices.html';

	this.selectedColumn = false;

	this.element = false;
	this.contentElement = false;


	this.columns = 3;
	this.minChoicesPerColumn = 3;

	var self = this;

	this.static = {};
	this.static.ensureElement = function() { self.ensureElement(); }



	document.observe('dom:loaded', self.static.ensureElement);
	document.observe('load', self.static.ensureElement);

	this.ensureElement = function()
	{
		if (!this.element)
		{
			this.element = $(Builder.node('div', { id: 'columnSelector' }));
			this.contentElement = $(this.element.appendChild(Builder.node('div', { className: 'IEBUG' })));
			this.element.hide();
			$('middleContent').appendChild(this.element);
		}
	};


	this.showSelection = function(column, columnName)
	{
		this.selectedColumn = column;
		var self = this;
		cursorIcon.show('loading');
		new Ajax.Request(this.columnChoicesAddress,
		{
			method:'get',
			onSuccess: function(transport) { self.paint(column, transport.responseText.evalJSON(true), columnName); },
			onFailure: function()          { messages.showError('Request was not successful.'); },
			onComplete: function() { cursorIcon.hide('loading'); },
			parameters: { column: column }
		});

	};

	this.paint = function(column, choices, columnName)
	{
		var self = this;
		var alphabetChoices = [];

		var idx = -1;

		var previousLetter = '';
		choices.each(function(c)
		{
			var firstLetter = c.charAt(0);

			if (previousLetter != firstLetter)
			{
				idx ++;
				alphabetChoices[idx] = { letter: firstLetter, choices: [] };
				previousLetter = firstLetter;
			}
			alphabetChoices[idx].choices.push(c);
		});


		if (this.selectedColumn != column) { return; }

		this.contentElement.update('');

		this.contentElement.appendChild(Builder.node('div', { className: 'headline' }, dictionary.choose_the_xxx.gsub(/\#\{name\}/, columnName)));
		var theForm = this.contentElement.appendChild(Builder.node('form', { action: '.', method:'get' }));

		var selection = theForm.appendChild(Builder.node('div', { className: 'selection' }));

		selection.appendChild(Builder.node('input', { type:'hidden', name: 'element', value: 'Items' }));

		alphabetChoices.each(function(group)
		{
			if (group) {
				selection.appendChild(Builder.node('h3', group.letter));

				var table = selection.appendChild(Builder.node('table', { cellspacing: 3, width: '100%' })).appendChild(Builder.node('tbody'));;

				var tr = table.appendChild(Builder.node('tr'));

				var td = [];
				for (var i = 0; i < self.columns; i ++)
				{
					td[i] = $(tr.appendChild(Builder.node('td')));
				}
				var choiceCount = group.choices.length;
				var choicesPerColumn = Math.max(Math.ceil(choiceCount / self.columns), self.minChoicesPerColumn);
	
				group.choices.each(function(c, position)
				{
					var tableColumn = Math.floor(position / choicesPerColumn);

					var cont = $(Builder.node('div'));
					cont.appendChild(Builder.node('input', { type: 'checkbox', name: 'columnSearch['+column+'][]', value: c }));
					cont.appendChild(Builder.node('span', c));
	
					td[tableColumn].appendChild(cont);
				});
			}
		});

		var theButton = theForm.appendChild(Builder.node('button', { type: 'submit', className: 'dark' }));



		theButton.appendChild(Builder.node('div')).appendChild(Builder.node('div', dictionary.search));
		this.contentElement.appendChild(Builder.node('a', { className: 'close', href: 'javascript:columnSelector.hide();' })).appendChild(Builder.node('img', { src: 'Pictures/spacer.gif' }));

		this.contentElement.appendChild(Builder.node('div', dictionary.column_selector_comment));

		this.element.show();

// 		document.observe('click', this.static.hide);
	};
	this.hide = function()
	{
		this.element.hide();
// 		document.stopObserving('click', this.static.hide);
	}
	this.static.hide = function() { self.hide(); }

};



var columnSelector = new ColumnSelector();

var Messages = function()
{

	this.errors = new Array();
	this.successes = new Array();

	this.element = false;
	this.contentElement = false;

	this.errorsElement = false;
	this.successesElement = false;
	this.warningsElement = false;

	this.messages = { };

	this.showElementsAfterCreatingElements = false;


	this.init = function()
	{
		var self = this;
		document.observe("dom:loaded", function() { self.ensureContainerElement(); });
	};


	this.showError = function(message) { this.appendError(message); this.show(); }
	this.appendError = function(message)
	{
		this.errors.push(message);
	};

	this.showSuccess = function(message) { this.appendSuccess(message); this.show(); }
	this.appendSuccess = function(message)
	{
		this.successes.push(message);
	};

	this.ensureContainerElement = function()
	{
		if (!this.element)
		{
			if ($('container')) { var parentElement = $('container'); }
			else { var parentElement = document.body; }

			this.element = $(Builder.node('div', {id:'messages'}));

			parentElement.appendChild(this.element);
		}
		if (this.showElementsAfterCreatingElements) { this.show(); }
	};

	this.show = function()
	{
		this.showErrors();
		this.showSuccesses();
		//this.showWarnings();
	};

	this.showErrors    = function() { this.showSomething(this.errors,    'errors');    };
	this.showSuccesses = function() { this.showSomething(this.successes, 'successes'); };
	this.showWarnings  = function() { this.showSomething(this.warnings,  'warnings');  };

	this.showSomething = function(messageList, className, observed)
	{
		if (!this.element) { this.showElementsAfterCreatingElements = true; }
		else
		{
			if (messageList.length > 0)
			{
				var sss = this.createMessages(messageList, className);
				if (sss) { this.element.appendChild(sss); }
				switch(className)
				{
					case 'errors': this.errors = []; break;
					case 'successes': this.successes = []; break;
					case 'warnings': this.warnings = []; break;
				}
			}
		}
	};

	this.createMessages = function(messageList, elementName)
	{
		if (messageList.length > 0)
		{
			var self = this;

			var container = $(Builder.node('div', { className: elementName } ));

			var header         = container.appendChild(Builder.node('div', { className: 'header ' } ));
			var contentElement = container.appendChild(Builder.node('div', { className: 'content' } ));
			var footer         = container.appendChild(Builder.node('div', { className: 'footer ' } ));


			messageList.each(function(message)
			{
				contentElement.appendChild(Builder.node('h1', { }, message));
			});

			var buttonElement = Builder.node('div', { className: 'button' }, 'OK');
			buttonElement.onclick = function() { self.hideMessageBox(container); };
			contentElement.appendChild(buttonElement);

			return container;
		}
	};


	this.hideMessageBox = function(element)
	{
		new Effect.Opacity(element, { duration:0.5, from:1.0, to:0.0, afterFinish: function() { element.hide(); } });
	};

}

var messages = new Messages();
messages.init();

/**
 *
 * This is the Menu class.
 * This class should never be overridden.
 *
 **/

function Menu()
{

	this.isLoading = new Array();

	this.menuAddress = 'menu.html';

	this.ui = { };

	this.items = new Array();
	this.categories = new Array();
	this.categories['0'] = { id: 0, opened: true, name: 'root', children: [], childrenElement: $('navigationChildren'), contentElement: $('navigationContent'), loadingElement: $('navigationLoading'), depth: -1 };

	this.items = new Array(); // The item a category contains

	this.additionalGetParameters = {};
	this.additionalLinkAttributes = '';
	
	this.setAdditionalGetParameters = function(parameters) { this.additionalGetParameters = parameters; }
	this.setAdditionalLinkAttributes = function(addAttributes) { this.additionalLinkAttributes = addAttributes; }

	this.init = function()
	{
		var categoryId = 0;
		this.openCategory(categoryId ? categoryId : 0);
	};
	this.setUI = function(UI)  { this.ui = new UI(this); };


	this.setCategories = function(categories) { this.categories = categories; };


	this.getCategoryById = function(id)
	{
		if (!this.categories[id]) { throw('Category ' + id + ' does not exist'); }

		return this.categories[id];
	};
	this.getItemById = function(id)
	{
		if (!this.items[id]) { throw('Category ' + id + ' does not exist'); }
		return this.items[id];
	};

	this.openCategory  = function(id)
	{
		cookie.set('lastOpenedCategoryId', id);


		cookie.set('openedCategory' + id, '1');

		this.ui.openCategory(id);
		this.categories[id].opened = true;


		if (!this.categories[id].loadedChildren)
		{
			this.loadChildren(id);
		}

	};

	this.loadChildren = function(id)
	{
		if (!this.isLoading[id])
		{
			var hasToLoad = true;
			if (this.categories[id])
			{
				this.categories[id].opened = true;
				//this.ui.openCategory(id);
				if (this.categories[id].loadedChildren) { hasToLoad = false; }
			}

			if (hasToLoad)
			{
				this.ui.loadingCategory(id);
				this.isLoading[id] = true;
				var self = this;
				var getParameters = this.additionalGetParameters;
				getParameters.parentId = id;
				new Ajax.Request(this.menuAddress,
					{
						method:'get',
						onSuccess: function(transport)
						{
							self.loadedChildren(transport.responseText.evalJSON(true), id);
						},
						onFailure: function() { messages.showError('Request was not successfull.'); },
						parameters: getParameters
					});
			}
		}
	};
	this.loadedChildren = function(categories, id)
	{

		this.isLoading[id] = false;
		this.categories[id].loadedChildren = true;

		var categoriesToOpen = new Array();

		var self = this;
		categories.each(
			function(category)
			{
				category = self.addCategory(category);
				if (category.id == selectedCategoryId)
				{
					var breadcrumb = self.getBreadcrumbNavigation(category);
					$$('.breadcrumbNavigation').each(function(el) { el.update(breadcrumb); });
					$$('.allItemsLink')[0].setStyle({ visibility: 'visible' });
					$$('.allItemsLink')[0].href = '?element=Items';
				}
				if (cookie.get('openedCategory' + category.id))
				{
					categoriesToOpen.push(category.id);
				}
			}
		);


		this.ui.loadedCategory(id);

		categoriesToOpen.each(
			function(id)
			{
				self.loadChildren(id);
			}
		);
	};

	this.getBreadcrumbNavigation = function(category, navigation)
	{
		if (navigation == undefined) { navigation = ''; }
		navigation = category.name + navigation;
		if (category.parentId != false)
		{
			navigation = this.getBreadcrumbNavigation(this.getCategoryById(category.parentId), ' / ' + navigation);
		}
		return navigation;
	};

	this.addCategory = function(category)
	{
		var id = category.id;
		var parentId = category.pi;

		if (!this.categories[id])
		{
			this.categories[id] = { children: [], opened: false };
		}

		this.categories[id].id = id;
		this.categories[id].name = category.n;
		this.categories[id].hasChildren = category.hc;
		this.categories[id].itemCount = category.ic;
		this.categories[id].parentId = category.pi;


		if (!this.categories[parentId])
		{
			this.categories[parentId] = { opened: false, name: 'not loaded', children: [] };
			this.categories[parentId].depth = 0;
		}

		this.categories[parentId].children.push(id);
		this.categories[parentId].hasChildren = true; // Just to make sure

		this.categories[id].depth = this.categories[parentId].depth + 1;
		
		return this.categories[id];
	};


	this.loadedCategoryError = function(Result)
	{
		alert('there was an error');
	};

	this.closeCategory = function(id)
	{
		this.categories[id].opened = false;
		cookie.unset('openedCategory' + id);

		this.ui.closeCategory(id);
	};


}

function MenuUI(menu)
{

	this.menu = menu;
	this.divName = 'navigationContent';

	this.element = $('navigationContent');


	this.openCategory = function(id)
	{
		this.showContent(id);
		this.showCloseLink(id);
	};

	this.closeCategory = function(id)
	{
		this.hideContent(id);
		this.showOpenLink(id);
	};


	this.showContent = function(categoryId)
	{

		var category = this.menu.getCategoryById(categoryId);
		if (!category.contentElement.visible())
		{
			category.contentElement.show();
			if (category.childrenElement.visible())
			{
				category.childrenElement.hide();
				this.showChildren(categoryId);
			}
		}
	};
	this.hideContent = function(categoryId)
	{
		var category = this.menu.getCategoryById(categoryId);
		category.contentElement.hide();
	};
	this.showChildren = function(categoryId, effectOptions)
	{
		if (!effectOptions) { effectOptions = {}; }
		if (!effectOptions.duration) { effectOptions.duration = 0.5; }
		var category = this.menu.getCategoryById(categoryId);

		new Effect.Appear(category.childrenElement, effectOptions);
	};
	this.hideChildren = function(categoryId)
	{
		var category = this.menu.getCategoryById(categoryId);
		category.childrenElement.hide();
	};
	this.showLoading = function(categoryId)
	{
		var category = this.menu.getCategoryById(categoryId);
/*		if (category.loadingElement.empty())
		{
			category.loadingElement.className = 'loading';
			category.loadingElement.appendChild(Builder.node('img', { src: 'Templates/Default/Pictures/navigation_loading.gif' }));
		}*/
		category.loadingElement.show();
	};
	this.hideLoading = function(categoryId)
	{
		var category = this.menu.getCategoryById(categoryId);
		category.loadingElement.hide();
	};


	this.showCloseLink = function(id) { this.showOpenCloseLink(id, true); };
	this.showOpenLink  = function(id) { this.showOpenCloseLink(id, false); };

	this.showOpenCloseLink = function(id, closeLink)
	{
		var category = this.menu.getCategoryById(id);
		if (category.closeLinkElement)
		{
			if (closeLink)
			{
				$(category.closeLinkElement).show();
				$(category.openLinkElement).hide();
			}
			else
			{
				$(category.closeLinkElement).hide();
				$(category.openLinkElement).show();
			}
		}
	};


	this.paintChild = function(childId)
	{
		var child = this.menu.getCategoryById(childId);

		if (!child.categoryElement)
		{
			child.categoryElement = $(Builder.node('div', { className: 'category' }));

			child.nameElement = $(Builder.node('div', { className: 'name' }));

			if (childId == selectedCategoryId) { child.nameElement.addClassName('selected'); }

			child.nameElement.observe('mouseover', function() { child.nameElement.addClassName('mouseOver'); });
			child.nameElement.observe('mouseout', function() { child.nameElement.removeClassName('mouseOver'); });




			var closeLink = $(child.nameElement.appendChild(Builder.node('span', { style: 'cursor:pointer; display:none;' })));
			var openLink  = $(child.nameElement.appendChild(Builder.node('span', { style: 'cursor:pointer; display:none;' })));

			openLink.style.display = 'none';
			closeLink.style.display = 'none';

			child.openLinkElement  = openLink;
			child.closeLinkElement = closeLink;


			for (var i = 0; i < child.depth; i++)
			{
				openLink.appendChild(Builder.node('img', {className: 'indentation', alt: '', src:'Pictures/spacer.gif' }));
				closeLink.appendChild(Builder.node('img', {className: 'indentation', alt: '', src:'Pictures/spacer.gif' }));
			}

			if (child.hasChildren)
			{
				closeLink.onclick = function(i) { return function() { self.menu.closeCategory(i); }; }(child.id);
				openLink.onclick  = function(i) { return function() { self.menu.openCategory(i); }; }(child.id);

				var openLinkImage = Builder.node('img', { className: 'plus', alt: '', src:'Pictures/spacer.gif' });
				var closeLinkImage = Builder.node('img', {className: 'minus', alt: '', src:'Pictures/spacer.gif' });


				openLink.appendChild(openLinkImage);
				closeLink.appendChild(closeLinkImage);


				if (child.opened) { this.showCloseLink(child.id); }
				else              { this.showOpenLink(child.id); }

			}
			else
			{
				openLink.setStyle({ cursor: 'default' });
				this.showOpenLink(child.id);
				child.nameElement.appendChild(Builder.node('img', {className: 'spacer', alt: '', src:'Pictures/spacer.gif' }));
			}

			var cccc = $(Builder.node('a', { style: 'display:inline-block;', href: '?element=Items&categoryId=' + child.id + this.menu.additionalLinkAttributes }, child.name + ' (' + child.itemCount + ')'));
			if (child.hasChildren) cccc.observe('click', function() { self.menu.openCategory(child.id); } );
			child.nameElement.appendChild(cccc);

			child.childrenElement = $(Builder.node('div', { className: 'children' } ));
			child.childrenElement.hide();


			child.loadingElement = $(Builder.node('div', { className: 'loading' }));
			child.loadingElement.hide();

			child.contentElement = $(Builder.node('div', { className: 'content' }));
			child.contentElement.appendChild(child.loadingElement);
			child.contentElement.appendChild(child.childrenElement);

			child.categoryElement.appendChild(child.nameElement);
			child.categoryElement.appendChild(child.contentElement);


			parentCategory = this.menu.getCategoryById(child.parentId);
			parentCategory.childrenElement.appendChild(child.categoryElement);

		}
		else { console.debug('This should not happen!'); }

	};


	this.paintChildren = function(id)
	{
		var self = this;
		var category = this.menu.getCategoryById(id);

		if (category.contentElement)
		{
			category.contentElement.hide();
			category.children.each(function(childId) { self.paintChild(childId); } );
		}
		else { console.warn('No category.contentElement... This is no normal behaviour.'); }
	};


	this.loadingCategory = function(id)
	{
		this.showLoading(id);
		this.hideChildren(id);
	};


	this.loadedCategory = function(id)
	{
		var category = this.menu.getCategoryById(id);

		this.paintChildren(id);
		var self = this;
		this.showChildren(id, { beforeUpdate: function(effect) { if(effect.currentFrame == 0) { self.hideLoading(id); } } });
		if (category.opened) { this.openCategory(id); }
	};

}


function ShoppingCart()
{

	this.ui = { };
	this.items = new Array();

	this.cartAddress = 'shoppingCart.html';

	this.isLoading = 0;


	this.init = function()
	{
		this.loadItems({}, true);
	}



	/**
	 * When the submit button to add an item is pressed.
	 */
	this.onItemSubmit = function(id, packagingUnitId)
	{
		var quantity = $('shopItemQuantity' + id + '_' + packagingUnitId).value;
		this.addItem(id, packagingUnitId, quantity);
	};




	this.setUI = function(UI)  { this.ui = new UI(this); };


	this.addItem = function(id, packagingUnitId, quantity)
	{
		if (existingItem = this.getItemByIdAndPackagingUnitId(id, packagingUnitId))
		{
			this.changeItemQuantity(id, packagingUnitId, parseInt(existingItem.quantity) + parseInt(quantity));
		}
		else
		{
			cursorIcon.show('loading');
			this.loadItems({ addItemId: id, addItemQuantity: quantity, packagingUnitId: packagingUnitId }, false, function() { cursorIcon.hide('loading'); });
		}
	};

	this.changeItemQuantity = function(id, packagingUnitId, quantity)
	{
		cursorIcon.show('loading');
		this.loadItems({ itemId: id, quantity: quantity, packagingUnitId: packagingUnitId }, false, function() { cursorIcon.hide('loading'); });
	};




	this.getTotalPrice = function (withTaxes)
	{
		var sum = 0;
		this.items.each(function(thisItem){
			var price = withTaxes ? thisItem['priceWithTaxes'] : thisItem['price'];
			sum += price * thisItem['quantity'];
		});
		return sum;
	};

	this.getTotalInformation = function()
	{
		var information = { price: 0, priceWithTaxes: 0, taxes: 0 };

		this.items.each(function(thisItem) {
			var price = thisItem['price'] * thisItem['quantity'];
			var priceWithTaxes = thisItem['priceWithTaxes'] * thisItem['quantity'];
			information.price          += price;
			information.priceWithTaxes += priceWithTaxes;
			information.taxes          += priceWithTaxes - price;
		});
		return information;
	
	};

	this.getTotalItemCount = function ()
	{
		var sum = 0;
		this.items.each(function(thisItem){
			sum += thisItem['quantity'];
		});
		return sum;
	};



	this.loadItems = function(getVars, firstLoad, onSuccessFunction)
	{
		var self = this;
		this.isLoading ++;
		this.ui.loading();

		new Ajax.Request(this.cartAddress,
		{
			method:'get',
			onSuccess: function(transport)
			{
				var res = transport.responseText.evalJSON(true);
				self.loadedItems(res.items, firstLoad);
				if (res.error) { messages.showError(res.error); }
				if (res.infos) { res.infos.each(function(message) { messages.showError(message); }); }
				if (onSuccessFunction) { onSuccessFunction(); }
			},
			onFailure: function() { messages.showError('Request was not successfull.'); },
			parameters: getVars
		});

	};

	this.loadedItems = function(items, firstLoad)
	{
		this.isLoading = Math.max(0, this.isLoading - 1);

		var newItems    = items.concat();
		var removeItems = this.items.concat();
		var updateItems = new Array();

		var newItems    = new Array();
		var removeItems = new Array();
		var updateItems = new Array();

		var self = this;


		this.items.each(function(existingItem, index)
		{
			if (nnItem = items.find(function(newItem) { return newItem.ABC == existingItem.ABC; }))
			{
				updateItems.push({ newItem: nnItem, existingItem: existingItem });
			}
			else
			{
				removeItems.push(existingItem);
			}
		}, this);

		items.each(function(item) {
			if (!updateItems.find(function(newItem) { return newItem.existingItem.ABC == item.ABC; }))
			{
				newItems.push(item);
			}
		}, this);


		this.items = newItems.concat(updateItems);;


		var realItems = new Array();

		newItems.each(function(item)
		{
			realItems.push(this.ui.addItem(item, firstLoad));
		}, this);

		updateItems.each(function(item)
		{
			realItems.push(this.ui.updateItem(item.newItem, item.existingItem, firstLoad));
		}, this);

		removeItems.each(function(item)
		{
			this.ui.removeItem(item, firstLoad);
		}, this);


		this.items = realItems;
		this.ui.paintItemsHeader();
		if (!this.isLoading) { this.ui.loaded(); }

	};

	this.getItemByIdAndPackagingUnitId = function(id, packagingUnitId)
	{
		return this.items.find(function(item) { return item.ABC == id + '.' + packagingUnitId; });
	};

	this.removeItemByIdAndPackagingUnitId = function(id, packagingUnitId)
	{
		if (existingItem = this.getItemByIdAndPackagingUnitId(id, packagingUnitId))
		{
			console.info('Removing item from shopping cart. ID:', id);
			this.loadItems({ removeItemId: id, packagingUnitId: packagingUnitId });
		}
	};


}

function ShoppingCartUI(shoppingCart)
{

	this.shoppingCart = shoppingCart;

	this.element = $('shoppingCart');

	this.loadingElement = $('sCloading');
	this.emptyElement = $('sCempty');
	this.itemsElement = $('sCitems').hide();
	this.itemsHeaderElement = $('sCitemsHeader');
	this.itemsListElement = $('sCitemsList');


	var text = '';
	text += '<table border="0" width="100%"><tr><td colspan="2" style="position: relative"><div class="name">#{name}</div> <a class="removeButton" href="javascript:shoppingCart.removeItemByIdAndPackagingUnitId(#{id}, #{packagingUnitId});"><img src="Pictures/spacer.gif" alt="" /></a></td></tr>';
	text += '<tr><td><div class="quantity"><input onchange="javascript:ensureValue.integer(this); shoppingCart.changeItemQuantity(#{id}, #{packagingUnitId}, this.value);" type="text" maxlength="6" value="#{quantity}" /></div></td>';
	text += '<td><div class="price"> #{displayPrice} #{currencySign}</div></td>';
	text += '</tr><tr><td><div><em>#{packagingUnitName}</em></div></td></tr></table>';
	this.itemTemplate = new Template(text);

	this.addElement = function()
	{
		this.hideEmpty();
		this.showItems();
	};

	this.showLoading = function() { this.loadingElement.style.visibility = 'visible'; }
	this.hideLoading = function() { this.loadingElement.style.visibility = 'hidden'; }
	this.showEmpty   = function() { this.emptyElement.show(); }
	this.hideEmpty   = function() { this.emptyElement.hide(); }
	this.showItems   = function() { this.itemsElement.show(); }
	this.hideItems   = function() { this.itemsElement.hide(); }

	this.getDisplayAmount = function(amount)
	{
		var prefix = parseInt(amount / 100);
		var suffix = amount - (prefix * 100);
		return prefix + '.' + suffix;
	};

	this.paintItemsHeader = function()
	{
		var information = this.shoppingCart.getTotalInformation();

		$('sCtotalPrice').update(this.getDisplayAmount(information.price));
		$('sCtotalPriceWithTaxes').update(this.getDisplayAmount(information.priceWithTaxes));
		$('sCtotalTaxes').update(this.getDisplayAmount(information.taxes));
		$('sCitemCount').update(this.shoppingCart.getTotalItemCount());
	};

	this.addItem = function(item, noEffect)
	{
		this.hideEmpty();
		this.showItems();

		var companyContainer = false;
		var createdContainer = false;

		if (!(companyContainer = this.itemsListElement.select('#companyContainer' + item.companyId).first()))
		{
		
			companyContainer = $(this.itemsListElement.appendChild($(Builder.node('div', { id: 'companyContainer' + item.companyId, className: 'companyContainer', style: 'display: none' }))));
			companyContainer.update('<br />');
			companyContainer.appendChild($(Builder.node('div', { className: 'companyName' }, item.companyName)));
			// The showing is done later on.

			createdContainer = true;
		}

		var itemElement = $(Builder.node('div', { className: 'item' }));

		var displayPrice = displayPricesWithTaxes ? item.priceWithTaxes : item.price;
		item.displayPrice = this.getDisplayAmount(displayPrice);

		if (item.packagingUnitId == 0) { item.packagingUnitName = ''; }

		item.currencySign = dictionary.currency_sign;

 		itemElement.update(this.itemTemplate.evaluate(item));


		itemElement.style.display = 'none';
		item.element = itemElement;
		itemElement = $(companyContainer.appendChild(itemElement));

		if (noEffect || createdContainer || isInternetExplorer()) { item.element.show(); }
		else { new Effect.BlindDown(item.element, { duration: 1.0 }); }

		if (createdContainer && !noEffect && !isInternetExplorer()) { companyContainer.blindDown(); }
		else if (createdContainer) { companyContainer.show(); }

		return item;
	};

	this.removeItem = function(item, noEffect)
	{
		var self = this;
		var afterFinish = function()
		{
			item.element.remove();
			var containerElement = self.itemsListElement.select('#companyContainer' + item.companyId).first();
			if (!containerElement.select('.item').first())
			{
				if (noEffect)
				{
					containerElement.remove();
				}
				else
				{
					containerElement.blindUp({ afterFinish: function() { containerElement.remove(); } });
// 					containerElement.fade({ afterFinish: function() { containerElement.blindUp({ afterFinish: function() { containerElement.remove(); } }) } });
				}
			}
		};
		if (this.shoppingCart.getTotalItemCount() == 0)
		{
			var self = this;
			afterFinish = function() { self.hideItems(); self.showEmpty(); };
		}
		if (noEffect) { afterFinish(); }
		else { new Effect.BlindUp(item.element, { duration: 1.0, afterFinish: afterFinish }); }
	};

	this.updateItem = function(newItem, existingItem, noEffect)
	{
		newItem.element = existingItem.element;
		if (newItem.quantity != existingItem.quantity ||
			newItem.price != existingItem.price ||
			newItem.name != existingItem.name)
		{

			if (newItem.packagingUnitId == 0) { newItem.packagingUnitName = ''; }

			var displayPrice = displayPricesWithTaxes ? newItem.priceWithTaxes : newItem.price;
			newItem.displayPrice = this.getDisplayAmount(displayPrice);
			newItem.element.update(this.itemTemplate.evaluate(newItem));

			if (!noEffect) { new Effect.Highlight(newItem.element); }
		}
		return newItem;
	};

	this.setItems = function(items)
	{
		this.showItems();
		if (items.length > 0)
		{
			this.paintItemsHeader();
			this.showItems();
			this.hideEmpty();
		}
		else
		{
			this.showEmpty();
			this.hideItems();
		}
		var self = this;
		items.each(function(item){
			self.addItem(item);
		});
	};


	this.loading = function()
	{
		this.showLoading();
	};
	this.loaded = function()
	{
		this.hideLoading();
	};

}

