
var figgjo = {};

(function($) {

figgjo = {

    tableSettings: [],
    tableSettingSolutionMap: null,
    currentTableSettingIndex: 0,
    
    showroomUseLazyImageLoadingOvershoot: 300, 
    showroomUseLazyImageLoading: true,
    showroomUseLazyImageLoadingFader: !(/MSIE/.test(navigator.userAgent)),
    showroomUseLazyImageLoadingUnloaded: [], 
    showroomProductlistThumbnailHeight: 110,
    showroomProductlist: [],
    showroomBasketContent: {},
    showroomProductInfoDialog: null,
    showroomKey: 'professional',
    showroomMapSolutions: {},
    showroomMapSeries: {},
    showroomMapSubseries: {},
    showroomMapForms: {},
    showroomMapDesigns: {},
    showroomMapMeals: {},
    showroomMapCategories: {},
    showroomMapFirmagave: {},
    showroomFilterOptions: {},
    showroomFilterHasSeparateAllSelect: true, // false for MobileSafari
    showroomHelpTitle: '',
    showroomSendInquiryTitle: 'Inquiry', 
    showroomi18nAddToBasket: 'ADD TO SOLUTION',
    showroomi18nRemoveFromBasket: 'REMOVE FROM SOLUTION',
    showroomi18nReplaceTitle: 'Change basket content?',
    showroomi18nReplaceText: 'Replace showroom basket content with products from link?',
    showroomi18nReplaceKeepOriginal: 'Keep original basket content',
    showroomi18nReplaceKeepLink: 'Replace with new products',
    showroomi18nReplaceMerge: 'Merge basket content with new products',
    showroomi18nSendToAFriendTitle: 'Share with a friend',
    
    showroomi18nProductInfoLabelSeries: 'Series',
    showroomi18nProductInfoLabelType: 'Type',
    showroomi18nProductInfoLabelDesigner: 'Designer',
    showroomi18nProductInfoLabelFirmagave: 'Company gift',
    showroomi18nProductInfoLabelLaunchyear: 'Launchyear',
    showroomi18nProductInfoLabelLength: 'Length',
    showroomi18nProductInfoLabelWidth: 'Width',
    showroomi18nProductInfoLabelHeight: 'Height',
    showroomi18nProductInfoLabelVolume: 'Volume',
    showroomi18nProductInfoLabelPrice: 'Price',
    showroomi18nProductInfoLabelOldPrice: 'Old price',
    showroomi18nProductInfoLabelSpecialPrice: 'Special price',
    showroomi18nOptionAll: 'ALL',
    
    hasWallpaper: false,
    resizeDiv: null,
    resizeDivSibling: null,
    resizeTimeout: false,
    resizeDivTimeoutFunction: null,
    
    htmlEscape: function(text) {
        return $('<div/>').text(String(text)).html();
    },
    
    onDocumentReady: function() {
        $(window).resize($.proxy(this.onWindowResize, this));
        this.onWindowResize();
        // Clicks on popup content should not toggle popup
        $(".figgjo-footer-popup").click(function(event){event.stopPropagation();});
        this.placeHeading();
    },
    
    placeHeading: function() {
    	var content = $('.content:first');
    	var heading = $('#figgjo-page-heading');
    	if (content.length == 1 && heading.length == 1) {
    		var contentOffset = content.offset();
    		var headingHeight = heading.height();
    		heading.css('top', contentOffset.top - headingHeight - 36);
    	}
    },
    
    setHeadingHtmlContent: function(content) {
    	$('#figgjo-page-heading').html(content);
    	this.placeHeading();
    },
    
    getHeadingHtmlContent: function(content) {
        return $('#figgjo-page-heading').html();
    },
    
    loadTableSettings: function() {
    	this.displayLoader();
        $.getJSON(figgjo_globals.baseURL+'figgjo/ajax/tablesettings', $.proxy(this.onLoadTableSettingsComplete, this));
    },
    
    displayLoader: function() {
    	var container = $('body');
    	var loader = $('<div/>').attr('id', 'loader').addClass('loader');
    	container.append(loader);
    	var windowWidth = $(window).width();
    	var windowHeight = $(window).height();
    	var loaderWidth = loader.width();
    	var loaderHeight = loader.height();
    	loader.css('top', (windowHeight - loaderHeight) / 2 + 'px').css('left', (windowWidth - loaderWidth) / 2 + 'px');
    	this.galleryListDisplayed = false;
    	this.galleryDisplayed = false;
    },
    
    removeLoader: function() {
    	$('#loader').remove();
    },

    onLoadTableSettingsComplete: function(json) {
    	this.removeLoader();
        this.tableSettingSolutionMap = {}; // map from solution id to array of tablesettings
        var that = this;
        $.each(json.tablesettings, function(tsidx,tablesetting) {
        	$.each(tablesetting.tablesettingProducts.solutions, function(sidx, solutionId) {
        		if (!that.tableSettingSolutionMap.hasOwnProperty(solutionId)) {
        			that.tableSettingSolutionMap[solutionId] = [];
        		}
        		that.tableSettingSolutionMap[solutionId].push(tablesetting);
        	}); 
        });
        
        // Replace links to showroom
        var changeLink = $('<a/>').attr('href', figgjo_globals.baseURL + 'figgjo/showroom/professional');
        changeLink.attr('id', 'figgjo-tablesetting-change-button').addClass('figgjo-showroom-link');
        $('#figgjo-tablesetting-change-button-container').append(changeLink);
        
        $(".figgjo-showroom-link").click($.proxy(this.navigateFromTableSettingToShowroom, this));
        
        if (this.tableSettingSolutionMap.hasOwnProperty(0)) {
        	this.tableSettings = this.tableSettingSolutionMap[0];
        }
        
        var list = $("#figgjo-tablesetting-solution-list");
        $.each(json.solutions, function(idx, obj) {
        	if (that.tableSettingSolutionMap.hasOwnProperty(obj['id'])) {
        		var item = $('<li/>').append(obj['label']).data('solutionId', obj['id']);
        		item.click(function() {
        			var solutionId = $(this).data('solutionId');
        			$("#figgjo-tablesetting-solution-list li").each(function(idx, element) {
        				if ($(element).data('solutionId') == solutionId) {
        					$(element).addClass('selected');
        				} else {
        					$(element).removeClass('selected');
        				}
        				that.tableSettings = that.tableSettingSolutionMap[solutionId];
        				that.initializeTableSetting();
        			});
        		});
        		list.append(item);
        		if (that.tableSettings == null) {
        			that.tableSettings = that.tableSettingSolutionMap[obj['id']]; // select first.. not certain this is the best way..
        			item.addClass("selected");
        		}
        	}
        });
        this.setupTooltips('#backstretch img');
        this.initializeTableSetting();
    },
    
    initializeTableSetting: function() {
        // create pager content
        var pager = $('#figgjo-tablesetting-pager');
        pager.empty();
        
        if (this.tableSettings.length > 1) {
        	$('#figgjo-tablesetting-prev-button').fadeIn();
        	$('#figgjo-tablesetting-next-button').fadeIn();
            $.each(this.tableSettings, function(idx,obj) {
                var newpage = $('<li><img src="../figgjo-data/pager_item.gif" width="4px" height="4px" border="0"/></li>');
                newpage.data('idx', idx);
                pager.append(newpage);
            });
            $("#figgjo-tablesetting-pager li").click($.proxy(this.onTableSettingPagerClick, this));
        } else {
        	$('#figgjo-tablesetting-prev-button').fadeOut();
        	$('#figgjo-tablesetting-next-button').fadeOut();
        }
        
        // initialize table settings hover and click handling
        this.showTableSetting(0);
    },
    
    setupTooltips: function(imageQuery) {
    	this.tooltipImageQuery = imageQuery;
        $(document).mousemove($.proxy(this.onTooltipDocumentMouseMove, this));
        $(window).resize($.proxy(this.tooltipAdjustProductTooltipPosition, this));
    },
    
    tooltipImageQuery: null,
    tooltipCurrentClosestProduct: null,
    tooltipProducts: null,
    
    onTableSettingMouseClick: function(e) {
    	this.tooltipUpdateClosestProduct(e.pageX, e.pageY);
    },
    
    onTooltipDocumentMouseMove: function(e) {
    	this.tooltipUpdateClosestProduct(e.pageX, e.pageY);
    },
    
    tooltipUpdateClosestProduct: function(pageX, pageY) {
    	var img = $(this.tooltipImageQuery);
    	var imgOffset = img.offset();
    	var imgWidth = img.width();
    	var imgHeight = img.height();
    	var products = this.tooltipProducts;
    	if (imgOffset != null && products != null) {
	    	var x = parseInt((pageX - imgOffset.left) / img.width() * 65536);
	    	var y = parseInt((pageY - imgOffset.top) / img.height() * 65536);
	        var closestProduct = null;
	        var closestDistance = 0;
	        if (products instanceof Array) {
		        $.each(products, function(index, obj) {
		        	if (Math.abs(x - obj.x) < 5000 && Math.abs(y - obj.y) < 5000) {
		        		var distSquared = (x - obj.x) * (x - obj.x) + (y - obj.y) * (y - obj.y);
		        		if (distSquared < 25000000) {
		        			if (closestProduct == null) {
		        				closestProduct = obj;
		        				closestDistance = distSquared;
		        			} else if (distSquared < closestDistance) {
		        				closestProduct = obj;
		        				closestDistance = distSquared;
		        			}
		        		}
		        	}
		        });
	        }
	        if (closestProduct != this.tooltipCurrentClosestProduct) {
		        if (this.tooltipCurrentClosestProduct != null) {
		        	this.tooltipHideProductTooltip();
		        }
		        this.tooltipCurrentClosestProduct = closestProduct;
		        if (this.tooltipCurrentClosestProduct != null) {
		        	this.tooltipShowProductTooltip();
		        }
	        }
    	}
    },
    
    tooltipHideProductTooltip: function() {
    	jQuery('#product-tooltip').remove();
    },
    
    tooltipShowProductTooltip: function() {
    	var product = this.tooltipCurrentClosestProduct;
    	var tooltip = $('<div/>').attr('id', 'product-tooltip')
    							 .addClass('left')
    							 .append(product.label);
    	$('body').prepend(tooltip);
    	this.tooltipAdjustProductTooltipPosition();
    },
    
    tooltipAdjustProductTooltipPosition: function() {
    	if (this.tooltipCurrentClosestProduct != null) {
    		var product = this.tooltipCurrentClosestProduct;
    		var tooltip = $('#product-tooltip');
    		var tooltipWidth = tooltip.outerWidth();
    		var tooltipHeight = tooltip.outerHeight();
        	var img = $(this.tooltipImageQuery);
        	var imgOffset = img.offset();
        	var imgWidth = img.width();
        	var imgHeight = img.height();
        	var left = imgOffset.left + product.x / 65536 * imgWidth;
        	var top = imgOffset.top + product.y / 65536 * imgHeight - tooltipHeight;
        	if (left > $(window).width() / 2) {
        		tooltip.removeClass('left').addClass('right');
        		left -= tooltipWidth;
        	} else {
        		tooltip.removeClass('right').addClass('left');
        	}
    		tooltip.css({top: top + 'px', left: left + 'px'});
    	}
    },
    
    showTableSetting: function(tableSettingIndex) {
        this.currentTableSettingIndex = tableSettingIndex;
        // update pager
        $("#figgjo-tablesetting-pager li").each(function(idx,obj) {
            if (idx == tableSettingIndex) {
                $(obj).addClass('selected');
            }
            else {
                $(obj).removeClass('selected');
            }
        });
        // Set up background image
        var tableSetting = this.tableSettings[tableSettingIndex];
        if (tableSetting) {
            this.setWallpaper(tableSetting.tablesettingImage);
            this.tooltipProducts = tableSetting.tablesettingProducts.tags;
        }
        
        this.tooltipHideProductTooltip();
        this.tooltipCurrentClosestProduct = null;
    },
    
    setWallpaper: function(imgurl) {
        this.hasWallpaper = true;
        $("#backstretch").remove();
        $.backstretch(imgurl, {speed: 1000});
        $('#backstretch img').click($.proxy(this.onTableSettingMouseClick, this));
    },
    
    onTableSettingPagerClick: function(event) {
        var clickedDiv = event.currentTarget;
        var idx = $(clickedDiv).data('idx');
        this.showTableSetting(idx);
    },
    
    navigateFromTableSettingToShowroom: function(event) {
        // Collect current table setting contents and transfer to showroom
        var currentTableSetting = this.tableSettings[this.currentTableSettingIndex];
        var ahref = event.target;
        var baseurl = ahref.href;
        var productCodeList = [];
        var productCodeMap = {};
        $.each(currentTableSetting.tablesettingProducts.tags, function(idx,el) {
            if (!(el.label in productCodeMap)) {
                productCodeList.push(el.label);
                productCodeMap[el.label] = true;
            }
        });
        productCodeList.sort();
        location.href = baseurl + '#/' + productCodeList.join(',');
        return false;
    },
    
    showroomInit: function() {
        var that=this;
        this.resizeDiv = $('#figgjo-showroom-basket');
        this.resizeDivSibling = $('#figgjo-showroom-productlist-options');
        this.resizeDivTimeoutFunction = function(){that.showroomBasketReflow(true);};
        this.onWindowResize();
        this.displayLoader();
        this.showroomLoadProductlist();
        // this.showroomHelpFirst();
        // add automagic repositioning of dialogs on window resize
        $(window).resize($.proxy(this.repositionDialogs, this));
    },
    
    repositionDialogs: function() {
        $(".ui-dialog-content:visible").each(function() {
            var dialog = $(this).data( "dialog" );
            dialog.option( "position", dialog.options.position );
        });
    },
    
    showroomLoadProductlist: function() {
        $.getJSON(figgjo_globals.baseURL+'figgjo/ajax/productlist/showroomKey/'+this.showroomKey, $.proxy(this.onLoadShowroomProductlistComplete, this));
    },
    
    showroomOpenDialog: function(html, element, title) {
        var that=this;
        var pos = $(element).offset();
        // reset options since possibly modal
        this.showroomProductInfoDialog.dialog('option', {minWidth: 500, height: 'auto', modal: false, hide:'fade', show:'fade', title: title});
        this.showroomProductInfoDialog.dialog('open');
        this.showroomProductInfoDialog.dialog('widget');
        var elementPosition = $(element).offset();
        this.showroomProductInfoDialog.html(html);
        // ie7 workaround
        if (/MSIE 7\.0/.test(navigator.userAgent)) {
            var width = this.showroomProductInfoDialog.parent().find('.ui-dialog-content').outerWidth()
            this.showroomProductInfoDialog.parent().find('.ui-dialog-titlebar').width(width);
            this.showroomProductInfoDialog.parent().find('.ui-dialog-content').width(width);
        }
        
        $(window).unbind("resize.dialog");
        $(window).bind("resize.dialog", $.proxy(this.showroomPositionDialog, this));
        this.showroomPositionDialog();
    },
    
    showroomCloseDialog: function() {
        this.showroomProductInfoDialog.dialog('close');
        $(window).unbind("resize.dialog");
    },
    
    showroomPositionDialog: function() {
        this.showroomProductInfoDialog.parent('.ui-dialog').position({my:'center', at:'center', of: window});
    },
    
    showroomHelp: function() {
        var helpDialog = $('<div style="display:none"><div class="loader" style="margin: 100px auto; position: static; display: block; padding: 0 auto">&nbsp;</div></div>').appendTo('body');
        setTimeout(function(){ helpDialog.bind('clickoutside', function(e) { helpDialog.remove(); }); }, 1);
        helpDialog.dialog({modal: true, width: 500, height:350, title:this.showroomHelpTitle,show:'fade', draggable: false, resizable: false, close:function(){$(this).remove();}});
        var that = this;
        helpDialog.load(figgjo_globals.baseURL+'figgjo/article/viewajax/showroomhelp-'+this.showroomKey, function(response) {
            // get the h1 (page title) move it's content to dialog title
            var h1 = $(this).find('h1');
            var text = h1.text();
            h1.remove();
            $(this).parents('.ui-dialog').first().find('span.ui-dialog-title').text(text);
            that.repositionDialogs();
        });
    },
    
    showroomHelpFirst: function() {
    	var showroomHelpCookie = ''+$.cookie('figgjo_showroom_helpinit');
    	var showroomValues = showroomHelpCookie.split(',');
    	if (-1 == $.inArray(this.showroomKey, showroomValues)) {
    		showroomValues.push(this.showroomKey);
            $.cookie('figgjo_showroom_helpinit', showroomValues.join(','));
            this.showroomHelp(); 
        }
    },
    
    showroomProductMultiValueAsString: function(productAttributeKeys, productAttributeMap) {
        if (typeof productAttributeKeys == "string" && productAttributeKeys.length > 0) {
            var result = [];
            var keysArray = productAttributeKeys.split(',');
            for (var i=0; i< keysArray.length; i++) {
                if (productAttributeMap.hasOwnProperty(keysArray[i])) {
                    result.push(productAttributeMap[keysArray[i]]);
                }
            }
            return result.join(', ');
        }
        return ''; 
    },
    
    showroomOpenDialogForProductId: function(productId, element) {
    	var that=this;
        var product = this.showroomProductlist[productId];
        if (this.showroomBasketContent[productId]) {
            var button = '<span class="figgjo-spanbutton" style="float: left" onclick="figgjo.showroomRemoveProductFromBasket(\''+productId+'\', true);">'+that.showroomi18nRemoveFromBasket+'</span>';
        }
        else {
            var button = '<span class="figgjo-spanbutton" style="float: left" onclick="figgjo.showroomAddProductToBasket(\''+productId+'\', true);">'+that.showroomi18nAddToBasket+'</span>';
        }
        var specsHTML = '<table class="product-info-table">'
                       +'<tr><th colspan="2">' + product.name + '</th></tr>'
                       +'<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelSeries)+':</td><td>'+this.htmlEscape($.map(product.series.split(','), function(seriesElement, idx){return that.showroomMapSeries[seriesElement];}).join(', '))+'</td></tr>'
                       +'<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelType)+':</td><td>'+this.htmlEscape($.map(product.categories.split(','), function(categoriesElement, idx){return that.showroomMapCategories[categoriesElement].label;}).join(', '))+'</td></tr>'
                       +(product.designer?'<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelDesigner)+':</td><td>'+this.htmlEscape(product.designer)+'</td></tr>':'')
                       +(product.hasOwnProperty('firmagave') ? '<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelFirmagave)+':</td><td>'+this.htmlEscape($.map(product.firmagave.split(','), function(firmagaveElement, idx){return that.showroomMapFirmagave[firmagaveElement];}).join(', '))+'</td></tr>' : '')
                       +'<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelLaunchyear)+':</td><td>'+this.htmlEscape(product.launchyear)+'</td></tr>'
                       +(product.length?'<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelLength)+':</td><td>'+this.htmlEscape(product.length)+' cm</td></tr>':'')
                       +(product.width?'<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelWidth)+':</td><td>'+this.htmlEscape(product.width)+' cm</td></tr>':'')
                       +(product.height?'<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelHeight)+':</td><td>'+this.htmlEscape(product.height)+' cm</td></tr>':'')
                       +(product.volume?'<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelVolume)+':</td><td>'+this.htmlEscape(product.volume)+' cl</td></tr>':'')
                       +(product.hasOwnProperty('price') ? (product.hasOwnProperty('specialPrice') ? '<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelSpecialPrice)+':</td><td style="color:#ff0000;">'+this.htmlEscape(product.specialPrice)+'</td></tr><tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelOldPrice)+':</td><td style="text-decoration: line-through;">'+this.htmlEscape(product.price)+'</td></tr>' : '<tr><td>'+this.htmlEscape(this.showroomi18nProductInfoLabelPrice)+':</td><td>'+this.htmlEscape(product.price)+'</td></tr>') : '')
                       +'<tr><td colspan="2" class="button-container">' + button + '</td></tr>'
                       +'</table>';
        var html = '<table class="product-info-popup-table"><tr><td style="text-align:center; min-width:200px;"><img src="'+this.htmlEscape(product.image)+'"></td><td class="product-dialog-separator">&nbsp;</td><td align="center">'+specsHTML+'</td></tr></table><br>';
        this.showroomOpenDialog(html, element, '');
    },
    
    parseFloatOrZero: function(val) {
        var f = parseFloat(val);
        return (f > 0 ? f : 0); 
    },
    
    objectKeysToArray: function(obj) {
    	var result = [];
    	for (var key in obj) result.push(this.parseFloatOrZero(key));
    	result.sort(function(a,b){ return (a-b); });
    	return result;
    },
    
    showroomFixMobileSafari: function() {
    	var that = this;
    	this.showroomFilterHasSeparateAllSelect = false;
    	
    	$.each(['solution', 'series', 'subseries', 'categories', 'firmagave', 'length', 'width', 'height', 'volume'], function(idx,val) {
    		that.showroomFilterOptions[val] = '<option value="0" selected>'+that.showroomi18nOptionAll+'</option>' + that.showroomFilterOptions[val];
    		$('#figgjo-showroom-productlist-filter-'+val+'-all').remove();
    		$('#figgjo-showroom-productlist-filter-'+val)
    			.attr('size', '1')
    			.addClass('mobilesafari')
    			.attr('onchange', '')
    			.bind('blur', function(){ that.showroomSearchFilterUpdate(val); })
    			;
    	});
    	$('#figgjo-showroom-productlist-filters').addClass('mobilesafari');
    },
    
    
    onProductlistVisibilityUpdateTimeout: null,
    
    onProductlistVisibilityUpdate: function() {
    	var that=this;
    	if (that.onProductlistVisibilityUpdateTimeout) {
    		clearTimeout(that.onProductlistVisibilityUpdateTimeout);
    	}
    	that.onProductlistVisibilityUpdateTimeout = setTimeout(function() {
    		that.onProductlistVisibilityUpdateReal();
    	}, 10);
    },
    
    onProductlistVisibilityUpdateReal: function() {
    	var that=this;
    	if (!this.showroomUseLazyImageLoading) return;
    	var now = new Date().getTime();
    	var productlistScrollLeft  = $("#figgjo-showroom-productlist").scrollLeft() - that.showroomUseLazyImageLoadingOvershoot;
    	var productlistScrollWidth = $("#figgjo-showroom-productlist").width();
    	var productlistScrollRight = productlistScrollLeft + productlistScrollWidth + 2*that.showroomUseLazyImageLoadingOvershoot;
    	
    	var unloadedLength = this.showroomUseLazyImageLoadingUnloaded.length;
    	var foundImages = false;
    	for (var i=0; i<unloadedLength; i++) {
    		var $img = this.showroomUseLazyImageLoadingUnloaded[i];
    		var imgParent = $img.attr('parentNode');
    		//if ($img.is(':visible')) {
    		if (imgParent.style.display != 'none') {
        		// var imgleft= $img.attr('offsetLeft'); // doesn't work properly in IE7, use parent instead
        		var imgleft= imgParent.offsetLeft;
        		var imgwidth = $img.width();
        		if (
        				(imgleft+imgwidth >= productlistScrollLeft) 
        				&& 
        				(imgleft <= productlistScrollRight)
    				) {
        			foundImages = true;
        			if (that.showroomUseLazyImageLoadingFader) {
        				$img.one('load', function(){$(this).fadeTo(200,1.0);});
        				$img.removeClass('figgjo-unloaded').css('opacity', 0).attr('src', $img.data('realsrc'));
        			}
        			else {
        				(function ($img) {
        					setTimeout(function() {
        						// MSIE is real slow to do .attr('src') on image, do it async
        						$img.removeClass('figgjo-unloaded').attr('src', $img.data('realsrc'));
        					}, 10);
        				})($img); 
        			}
        			
        			this.showroomUseLazyImageLoadingUnloaded.splice(i, 1);
        			unloadedLength--;
        			i--;
        		}
        		else {
        			// Walked off the right edge, no more visible images
        			if (foundImages) return;
        		}
    		}
    	}
    },
    
    onLoadShowroomProductlistComplete: function(json) {
        var that=this;
        
        this.removeLoader();
        
        this.showroomProductlist    = json.products;
        this.showroomMapSolutions   = json.solutions;
        this.showroomMapSeries      = json.series;
        this.showroomMapSubseries   = json.subseries;
        this.showroomMapForms       = json.forms;
        this.showroomMapDesigns     = json.designs;
        this.showroomMapMeals       = json.meals;
        this.showroomMapCategories  = json.categories;
        this.showroomMapFirmagave   = json.firmagave;
        
        this.showroomProductInfoDialog = $('<div></div>').html('Loading product info').dialog({autoOpen:false, draggable:false, resizable:false, title:'', hide:'fade', show:'fade', minWidth:550, width:'auto', height: 'auto'});
        this.showroomProductInfoDialog.bind('clickoutside', function(e){
            that.showroomCloseDialog();
        });

        var showroomProductLengths = {};
        var showroomProductWidths = {};
        var showroomProductHeights = {};
        var showroomProductVolumes = {};

        var listContainer = $("#figgjo-showroom-productlist");
        var clickProxy = $.proxy(this.onShowroomProductItemClick, this);
        var dblclickProxy = $.proxy(this.onShowroomProductItemDoubleClick, this);
        
        var listTable = $('<div />');
        var targetDPI = 100;
        $.each(this.showroomProductlist, function(idx,product) {
        	if (product.length) showroomProductLengths[product.length] = true;
        	if (product.width)  showroomProductWidths[product.width] = true;
        	if (product.height) showroomProductHeights[product.height] = true;
        	if (product.volume) showroomProductVolumes[product.volume] = true;
        	if (product.width) {
        		var thumbWidth = (product.imagehighsizex/product.imagehighsizey)*that.showroomProductlistThumbnailHeight;
        		var thisDPI = thumbWidth / Math.max(product.width, product.length);
        		if (!isNaN(thisDPI)) {
        		    targetDPI = Math.min(targetDPI, thisDPI);
        		}
        	}
        });
        
        $.each(this.showroomProductlist, function(idx,product) {
        	var d  = $('<div />').addClass('figgjo-product');
        	var thumbWidth = (product.imagehighsizex/product.imagehighsizey)*that.showroomProductlistThumbnailHeight;
        	var imageDPI = thumbWidth / Math.max(product.width, product.length);
        	var scaling = (targetDPI/imageDPI)*0.75+0.25;
        	if (that.showroomUseLazyImageLoading) {
        		var $img = $('<img class="figgjo-unloaded" />').attr({src: '/figgjo-data/transp.gif', width: Math.floor(scaling*thumbWidth), height: Math.floor(scaling*that.showroomProductlistThumbnailHeight)})
    			.data('realsrc', product.image);
            	d.append($img);
            	that.showroomUseLazyImageLoadingUnloaded.push($img);
        	}
        	else {
            	d.append($('<img />').attr({src: product.image, width: Math.floor(scaling*thumbWidth), height: Math.floor(scaling*that.showroomProductlistThumbnailHeight)}));
        	}
        	d.append($('<br />'));
        	d.append($('<div />').append(document.createTextNode(product.name)));
        	d.data('productid', idx);
        	d.click(clickProxy);
        	d.dblclick(dblclickProxy);
        	listTable.append(d);
        });
        
        listContainer.empty();
        listContainer.append(listTable);
        listContainer.scroll(function(e){
        	that.onProductlistVisibilityUpdate(); // force recalculation of visible products
        });
        this.onWindowResize();
        
        that.showroomFilterOptions['solution'] = '';
        that.showroomFilterOptions['series'] = '';
        that.showroomFilterOptions['subseries'] = '';
        that.showroomFilterOptions['categories'] = '';
        that.showroomFilterOptions['firmagave'] = '';
        that.showroomFilterOptions['length'] = '';
        that.showroomFilterOptions['width']  = '';
        that.showroomFilterOptions['height'] = '';
        that.showroomFilterOptions['volume'] = '';

        
        
        if (/AppleWebKit.*Mobile.*Safari/.test(navigator.userAgent)) {
        	// iPhone/iPad MobileSafari has a very different <select> implementation, where onChange doesn't fire etc.
            // iPad 3.2:         Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-su) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Sarari/531.21.10
            // iPhone 3GS 4.2.1: Mozilla/5.0 (iPhone; U, CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML; like Gecko) Version/5.0.2 Mobile/8C148a Safari/6533.18.5 
        	this.showroomFixMobileSafari();
    	}
        
        // Create filters
        if ($('#figgjo-showroom-productlist-filter-solution').length > 0) {
	        $.each(this.showroomMapSolutions, function(key, val) {
	        	that.showroomFilterOptions['solution'] += '<option value="'+key+'"'+(key == 0 ? ' selected':'')+'>'+that.htmlEscape(val)+'</option>';
	        });
	        $('#figgjo-showroom-productlist-filter-solution').append(that.showroomFilterOptions['solution']);
        }

        if ($('#figgjo-showroom-productlist-filter-series').length > 0) {
	        $.each(this.showroomMapSeries, function(key, val) {
	        	that.showroomFilterOptions['series'] += '<option value="'+key+'"'+(key == 0 ? ' selected':'')+'>'+that.htmlEscape(val)+'</option>';
	        });
	        $('#figgjo-showroom-productlist-filter-series').append(that.showroomFilterOptions['series']);
        }
        
        if ($('#figgjo-showroom-productlist-filter-subseries').length > 0) {
	        $.each(this.showroomMapSubseries, function(key, val) {
	        	that.showroomFilterOptions['subseries'] += '<option value="'+key+'"'+(key == 0 ? ' selected':'')+'>'+that.htmlEscape(val)+'</option>';
	        });
	        $('#figgjo-showroom-productlist-filter-subseries').append(that.showroomFilterOptions['subseries']);
        }
        
        if ($('#figgjo-showroom-productlist-filter-categories').length > 0) {
	        $.each(this.showroomMapCategories, function(key, val) {
	        	if (that.showroomKey != 'firmagaver' || val.level < 2) { // in firmagaver, only show first level of options 
	        		that.showroomFilterOptions['categories'] += '<option value="'+key+'"'+(key == 0 ? ' selected':'')+'>'+(new Array(val.level).join('&nbsp;&nbsp;'))+that.htmlEscape(val.label)+'</option>';
	        	}
	        });
	        $('#figgjo-showroom-productlist-filter-categories').append(that.showroomFilterOptions['categories']);
        }

        if ($('#figgjo-showroom-productlist-filter-firmagave').length > 0) {
	        $.each(this.showroomMapFirmagave, function(key, val) {
	        	that.showroomFilterOptions['firmagave'] += '<option value="'+key+'"'+(key == 0 ? ' selected':'')+'>'+that.htmlEscape(val)+'</option>';
	        });
	        $('#figgjo-showroom-productlist-filter-firmagave').append(that.showroomFilterOptions['firmagave']);
        }
        
        $.each(this.objectKeysToArray(showroomProductLengths), function(key,val){ that.showroomFilterOptions['length'] += '<option value="'+val+'">'+val+' cm</option>'; });
        $.each(this.objectKeysToArray(showroomProductWidths),  function(key,val){ that.showroomFilterOptions['width']  += '<option value="'+val+'">'+val+' cm</option>'; });
        $.each(this.objectKeysToArray(showroomProductHeights), function(key,val){ that.showroomFilterOptions['height'] += '<option value="'+val+'">'+val+' cm</option>'; });
        $.each(this.objectKeysToArray(showroomProductVolumes), function(key,val){ that.showroomFilterOptions['volume'] += '<option value="'+val+'">'+val+' cl</option>'; });
        
        
        $('#figgjo-showroom-productlist-filter-length').append(that.showroomFilterOptions['length']);
        $('#figgjo-showroom-productlist-filter-width').append(that.showroomFilterOptions['width']);
        $('#figgjo-showroom-productlist-filter-height').append(that.showroomFilterOptions['height']);
        $('#figgjo-showroom-productlist-filter-volume').append(that.showroomFilterOptions['volume']);
        
        if (this.showroomFilterHasSeparateAllSelect) {
        // Reset filter selection (browsers may "helpfully" remember last selection)
	        $.each(['solution', 'series', 'subseries', 'categories', 'firmagave', 'length', 'width', 'height', 'volume'], function(idx,val) {
	        	$('#figgjo-showroom-productlist-filter-'+val+'-all option').attr('selected', 'selected');
	        	$('#figgjo-showroom-productlist-filter-'+val+' option').removeAttr('selected');
	        });
        }
        $('#figgjo-showroom-productlist-search').val('');
        $('#figgjo-showroom-productlist-options').css('visibility','visible');
        
        $.address.externalChange($.proxy(this.onShowroomDeeplinkChange, this));
        this.showroomBasketDeeplinkAndCookieParse();
    },
    
    toggleProductFilter: function() {
        var filter = jQuery('#figgjo-showroom-productlist-filters');
        if (filter.is(':hidden')) {
            filter.show('fast');
            jQuery('#figgjo-showroom-productlist-filterbutton .closed').hide();
            jQuery('#figgjo-showroom-productlist-filterbutton .opened').show();
        } else {
            filter.hide('fast');
            jQuery('#figgjo-showroom-productlist-filterbutton .opened').hide();
            jQuery('#figgjo-showroom-productlist-filterbutton .closed').show();
        }
    },
    
    onShowroomProductItemClick: function(event) {
        var productDiv = $(event.currentTarget);
        var productID = productDiv.data('productid');
        this.showroomOpenDialogForProductId(productID, productDiv);
        event.stopPropagation(); // prevent clickoutside from closing dialog
    },
    
    onShowroomProductItemDoubleClick: function(event) {
        var productDiv = $(event.currentTarget);
        var productId = productDiv.data('productid');
        var product = this.showroomProductlist[productId];
        if (this.showroomBasketContent[productId]) {
        	this.showroomRemoveProductFromBasket(productId, true);
        }
        else {
        	this.showroomAddProductToBasket(productId, true);
        }
        event.stopPropagation(); // prevent clickoutside from closing dialog
    },
    
    showroomBasketCookieUpdate: function(updateHash) {
        var keys = [];
        for (var key in this.showroomBasketContent) {
            keys.push(key);
        }
        var csv = keys.join(',');
        $.cookie('figgjo_basket_'+this.showroomKey, csv);
        if (updateHash) {
            $.address.value(csv);
        } 
    },
    
    showroomBasketDeeplinkAndCookieParse: function() {
        var that = this;
        var productids = [];
        var deeplink = $.address.value().replace(/^\//, '');
        var cookie = $.cookie('figgjo_basket_'+this.showroomKey);
        if (deeplink != null && deeplink.length > 0) {
            if (/,replace$/.test(deeplink)) {
                deeplink = deeplink.substr(0, deeplink.length - 8);
                this.onShowroomBasketDeeplinkAndCookieParsed(deeplink);
                $.address.value(deeplink);
            } else if (cookie != null && cookie.length > 0 && deeplink != cookie) {
                var presentInCookie = {};
                var presentInDeeplink = {};
                var mergedList = [];
                var notPresentInCookie = 0;
                var notPresentInDeeplink = 0;
                var cookieList = cookie.split(',');
                for (var i = 0; i < cookieList.length; i++) {
                    presentInCookie[cookieList[i]] = 1;
                    mergedList.push(cookieList[i]);
                }
                var deeplinkList = deeplink.split(',');
                for (var i = 0; i < deeplinkList.length; i++) {
                    presentInDeeplink[deeplinkList[i]]
                    if (!(deeplinkList[i] in presentInCookie)) {
                        mergedList.push(deeplinkList[i]);
                        notPresentInCookie++;
                    }
                }
                for (var i = 0; i < cookieList.length; i++) {
                    if (!(cookieList[i] in presentInDeeplink)) {
                        notPresentInDeeplink++;
                    }
                }
                if (notPresentInCookie + notPresentInDeeplink > 0) {
                    var dialog = $('<div/>').append(this.showroomi18nReplaceText);
                    $("body").append(dialog);

                    var buttons = [];
                    buttons.push({
                        html: this.showroomi18nReplaceKeepOriginal,
                        click: function() {
                            that.onShowroomBasketDeeplinkAndCookieParsed(cookie);
                            $(this).dialog("close");
                        }
                    });
                    if (notPresentInCookie > 0) {
                        buttons.push({
                            html: this.showroomi18nReplaceMerge,
                            click: function() {
                                that.onShowroomBasketDeeplinkAndCookieParsed(mergedList.join(','));
                                $(this).dialog("close");
                            }
                        });
                    }
                    buttons.push({
                        html: this.showroomi18nReplaceKeepLink,
                        click: function() {
                            that.onShowroomBasketDeeplinkAndCookieParsed(deeplink);
                            $(this).dialog("close");
                        }
                    });
                    dialog.dialog({
                        resizable: false,
                        height: 'auto',
                        modal: true,
                        draggable: false,
                        title: this.showroomi18nReplaceTitle,
                        width: 550,
                        buttons: buttons,
                        closeOnEscape: false,
                        open: function(event, ui) { $(".ui-dialog-titlebar-close").hide(); }
                    });
                } else {
                    this.onShowroomBasketDeeplinkAndCookieParsed(cookie);
                }
            } else {
                this.onShowroomBasketDeeplinkAndCookieParsed(deeplink);
            }
        } else {
	        // If no deeplink specified, look in cookie 
	        if (cookie != null) {
	            this.onShowroomBasketDeeplinkAndCookieParsed(cookie);
	        } else {
	            this.onShowroomBasketDeeplinkAndCookieParsed('');
	        }
	        
        }
        
    },
    
    onShowroomBasketDeeplinkAndCookieParsed: function(csv) {
        productids = csv.split(',');
        
        for (var key in productids) {
            var productid = productids[key];
            this.showroomAddProductToBasket(productid, false);
        }
        // Set hash once when complete
        this.showroomBasketCookieUpdate(true);
    },
    
    onShowroomDeeplinkChange: function(event) {
        // user clicked back/forward, update basket content
    	var deeplink = $.address.value().replace(/^\//, '');
    	if (/,replace$/.test(deeplink)) {
    	    deeplink = deeplink.substr(0, deeplink.length - 8);
    	}
        var productidsValues = deeplink.split(',');
        var productids = {};
        $.each(productidsValues, function(idx, productid) {
            if (productid.length > 0) {
                productids[productid] = true;
            }
        });
        
        var productidsToRemove = [];
        var productidsToAdd = [];
        var that=this;
        $.each(productids, function(productid, trueval) {
            if (!that.showroomBasketContent[productid]) {
                productidsToAdd.push(productid);
            }
        });
        $.each(this.showroomBasketContent, function(productid, trueval) {
            if (!productids[productid]) {
                productidsToRemove.push(productid);
            }
        });
        
        $.each(productidsToRemove, function(idx, productid) {
            that.showroomRemoveProductFromBasket(productid, false);
        });
        $.each(productidsToAdd, function(idx, productid) {
            that.showroomAddProductToBasket(productid, false);
        });
        
    },
    
    showroomClearBasket: function() {
        this.showroomBasketContent = {};
        $("#figgjo-showroom-basket").empty();
        this.showroomBasketCookieUpdate(true);
        this.showroomBasketProductListUpdateLayoutAll();
    },
    
    showroomBasketProductListUpdateLayoutAll: function() {
        var that=this;
        $.each($('#figgjo-showroom-productlist .figgjo-product'), function(idx,obj) {
            $(obj).fadeTo('fast', ((that.showroomBasketContent[$(obj).data('productid')])? 0.5 : 1.0));
        });
    },
    
    showroomBasketProductListUpdateLayout: function(productId, nowInBasket) {
        var that=this;
        $.each($('#figgjo-showroom-productlist .figgjo-product'), function(idx,obj) {
            var obj = $(obj);
            if (obj.data('productid') == productId) {
                if (obj.is(':visible')) {
                    obj.fadeTo('fast', (nowInBasket? 0.5 : 1.0));
                }
                else {
                    // Don't show element if hidden by filter
                    obj.css('opacity', (nowInBasket? 0.5 : 1.0));
                }
            }
        });
    },
    
    showroomAddProductToBasket: function(productId, updateHash) {
        var product = this.showroomProductlist[productId];
        if (product == null) return;
        
        this.showroomCloseDialog();
                
        // See if the product is in the basket already
        if (this.showroomBasketContent[productId]) return;
        
        this.showroomBasketContent[productId] = true;
        this.showroomBasketCookieUpdate(updateHash);
        
        var newBasketItem = $('<div></div>').addClass('figgjo-showroom-basket-item');
        var newBasketItemInner = $('<div></div>').addClass('figgjo-showroom-basket-item-inner');
        newBasketItem.append(newBasketItemInner);
        var newBasketItemImg = $('<img />').attr('src', product.image).data('figgjo-image-high', product.imagehigh).data('figgjo-image-low', product.image);
        newBasketItemImg.css({width:1, height: 1});
        newBasketItemInner.append(newBasketItemImg); 
        newBasketItemInner.append($('<br />'));
        newBasketItemInner.append(document.createTextNode(product.name));
        
        newBasketItem.data('productid', productId);
        newBasketItem.data('unpositioned', true);
        newBasketItem.click($.proxy(this.onShowroomBasketItemClick, this));
        newBasketItem.dblclick($.proxy(this.onShowroomBasketItemDoubleClick, this));
        $("#figgjo-showroom-basket").append(newBasketItem);
        newBasketItem.hide();
        //newBasketItem.fadeIn();
        
        this.showroomBasketProductListUpdateLayout(productId, true);
        this.showroomBasketReflow(false);
        
    },
    
    showroomRemoveProductFromBasket: function(productId, updateHash) {
        this.showroomCloseDialog();
        delete(this.showroomBasketContent[productId]);
        this.showroomBasketCookieUpdate(updateHash);
        $.each($("#figgjo-showroom-basket").children(), function(idx, element) {
            element = $(element);
            if (element.data('productid') == productId) {
                element.data('productid', 0); // prevent re-use
                element.fadeOut(400, function() { $(this).remove(); });
            }
        });
        
        this.showroomBasketProductListUpdateLayout(productId, false);
        this.showroomBasketReflow(false);
    },
    
    showroomBasketReflow: function(skipAnimation) {
        var that=this;
        
        // Re-calculate sizes and positions for all basket items
        
        var productIds = [];
        for (var key in this.showroomBasketContent) {
            productIds.push(key);
        }
        var basketSize = productIds.length; 
        
        var layout;
        switch (basketSize) {
            case 0:
                return;
            case 1:
                layout = [ [0] ];
                break;
            case 2:
                layout = [ [0, 1] ];
                break;
            case 3:
                layout = [ [0, 1, 2] ];
                break;
            case 4:
                layout = [ [0, 1, 2, 3] ];
                break;
            case 5:
                layout = [ [0, 1, 2], [3, 4] ];
                break;
            case 6:
                layout = [ [0, 1, 2], [3, 4, 5] ];
                break;
            case 7:
                layout = [ [0, 1, 2], [3, 4, 5, 6] ];
                break;
            default:
                layout = [];
                for (var i=0; i<basketSize; i+=4) {
                    if (basketSize-i >= 4) {
                        layout.push([i, i+1, i+2, i+3]);
                    }
                    else {
                        var x = [];
                        for (j=i;j<basketSize;j++) {
                            x.push(j);
                        }
                        layout.push(x);
                    }
                }
                break;
        }
        
        var basketRows = layout.length;
        var basketCols = 1;
        
        var layoutByIdx = [];
        var numColsByRowIdx = [];
        $.each(layout, function(rowNum, obj) {
            var currentRowBasketCols = 1;
            $.each(obj, function(colNum, itemIdx) {
                currentRowBasketCols = Math.max(colNum+1, currentRowBasketCols);
                layoutByIdx[itemIdx] = [colNum, rowNum];
            });
            basketCols = Math.max(currentRowBasketCols, basketCols);
            numColsByRowIdx[rowNum] = currentRowBasketCols;
        });
        

        var topAbsolutePadding = 35;
        
        var availableHeight = this.resizeDivSibling.position().top - this.resizeDiv.position().top - topAbsolutePadding;
        var availableRowHeight        = Math.max(120, (availableHeight / basketRows));
        var availableRowHeightClamped = Math.min(500, availableRowHeight);
        
        var availableWidth = $('#figgjo-showroom-basket').width();
        var availableColWidth        = availableWidth / basketCols;
        var availableColWidthClamped = Math.min(500, availableColWidth);
        
        // 1. Find physically largest product and determine overall DPI to use
        var tallestProductId;
        var tallestProductWidth = 0;
        var targetDPI = 1;
        $.each(productIds, function(idx, productId) {
        	var width = Math.max(that.showroomProductlist[productId].width, that.showroomProductlist[productId].length);
        	if (width > tallestProductWidth) {
        		tallestProductId = productId;
        		tallestProductWidth = width;
        		targetDPI = that.showroomProductlist[productId].imagehighsizex / width;
        	}
        });
        
        // 2. Resize all images to match targetDPI (making them physically to-scale with each other) + also take note of downsizing (fitting) scale factor required to make even the largest image fit in a cell
        var imageScaleFactors = [];
        var fittingScaleFactor = 1.0;
        var heightOfLabel = 30;
        $.each(productIds, function(idx, productId) {
        	var currentDPI = that.showroomProductlist[productId].imagehighsizex / Math.max(that.showroomProductlist[productId].width, that.showroomProductlist[productId].length);
        	imageScaleFactors[productId] = targetDPI / currentDPI;
        	
        	fittingScaleFactor = Math.min(fittingScaleFactor, (availableRowHeightClamped-heightOfLabel)/(that.showroomProductlist[productId].imagehighsizey*imageScaleFactors[productId]));
        	fittingScaleFactor = Math.min(fittingScaleFactor, availableColWidthClamped/(that.showroomProductlist[productId].imagehighsizex*imageScaleFactors[productId]));
        });
        
        // 3. Apply scaling and positioning
        $.each(productIds, function(idx, productId) {
        	var targetPosition = layoutByIdx[idx];

            var imgNewWidth  = fittingScaleFactor * imageScaleFactors[productId] * that.showroomProductlist[productId].imagehighsizex;
            var imgNewHeight = fittingScaleFactor * imageScaleFactors[productId] * that.showroomProductlist[productId].imagehighsizey;
            
            var targetPositionX = (targetPosition[0]) * availableColWidth 
                                  + (availableWidth - availableColWidth*numColsByRowIdx[targetPosition[1]])/2; // center, if there are less than maxcols in this row
            var targetPositionY = (targetPosition[1]) * availableRowHeight + topAbsolutePadding;
            
            // find corresponding div. XXX: Should be stored in a hash
            var divToAnimate = null;
            $.each($('#figgjo-showroom-basket div'), function(idx,obj) { var x = $(obj); if (x.data('productid') == productId) { divToAnimate = x; return false; } } );
            if (divToAnimate != null) {
            
                divToAnimate.find('img').each(function(){
                    var jqthis = $(this); 
                    var imgSrcHigh = jqthis.data('figgjo-image-high');
                    var imgSrcLow  = jqthis.data('figgjo-image-low');
                    if (imgSrcHigh && imgSrcLow) {
                        if (imgNewHeight > 128) {
                            if (this.src != imgSrcHigh) this.src = imgSrcHigh;
                        }
                        else {
                            if (this.src != imgSrcLow) this.src = imgSrcLow;
                        }
                    }
                });
            
                if (skipAnimation || divToAnimate.data('unpositioned')) {
                    divToAnimate.data('unpositioned', false);
                    divToAnimate.css({width: availableColWidth, height: availableRowHeight, left: targetPositionX, top: targetPositionY});
                    if (!skipAnimation) {
                        divToAnimate.fadeIn(200);
                    }
                }
                else {
                    divToAnimate.animate({width: availableColWidth, height: availableRowHeight, left: targetPositionX, top: targetPositionY}, {queue: false, duration: 300, easing: 'easeOutQuint'});
                }
                
                if (skipAnimation) {
                    divToAnimate.find('img').css({width:imgNewWidth, height:imgNewHeight});
                }
                else {
                    divToAnimate.find('img').animate({width:imgNewWidth, height:imgNewHeight}, {queue: false, duration: 500, easing: 'easeOutQuart'});
                }
                
            }
            
        	
        	
        });
        
    },
    
    onShowroomBasketItemClick: function(event) {
        var basketItem = $(event.currentTarget);
        this.showroomOpenDialogForProductId(basketItem.data('productid'), basketItem);
        event.stopPropagation(); // prevent clickoutside from closing dialog
    },
    
    onShowroomBasketItemDoubleClick: function(event) {
        var basketItem = $(event.currentTarget);
        this.showroomRemoveProductFromBasket(basketItem.data('productid'), true);
        event.stopPropagation(); // prevent clickoutside from closing dialog
    },
    
    
    showroomSearchFilterReset: function(whatToReset) {
    	switch (whatToReset) {
    		case 'freetext':
    			$('#figgjo-showroom-productlist-search').val('');
    			this.showroomSearchFilterUpdate('freetext');
    			break;
    		case 'filters':
    	        if (this.showroomFilterHasSeparateAllSelect) {
	    	        $.each(['solution', 'series', 'subseries', 'categories', 'firmagave', 'length', 'width', 'height', 'volume'], function(idx,val) {
	    	        	$('#figgjo-showroom-productlist-filter-'+val+'-all option').attr('selected', 'selected');
	    	        	$('#figgjo-showroom-productlist-filter-'+val).attr('selectedIndex', '-1');
	    	        });
	            }
    	        else {
	    	        $.each(['solution', 'series', 'subseries', 'categories', 'firmagave', 'length', 'width', 'height', 'volume'], function(idx,val) {
	    	        	$('#figgjo-showroom-productlist-filter-'+val).attr('selectedIndex', '0');
	    	        });
    	        }
    			this.showroomSearchFilterUpdate('');
    			break;
    	}
    },
    
    showroomSearchFilterUpdate: function(columnName) {
    	
    	// Now perform a search, and collect a set of valid options (i.e. from matching products) per filter
    	
    	var that = this;
    	var numActiveFilters = 0;
    	
    	
    	var matchingSolutions  = {};
    	var matchingSeries     = {};
    	var matchingSubseries  = {};
    	var matchingCategories = {};
    	var matchingFirmagave  = {};
    	var matchingLength     = {};
    	var matchingWidth      = {};
    	var matchingHeight     = {};
    	var matchingVolume     = {};
    	
    	var matchingProductIds = {};
    	
    	var filterOnSolution   = $('#figgjo-showroom-productlist-filter-solution').val();
    	var filterOnSeries     = $('#figgjo-showroom-productlist-filter-series').val();
    	var filterOnSubseries  = $('#figgjo-showroom-productlist-filter-subseries').val();
    	var filterOnCategory   = $('#figgjo-showroom-productlist-filter-categories').val();
    	var filterOnFirmagave  = $('#figgjo-showroom-productlist-filter-firmagave').val();
    	var filterOnLength     = $('#figgjo-showroom-productlist-filter-length').val();
    	var filterOnWidth      = $('#figgjo-showroom-productlist-filter-width').val();
    	var filterOnHeight     = $('#figgjo-showroom-productlist-filter-height').val();
    	var filterOnVolume     = $('#figgjo-showroom-productlist-filter-volume').val();
    	
    	filterOnSolution  = (filterOnSolution == 0  ? null : filterOnSolution);
    	filterOnSeries    = (filterOnSeries == 0    ? null : filterOnSeries);
    	filterOnSubseries = (filterOnSubseries == 0 ? null : filterOnSubseries);
    	filterOnCategory  = (filterOnCategory == 0  ? null : filterOnCategory);
    	filterOnFirmagave = (filterOnFirmagave == 0 ? null : filterOnFirmagave);
    	filterOnLength    = (filterOnLength == 0    ? null : filterOnLength);
    	filterOnWidth     = (filterOnWidth == 0     ? null : filterOnWidth);
    	filterOnHeight    = (filterOnHeight == 0    ? null : filterOnHeight);
    	filterOnVolume    = (filterOnVolume == 0    ? null : filterOnVolume);
    	
    	
    	if (filterOnSolution != null)  numActiveFilters++;
    	if (filterOnSeries != null)    numActiveFilters++;
    	if (filterOnSubseries != null) numActiveFilters++;
    	if (filterOnCategory != null)  numActiveFilters++;
    	if (filterOnFirmagave != null) numActiveFilters++;
    	if (filterOnLength != null)    numActiveFilters++;
    	if (filterOnWidth != null)     numActiveFilters++;
    	if (filterOnHeight != null)    numActiveFilters++;
    	if (filterOnVolume != null)    numActiveFilters++;
    	
    	if (numActiveFilters > 0) {
    		$.each(that.showroomProductlist, function(productId, product) {
	        	// try to match filters per column
	        	var acceptFilterSolution    = true;
	        	var acceptFilterSeries      = true;
	        	var acceptFilterSubseries   = true;
	        	var acceptFilterCategory    = true;
	        	var acceptFilterFirmagave   = true;
	        	var acceptFilterLength      = true;
	        	var acceptFilterWidth       = true;
	        	var acceptFilterHeight      = true;
	        	var acceptFilterVolume      = true;
	        	
	        	if (filterOnSolution != null) {
	        		acceptFilterSolution = false;
	        		$.each(product.solution.split(','),   function(sidx, selement) { if (selement == filterOnSolution)   { acceptFilterSolution = true; return false; /* break sub-$.each() */ } });
	        	}
	        	if (filterOnSeries != null) {
	        		acceptFilterSeries = false;
	        		$.each(product.series.split(','),     function(sidx, selement) { if (selement == filterOnSeries)     { acceptFilterSeries = true; return false; /* break sub-$.each() */ } });
	        	}
	        	if (filterOnCategory != null) {
	        		acceptFilterCategory = false;
	        		$.each(product.categories.split(','), function(sidx, selement) { if (selement == filterOnCategory)   { acceptFilterCategory = true; return false; /* break sub-$.each() */ } });
	        	}
	        	if (filterOnFirmagave != null) {
	        		acceptFilterFirmagave = false;
	        		$.each(product.firmagave.split(','),  function(sidx, selement) { if (selement == filterOnFirmagave)  { acceptFilterFirmagave = true; return false; /* break sub-$.each() */ } });
	        	}
	        	acceptFilterSubseries = (filterOnSubseries == null || filterOnSubseries == product.subseries);
	        	acceptFilterLength    = (filterOnLength    == null || filterOnLength    == product.length);
	        	acceptFilterWidth     = (filterOnWidth     == null || filterOnWidth     == product.width);
	        	acceptFilterHeight    = (filterOnHeight    == null || filterOnHeight    == product.height);
	        	acceptFilterVolume    = (filterOnVolume    == null || filterOnVolume    == product.volume);
	        	
	        	// update matching attributes:
	        	// An attribute is added for a column if the product is a match on all other columns except the one in question
	        	// (I.e. the list of valid option in a column is determined by filtering the product list against only the other columns
	        	if (                        acceptFilterSeries && acceptFilterSubseries && acceptFilterCategory && acceptFilterFirmagave && acceptFilterLength && acceptFilterWidth && acceptFilterHeight && acceptFilterVolume)   { $.each(product.solution.split(','),     function(sidx, selement) { matchingSolutions[selement] = true; });  }
	        	if (acceptFilterSolution &&                       acceptFilterSubseries && acceptFilterCategory && acceptFilterFirmagave && acceptFilterLength && acceptFilterWidth && acceptFilterHeight && acceptFilterVolume)   { $.each(product.series.split(','),       function(sidx, selement) { matchingSeries[selement] = true; });     }
	        	if (acceptFilterSolution && acceptFilterSeries &&                          acceptFilterCategory && acceptFilterFirmagave && acceptFilterLength && acceptFilterWidth && acceptFilterHeight && acceptFilterVolume)   { matchingSubseries[product.subseries] = true; }
	        	if (acceptFilterSolution && acceptFilterSeries && acceptFilterSubseries &&                         acceptFilterFirmagave && acceptFilterLength && acceptFilterWidth && acceptFilterHeight && acceptFilterVolume)   { $.each(product.categories.split(','),   function(sidx, selement) { matchingCategories[selement] = true; }); }
	        	if (acceptFilterSolution && acceptFilterSeries && acceptFilterSubseries && acceptFilterCategory &&                          acceptFilterLength && acceptFilterWidth && acceptFilterHeight && acceptFilterVolume)   { if (product.hasOwnProperty('firmagave')) $.each(product.firmagave.split(','),    function(sidx, selement) { matchingFirmagave[selement] = true; }); }
	        	if (acceptFilterSolution && acceptFilterSeries && acceptFilterSubseries && acceptFilterCategory && acceptFilterFirmagave &&                       acceptFilterWidth && acceptFilterHeight && acceptFilterVolume)   { matchingLength[product.length] = true; }
	        	if (acceptFilterSolution && acceptFilterSeries && acceptFilterSubseries && acceptFilterCategory && acceptFilterFirmagave && acceptFilterLength &&                      acceptFilterHeight && acceptFilterVolume)   { matchingWidth[product.width] = true; }
	        	if (acceptFilterSolution && acceptFilterSeries && acceptFilterSubseries && acceptFilterCategory && acceptFilterFirmagave && acceptFilterLength && acceptFilterWidth &&                       acceptFilterVolume)   { matchingHeight[product.height] = true; }
	        	if (acceptFilterSolution && acceptFilterSeries && acceptFilterSubseries && acceptFilterCategory && acceptFilterFirmagave && acceptFilterLength && acceptFilterWidth && acceptFilterHeight                      )   { matchingVolume[product.volume] = true; }
	        	if (acceptFilterSolution && acceptFilterSeries && acceptFilterSubseries && acceptFilterCategory && acceptFilterFirmagave && acceptFilterLength && acceptFilterWidth && acceptFilterHeight && acceptFilterVolume)   { matchingProductIds[productId] = true }
    		});
    	}
    	
        // Update columns (unless updating from freetext, in which case there's no change to the columns)
    	var filtersAcceptEverything = (numActiveFilters == 0);
        if (columnName != 'freetext') {
	        var updateColumnFunction = function(jsname, matchingCollection) {
	        	var selectElement = $('#figgjo-showroom-productlist-filter-'+jsname);
	        	if (selectElement.length < 1) return;
	        	// Save selected value
	        	var oldSelectedValue = selectElement.val();
	        	// Prepare new list of options
	        	var newOptions = $(that.showroomFilterOptions[jsname]);
	        	newOptions = $.grep(newOptions, function(element) {
	        		var $element = $(element);
	        		var val = $element.val();
	        		// Also mark as selected
	        		if (val == oldSelectedValue) $element.attr('selected', 'selected');
	        		return filtersAcceptEverything || val == 0 || matchingCollection.hasOwnProperty(val);
	        	});
	        	
	        	// Insert new options
	        	selectElement.empty();
	        	selectElement.append(newOptions);
	        	selectElement.width(0);
	        	selectElement.width('100%');
	        };
	        
	        updateColumnFunction('solution',   matchingSolutions);
	        updateColumnFunction('series',     matchingSeries);
	        updateColumnFunction('subseries',  matchingSubseries);
	        updateColumnFunction('categories', matchingCategories);
	        updateColumnFunction('firmagave',  matchingFirmagave);
	        updateColumnFunction('length',     matchingLength);
	        updateColumnFunction('width',      matchingWidth);
	        updateColumnFunction('height',     matchingHeight);
	        updateColumnFunction('volume',     matchingVolume);
        }
        
    	
        // Furthermore, apply freetext search (should only affect list of visible products, not the filter columns)
        var freetextSearch = $('#figgjo-showroom-productlist-search').val().toLowerCase();
        if (freetextSearch.length > 0) {
        	var keysToSearch = matchingProductIds;
        	var keysToSearchHasProductValue = false;
        	matchingProductIds = {}; // reset list of matching products so it can be rebuilt from only matching elements
        	if (filtersAcceptEverything) {
        		// search in all products
        		keysToSearch = that.showroomProductlist;
        		keysToSearchHasProductValue = true;
        	}
        	$.each(keysToSearch, function(productId, product){
        		if (!keysToSearchHasProductValue) product = that.showroomProductlist[productId];
        		
                isMatch = false;
                if (!isMatch && product.name.toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && that.showroomProductMultiValueAsString(product.solution, that.showroomMapSolutions).toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && that.showroomProductMultiValueAsString(product.series, that.showroomMapSeries).toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && (product.subseries != null) && that.showroomMapSubseries[product.subseries].toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && ($.map(product.categories.split(','), function(categoriesElement, idx){return (categoriesElement.length > 0 && that.showroomMapCategories.hasOwnProperty(categoriesElement)) ? that.showroomMapCategories[categoriesElement].label : '';}).join(', ')).toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && that.showroomProductMultiValueAsString(product.form, that.showroomMapForms).toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && product.designer.toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && that.showroomProductMultiValueAsString(product.design, that.showroomMapDesigns).toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && that.showroomProductMultiValueAsString(product.meal, that.showroomMapMeals).toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
                if (!isMatch && product.launchyear.toLowerCase().indexOf(freetextSearch) != -1) {
                    isMatch = true;
                }
        		
        		if (isMatch) matchingProductIds[productId] = true;
        	});
        	
        	numActiveFilters++;
        }
        
        // Update list of visible products
    	
    	if (numActiveFilters == 0) {
    		$('#figgjo-showroom-productlist .figgjo-product').show();
    	}
    	else {
	        $.each($('#figgjo-showroom-productlist .figgjo-product'), function(idx, element) {
	            element = $(element);
	            var productId = element.data('productid');
	            if (productId.length > 0) {
	            	(matchingProductIds.hasOwnProperty(productId)) ? element.show() : element.hide();
	            }
	        });
    	}
        // Update filter count
        $('#figgjo-showroom-productlist-filters-count').html(numActiveFilters > 0 ? ''+numActiveFilters : '');
        (numActiveFilters > 0) ? $('#figgjo-showroom-productlist-filters-count-wrapper').show() : $('#figgjo-showroom-productlist-filters-count-wrapper').hide();
        
        this.onProductlistVisibilityUpdate();
        
    },
    
    showroomSearchFilterUpdateFromAll: function(columnName) {
    	// If the 'all' option value is selected here in this column, clear the other options
    	var allSelect = $('#figgjo-showroom-productlist-filter-'+columnName+'-all');
    	var optSelect = $('#figgjo-showroom-productlist-filter-'+columnName);
    	
    	if (allSelect.val() == 'ALL') {
    		optSelect.attr('selectedIndex', '-1');
    	}
    	
    	// Then apply search
    	this.showroomSearchFilterUpdate(columnName);
    },
    
    showroomSearchFilterUpdateFromAttr: function(columnName) {
    	// If any option value is selected here in this column, clear the 'all' option 
    	var allSelect = $('#figgjo-showroom-productlist-filter-'+columnName+'-all');
    	var optSelect = $('#figgjo-showroom-productlist-filter-'+columnName);
    	
    	if (optSelect.val() != null) {
    		allSelect.attr('selectedIndex', '-1');
    	}
    	
    	// Then apply search
    	this.showroomSearchFilterUpdate(columnName);
    },
    
    showroomSendToFriend: function() {
        var keys = [];
        for (var key in this.showroomBasketContent) {
            keys.push(key);
        }
        var csv = keys.join(',');
        
    	var sendToFriendDialog = $('<div style="display:none"><div class="loader" style="margin: 75px auto; position: static; display: block; padding: 0 auto">&nbsp;</div></div>').appendTo('body');
    	setTimeout(function(){ sendToFriendDialog.bind('clickoutside', function(e) { sendToFriendDialog.remove(); }); }, 1);
    	sendToFriendDialog.dialog({modal: true, width: 500, height:'auto', title:this.showroomi18nSendToAFriendTitle ,show:'fade', draggable: false, resizable: false, close:function(){$(this).remove();}});
    	sendToFriendDialog.load(figgjo_globals.baseURL+'figgjo/showroom/sendtofriend?productIDs='+csv+'&showroomKey='+this.showroomKey, this.repositionDialogs);
    },
    
    showroomSendToFriendPostEmail: function(theForm) {
    	var $theForm = $(theForm);
    	
    	$theForm.find('.form-submit-normal').hide();
    	$theForm.find('.form-submit-sending').show();
    	
    	var postdata = $theForm.serialize();
    	$.ajax({
    		type: 'POST',
    		url: figgjo_globals.baseURL+'figgjo/showroom/sendtofriendpost',
    		data: postdata,
    		success: function(msg) {
    			$theForm.find('.form-submit-sending').hide();
    			$theForm.find('.form-submit-sent').show();
    		},
    		error: function(xhr) {
    			$theForm.find('.form-submit-sending').hide();
    			$theForm.find('.form-submit-error').show();
    		}
    	});
    	
    	return false;
    },
    
    showroomSendToFriendResetForm: function(element) {
    	var $theForm = $(element).closest('form');
    	$theForm.find('input[type="text"]').val('');
    	$theForm.find('.form-submit-normal').show();
    	$theForm.find('.form-submit-sending').hide();
    	$theForm.find('.form-submit-error').hide();
    	$theForm.find('.form-submit-sent').hide();
    	
    },

    showroomGotoCheckout: function() {
        var keys = [];
        for (var key in this.showroomBasketContent) {
            keys.push(key);
        }
        var csv = keys.join(',');
        location.href=figgjo_globals.baseURL+'figgjo/showroom/gotocheckout?productIDs='+csv;
    },
    
    showroomSendInquiry: function() {
        var keys = [];
        for (var key in this.showroomBasketContent) {
            keys.push(key);
        }
        var csv = keys.join(',');
        
        var inquiryDialog = $('<div style="display:none"><div class="loader" style="margin: 100px auto; position: static; display: block; padding: 0 auto">&nbsp;</div></div>');
        inquiryDialog.dialog({modal: true, width: 500, minHeight:350, height:'auto', title:this.showroomSendInquiryTitle,show:'fade', draggable: false, resizable: false, close:function(){$(this).dialog('destroy').remove();}});
        setTimeout(function(){ inquiryDialog.bind('clickoutside', function(e) { inquiryDialog.remove(); }); }, 1);
        var that=this;
        inquiryDialog.load(figgjo_globals.baseURL+'figgjo/showroom/inquiryform?productIDs='+csv+'&showroomKey='+this.showroomKey, function() {
            that.showroomInquirySetupRequiredFields(inquiryDialog);
            that.repositionDialogs();
        });
    },
    
    showroomInquiryRequiredFieldsMap: {fromName:1, fromCompany:1, fromEmail:1, fromAreaCode:1, fromArea:1, fromCountry:1},
    
    showroomInquirySetupRequiredFields: function(inquiryDialog) {
        var that = this;
        inquiryDialog.find('input[type="text"]').each(function(index, element) {
            var input = $(element);
            var name = input.attr('name');
            if (name in that.showroomInquiryRequiredFieldsMap) {
                var tr = input.parents('tr:first');
                tr.append('<td>&nbsp;*</td>');
            }
        });
        inquiryDialog.find('[type="submit"]').each(function(index, element) {
            $(element).click(function() {
                var failures = 0;
                inquiryDialog.find('input[type="text"]').each(function(index, element) {
                    var input = $(element);
                    var name= input.attr('name');
                    if (name in that.showroomInquiryRequiredFieldsMap) {
                        var asteriskTd = input.parents('tr:first').children().last();
                        if ($(element).val() == '') {
                            failures++;
                            asteriskTd.css('color', '#e31111');
                        } else {
                            asteriskTd.css('color', 'inherit');
                        }
                    }
                });
                return (failures == 0);
            });
        });
    },
    
    showroomPostInquiry: function(theForm) {
    	var theForm = $(theForm);
    	var theDialogContent = theForm.parents('.ui-dialog-content');
    	
    	theForm.find('.form-submit-normal').hide();
    	theForm.find('.form-submit-sending').show();
    	
    	var postdata = theForm.serialize();
    	$.ajax({
    		type: 'POST',
    		url: figgjo_globals.baseURL+'figgjo/showroom/inquirypost',
    		data: postdata,
    		success: function(msg) {
    		    theForm.find('.form-submit-button').hide();
    	    	theDialogContent.find('.form-state-success').show();
    		},
    		error: function(xhr) {
                theForm.find('.form-submit-button').hide();
                theDialogContent.find('.form-state-error').show();
    		}
    	});
    	
    	return false;
    },
    
    onWindowResize: function() {
        $(".figgjo-footer-popup").each(function(index,element){
            var parent = $("#"+element.id+"-owner");
            element = $(element);
            var wasHidden = element.is(":hidden");
            element.show();
	        var baseOffset = parent.offset();
	        element.outerWidth(parent.outerWidth());
            baseOffset.top -= (element.height() + 21);
            baseOffset.left += (parent.outerWidth() - element.outerWidth())/2; 
            element.offset(baseOffset);
            if (wasHidden) element.hide();
        });
        
        if (this.resizeDiv != null) {
            var newHeight = this.resizeDivSibling.position().top - this.resizeDiv.position().top;
            this.resizeDiv.css('height', newHeight + 'px');
            if (this.resizeDivTimeoutFunction != null) {
            	if (this.resizeTimeout) {
            		clearTimeout(this.resizeTimeout);
            	}
            	this.resizeTimeout = setTimeout(this.resizeDivTimeoutFunction, 200);
            }
        }
        
        this.onProductlistVisibilityUpdate();
        
    },
    
    toggleFooterPopup: function(popupName, relativeTo) {
        var hideOnly = true;
        var popup = $("#figgjo-footer-popup-"+popupName);
        if (popup.is(":hidden")) {
            hideOnly = false;
        }
        $(".figgjo-footer-popup").fadeOut();
        if (hideOnly) return;
        
        popup.fadeIn('slow');
    },
    
    galleryInit: function(galleryListName) {
        this.galleryListName = galleryListName;
        this.resizeDiv = $('#figgjo-gallery-container');
        this.resizeDivSibling = $('#figgjo-gallery-pager');
        this.onWindowResize();
        this.galleryCalculateImagesPerPage();
        this.galleryCalculateGalleriesPerPage();
        $(window).resize($.proxy(this.onGalleryWindowResize, this));
        $.address.change($.proxy(this.onGalleryDeeplinkChange, this));
    	this.galleryLoadGalleryList();
		this.setupTooltips('#figgjo-gallery-lightbox img.lightbox-image');
		this.galleryDefaultHeadingHtml = this.getHeadingHtmlContent();
		var that = this;
		$('#figgjo-gallery-lightbox-wrapper').click(function() {
	        $.address.value(that.galleryCurrentTag + '/' + that.galleryCurrentPage);
		});
    },
    
    galleryCalculateImagesPerPage: function() {
    	var changed = false;
    	var container = $('#figgjo-gallery-container');
    	var containerWidth = container.width();
    	var containerHeight = container.height() - this.gallerySpacingOnTop;
    	var blockWidth = 221;
    	var blockHeight = 170;
    	var minSpacing = 10;
    	
    	var horizontalSlots = Math.max(2, Math.floor((containerWidth + minSpacing) / (blockWidth + minSpacing)));
    	var verticalSlots = Math.max(1, Math.floor((containerHeight + minSpacing) / (blockHeight + minSpacing)));
    	this.galleryImagesPerPage = horizontalSlots * verticalSlots;
    	
    	if (horizontalSlots != this.galleryHorizontalSlots || verticalSlots != this.galleryVerticalSlots) {
    		changed = true;
    	}
    	this.galleryHorizontalSlots = horizontalSlots;
    	this.galleryVerticalSlots = verticalSlots;
    	
    	var horizontalSpacing = (containerWidth - horizontalSlots * blockWidth) / (horizontalSlots - 1);
    	var verticalSpacing = verticalSlots > 1 ? (containerHeight - verticalSlots * blockHeight) / (verticalSlots - 1) : 0;
    	this.galleryHorizontalIncrement = Math.max(blockWidth + minSpacing, (containerWidth + horizontalSpacing) / horizontalSlots);
		this.galleryVerticalIncrement = blockHeight + minSpacing; //Math.max(blockHeight + minSpacing, (containerHeight + verticalSpacing) / verticalSlots);
		return changed;
    },
    
	galleryCalculateGalleriesPerPage: function() {
    	var changed = false;
    	var container = $('#figgjo-gallery-container');
    	var containerWidth = container.width();
    	var containerHeight = container.height() - this.gallerySpacingOnTop;
    	var blockWidth = 221;
    	var blockHeight = 170;
    	var minSpacing = 10;
    	
    	var horizontalSlots = Math.max(2, Math.floor((containerWidth + minSpacing) / (blockWidth + minSpacing)));
    	var verticalSlots = Math.max(1, Math.floor((containerHeight + minSpacing) / (blockHeight + minSpacing)));
    	this.galleryGalleriesPerPage = horizontalSlots * verticalSlots;
    	
    	if (horizontalSlots != this.galleryListHorizontalSlots || verticalSlots != this.galleryListVerticalSlots) {
    		changed = true;
    	}
    	this.galleryListHorizontalSlots = horizontalSlots;
    	this.galleryListVerticalSlots = verticalSlots;
    	
    	var horizontalSpacing = (containerWidth - horizontalSlots * blockWidth) / (horizontalSlots - 1);
    	var verticalSpacing = verticalSlots > 1 ? (containerHeight - verticalSlots * blockHeight) / (verticalSlots - 1) : 0;
    	this.galleryListHorizontalIncrement = Math.max(blockWidth + minSpacing, (containerWidth + horizontalSpacing) / horizontalSlots);
		this.galleryListVerticalIncrement = blockHeight + minSpacing; //Math.max(blockHeight + minSpacing, (containerHeight + verticalSpacing) / verticalSlots);
		return changed;
    },
    
    onGalleryWindowResize: function(e) {
    	var galleryChanged = this.galleryCalculateImagesPerPage();
    	var galleryListChanged = this.galleryCalculateGalleriesPerPage();
    	if (this.galleryDisplayed) {
	    	if (galleryChanged) {
	    		this.galleryRenderGallery();
	    	} else {
	    		this.galleryLayoutGallery();
	    	}
    	} else if (this.galleryListDisplayed) {
    		if (galleryListChanged) {
    			this.galleryRenderGalleryList();
    		} else {
    			this.galleryLayoutGalleryList();
    		}
    	}
    },
    
    galleryDisplayLoader: function() {
    	var container = $('#figgjo-gallery-container');
    	var loader = $('<div/>').addClass('loader').append('Loading...');
    	container.empty();
    	container.append(loader);
    	var windowWidth = $(window).width();
    	var windowHeight = $(window).height();
    	var loaderWidth = loader.width();
    	var loaderHeight = loader.height();
    	var containerOffset = container.offset();
    	loader.css('top', (windowHeight - loaderHeight) / 2 - containerOffset.top + 'px').css('left', (windowWidth - loaderWidth) / 2 -containerOffset.left + 'px');
    	this.galleryListDisplayed = false;
    	this.galleryDisplayed = false;
    },
    
    onGalleryDeeplinkChange: function(e) {
    	this.tooltipProducts = null;
    	var deeplink = $.address.value();
    	var elements = deeplink.split('/');
    	elements.shift(); // remove first element (the one before the first '/')
    	if (elements.length > 0 && elements[elements.length - 1] == '') {
    		elements.pop(); // remove last element if it is ''
    	}
    	this.galleryCurrentDeeplinkElements = elements;
    	if (elements.length == 0 || elements.length == 1 && parseInt(elements[0]) == elements[0]) {
    		this.galleryCurrentTag = null;
    		this.galleryCurrentData = null;
    		this.galleryCurrentPage = null;
    		this.galleryListCurrentPage = elements.length == 1 ? parseInt(elements[0]) : 1;
    		this.setHeadingHtmlContent(this.galleryDefaultHeadingHtml);
    		if (this.galleryList != null) {
    			this.removeLoader();
    			this.galleryRenderGalleryList();
    		} else {
    			$('#figgjo-gallery-container').empty();
    			this.displayLoader();
    		}
    		// this.galleryList is always loaded on page load, so if data not present yet, the loader will display the gallery listing.
    	} else {
    		var gallery = elements[0];
        	var page = elements.length > 1 ? page = parseInt(elements[1]) : 1;
        	if (gallery != this.galleryCurrentTag) {
        		this.galleryCurrentTag = gallery;
        		this.galleryCurrentPage = page;
        		this.galleryCurrentData = null;
        		this.galleryCurrentRequest++;
    			$('#figgjo-gallery-container').empty();
        		this.displayLoader();
        		this.galleryLoadGallery(gallery, page, this.galleryCurrentRequest);
        	} else if (page != this.galleryCurrentPage) {
        		this.galleryCurrentPage = page;
        		if (this.galleryCurrentData != null) { // gallery will be rendered by loader if data not present yet.
        			this.removeLoader();
        			this.galleryRenderGallery();
        		}
        	}
        }

//    	if (elements.length > 2) {
//    		var imageId = elements[2];
//    		this.galleryCurrentLightboxImageId = imageId;
//    		if (this.galleryCurrentData != null) {
//    			this.galleryRenderLightbox();
//    			$('#figgjo-gallery-lightbox-wrapper').addClass('enabled');
//    			$('#figgjo-gallery-lightbox-container').addClass('enabled');
//    			this.galleryLightboxRepos();
//    			$(window).resize(this.galleryLightboxRepos);
//    		}
//    		// on close:  $.address.value(this.galleryCurrentTag + '/' + this.galleryCurrentPage);
//    	} else {
    		this.galleryCurrentLightboxImageId = null;
    		$('#figgjo-gallery-lightbox-wrapper').removeClass('enabled');
    		$('#figgjo-gallery-lightbox-container').removeClass('enabled');
    		$(window).unbind('resize', this.galleryLightboxRepos);
//    	}
    },
    
    galleryLightboxRepos: function() {
    	var lightbox = $('#figgjo-gallery-lightbox-container');
    	var windowWidth = $(window).width();
    	var windowHeight = $(window).height();
    	var width = lightbox.outerWidth();
    	var height = lightbox.outerHeight();
    	lightbox.css({left: Math.max(0, (windowWidth - width) / 2) + 'px', top: Math.max(0, (windowHeight - height) / 2) + 'px'});
    },
    
    galleryRenderLightbox: function() {
        var container = $('#figgjo-gallery-lightbox-container');
    	var lightbox = $('#figgjo-gallery-lightbox');
    	var data = null;
    	for (var i = 0; i < this.galleryCurrentData.length; i++) {
    		if (this.galleryCurrentData[i].imageId == this.galleryCurrentLightboxImageId) {
    			data = this.galleryCurrentData[i];
    		}
    	}
    	lightbox.empty();
    	var closeurl = this.galleryCurrentTag + '/' + this.galleryCurrentPage;
    	var closebtn = $('<div/>').addClass('gallery-close-btn').click(function(){
            $('#figgjo-gallery-lightbox-wrapper').removeClass('enabled');
            $('#figgjo-gallery-lightbox-container').removeClass('enabled');
    	});
    	lightbox.append(closebtn);
    	if (data != null) {
			this.tooltipProducts = (data.imageProducts != null && data.imageProducts.hasOwnProperty('tags')) ? data.imageProducts.tags : null;
			var imageWrapper = $('<div>').css('width', data.imageWidth).css('height', data.imageHeight).css('margin', '0px auto');
			var image = $('<img/>').attr('src', data.imageUrl).addClass('lightbox-image');
			imageWrapper.append(image);
    		lightbox.append(imageWrapper);
    		
            //var imgdom = image.get(0);
            //if (imgdom.complete || imgdom.readyState === 4) {
            //    image.data('originalWidth', image.width());
            //    image.data('originalHeight', image.height());
            //} else {
            //    var that = this;
            //    image.load(function() {
            //        image.data('originalWidth', image.width());
            //        image.data('originalHeight', image.height());
            //        that.galleryLightboxRepos();
            //    });
            //}

    		
    		if (data.imageCaption != null && data.imageCaption != '') {
    		    lightbox.append($('<h1/>').append(data.imageCaption));
    		}
    		if (data.imageContent != null && data.imageContent != '') {
    		    lightbox.append($('<div class="separator"/>'));
    		    lightbox.append(data.imageContent);
    		}
    		var productsText = [];
    		var productCodeList = [];
    		if (data.imageProducts != null && data.imageProducts.tags instanceof Array) {
    			$.each(data.imageProducts.tags, function(index, obj) {
    				productsText.push(obj.label);
    				productCodeList.push(obj.label);
    			});
    	        image.click($.proxy(this.onGalleryImageMouseClick, this));
    		}
    		if (productCodeList.length > 0) {
    			var showroomUrl = figgjo_globals.baseURL + '/figgjo/showroom/professional#/' + productCodeList.join(',');
    			var a = $('<a/>').attr('href', showroomUrl).addClass('products').append(productsText.join(' , '));
    			lightbox.append(a);
    		}
    	} else {
    		lightbox.append($('<p>The image does not exist</p>').addClass('error'));
    		// some sort of error message...
    	}
    },
    
    onGalleryImageMouseClick: function(e) {
    	this.tooltipUpdateClosestProduct(e.pageX, e.pageY);
    },
    
    onGalleryImageMouseMove: function(e) {
    	this.tooltipUpdateClosestProduct(e.pageX, e.pageY);
    },

    galleryListName: 'inspiration',
    galleryDefaultHeadingHtml: '',
    galleryTagToNameMap: [],
    galleryList: null,
    galleryCurrentTag: null,
    galleryCurrentData: null,
    galleryCurrentPage: null,
    galleryListCurrentPage: null,
    galleryCurrentRequest: 1,
    galleryCurrentDeeplinkElements: null,
    galleryCurrentLightboxImageId: null,
	
    galleryListDisplayed: false,
	galleryDisplayed: false,
	
	gallerySpacingOnTop: 0,
	
	galleryImagesPerPage: null,
	galleryHorizontalSlots: null,
	galleryVerticalSlots: null,
	galleryHorizontalIncrement: null,
	galleryVerticalIncrement: null,

	galleryGalleriesPerPage: null,
	galleryListHorizontalSlots: null,
	galleryListVerticalSlots: null,
	galleryListHorizontalIncrement: null,
	galleryListVerticalIncrement: null,
    
    galleryLoadGallery: function(gallery, page, requestNumber) {
    	$.getJSON(figgjo_globals.baseURL + 'figgjo/ajax/gallery', {gallery: gallery}, $.proxy(function(data) {
    		if (requestNumber == this.galleryCurrentRequest) {
    			this.galleryCurrentData = data;
    			this.galleryRenderGallery();
    			if (this.galleryCurrentLightboxImageId != null) {
	    			this.galleryRenderLightbox();
	    			$('#figgjo-gallery-lightbox-wrapper').addClass('enabled');
	    			$('#figgjo-gallery-lightbox-container').addClass('enabled');
	    			this.galleryLightboxRepos();
	    			$(window).resize(this.galleryLightboxRepos);
    			}
    		}
    	}, this));
    },
    
    galleryLoadGalleryList: function() {
    	$.getJSON(figgjo_globals.baseURL + 'figgjo/ajax/galleryList?galleryListName=' + this.galleryListName, $.proxy(this.onLoadGalleryListComplete, this));
    },
    
    onGalleryNavClick: function() {
    	$.address.value($(this).data('url'));
    },
    
    galleryShowLightbox: function(imageId) {
        this.galleryCurrentLightboxImageId = imageId;
        this.galleryRenderLightbox();
        $('#figgjo-gallery-lightbox-wrapper').addClass('enabled');
        $('#figgjo-gallery-lightbox-container').addClass('enabled');
        this.galleryLightboxRepos();
        $(window).resize(this.galleryLightboxRepos);
    },
    
    onLoadGalleryListComplete: function(data) {
    	this.galleryList = data;
    	for (var i = 0; i < data.length; i++) {
    	    this.galleryTagToNameMap[data[i].galleryTag] = data[i].galleryName;
    	}
    	if (this.galleryCurrentDeeplinkElements == null || this.galleryCurrentDeeplinkElements.length == 0 || (this.galleryCurrentDeeplinkElements.length == 1 && parseInt(this.galleryCurrentDeeplinkElements[0]) == this.galleryCurrentDeeplinkElements[0])) {
    		this.galleryRenderGalleryList();
    	}
    },
    
    galleryRenderGalleryList: function() {
    	var container = $('#figgjo-gallery-container');
    	this.removeLoader();
    	container.empty();
    	
    	var numPages = Math.floor((this.galleryList.length + this.galleryGalleriesPerPage - 1) / this.galleryGalleriesPerPage);
    	var currentPage = Math.max(1, Math.min(numPages, this.galleryListCurrentPage));
    	this.galleryRenderPager(numPages, currentPage, this.galleryListGotoPage);
    	
    	var startIndex = (currentPage - 1) * this.galleryGalleriesPerPage;
    	for (i = startIndex, pos = 0; pos < this.galleryGalleriesPerPage && i < this.galleryList.length; i++, pos++) {
    		var entry = this.galleryList[i];
    		var box = $('<div />').addClass('figgjo-gallery-box');
    		box.append($('<img/>').attr('src', entry.galleryImage));
    		box.append($('<div/>').addClass('caption').append(entry.galleryName));
    		box.data('url', entry.galleryTag);
    		box.click(this.onGalleryNavClick); // not proxied on purpose!
    		container.append(box);
    	}
    	this.galleryListDisplayed = true;
    	this.galleryLayoutGalleryList();
    },
    
    galleryLayoutGalleryList: function() {
    	$('#figgjo-gallery-container > div').each($.proxy(function(index, element) {
    		var posX = (index % this.galleryListHorizontalSlots) * this.galleryListHorizontalIncrement;
    		var posY = Math.floor(index / this.galleryListHorizontalSlots) * this.galleryListVerticalIncrement + this.gallerySpacingOnTop;
    		$(element).css('top', posY + 'px').css('left', posX + 'px');
    	}, this));
    },
    
    galleryListGotoPage: function(page) {
    	$.address.value("" + page);
    },
    
    galleryGotoPage: function(page) {
    	$.address.value(this.galleryCurrentTag + '/' + page);
    },
    
    galleryRenderGallery: function() {
        var that = this;
    	var container = $('#figgjo-gallery-container');
    	container.empty();
    	this.removeLoader();
    	
    	var numPages = Math.floor((this.galleryCurrentData.length + this.galleryImagesPerPage - 1) / this.galleryImagesPerPage);
    	this.galleryCurrentPage = Math.max(1, Math.min(numPages, this.galleryCurrentPage));
    	this.galleryRenderPager(numPages, this.galleryCurrentPage, this.galleryGotoPage);

    	var startIndex = (this.galleryCurrentPage - 1) * this.galleryImagesPerPage;
    	for (i = startIndex, pos = 0; pos < this.galleryImagesPerPage && i < this.galleryCurrentData.length; i++, pos++) {
    		var entry = this.galleryCurrentData[i];
    		var box = $('<div />').addClass('figgjo-gallery-box');
    		box.append($('<img/>').attr('src', entry.imageThumbUrl));
    		box.append($('<div/>').addClass('caption').append(entry.imageCaption));
    		//box.data('url', this.galleryCurrentTag + '/' + this.galleryCurrentPage + '/' + entry.imageId);
    		box.data('imageId', entry.imageId);
    		box.click(function() {
    		    var imageId = $(this).data('imageId');
    		    that.galleryShowLightbox(imageId);
    		});
    		container.append(box);
    	}
    	this.galleryDisplayed = true;
    	this.galleryLayoutGallery();
    	this.setHeadingHtmlContent(this.galleryTagToNameMap[this.galleryCurrentTag]);
    },
    
    galleryLayoutGallery: function() {
    	$('#figgjo-gallery-container > div').each($.proxy(function(index, element) {
    		var posX = (index % this.galleryHorizontalSlots) * this.galleryHorizontalIncrement;
    		var posY = Math.floor(index / this.galleryHorizontalSlots) * this.galleryVerticalIncrement + this.gallerySpacingOnTop;
    		$(element).css('top', posY + 'px').css('left', posX + 'px');
    	}, this));
    },
    
    // selected is 1-based
    galleryRenderPager: function(count, selected, callback) {
        var outer = $('#figgjo-gallery-pager');
    	var container = $('#figgjo-gallery-pager-list');
    	container.empty();
    	var that = this;
    	if (count > 1) {
    	    outer.removeClass('empty');
        	if (selected > 1) {
        		var prevbtn = $('<div/>').addClass('gallery-prev-btn').click(function() {
        			callback.call(that, selected - 1);
        		});
        		container.append(prevbtn);
        	}
        	if (selected < count) {
        		var nextbtn = $('<div/>').addClass('gallery-next-btn').click(function() {
        			callback.call(that, selected + 1);
    			});
        		container.append(nextbtn);
        	}
        	for (i = 1; i <= count; i++) {
        		if (i == 1 || i == count || Math.abs(i - selected) < 3) {
    	    		var element = $('<span/>').addClass('figgjo-pager-element').append(i).data('page', i);
    	    		if (i == selected) {
    	    			element.addClass('selected');
    	    		} else {
    	    			element.click(function() {
    	    				var page = $(this).data('page');
    						callback.call(that, page);
    	    			});
    	    		}
    	    		container.append(element);
        		} else if (Math.abs(i - selected) == 3) {
        			container.append($('<span/>').addClass('figgjo-pager-element-ellipsis').append('...'));
        		}
        	}
    	} else {
            outer.addClass('empty');
    	}
    },
    
    galleryLayoutContainer: null,
    
    galleryDoLayout: function() {
    	var container = this.galleryLayoutContainer;
    	var boxes = container.data('boxes');
    	var boxWidth = container.data('boxWidth');
    	var boxHeight = container.data('boxHeight');
    	var minSpacing = container.data('minSpacing');

    	var containerWidth = container.innerWidth() - 20;
    	var horizontalSlots = Math.max(2, Math.floor((containerWidth + minSpacing) / (boxWidth + minSpacing)));
    	var horizontalSpacing = (containerWidth - horizontalSlots * boxWidth) / (horizontalSlots - 1);

    	var verticalSpacing = minSpacing;
    	var horizontalIncrement = Math.max(boxWidth + minSpacing, (containerWidth + horizontalSpacing) / horizontalSlots);
		var verticalIncrement = boxHeight + verticalSpacing;

		for (var i = 0; i < boxes.length; i++) {
			var ix = i % horizontalSlots;
			var iy = parseInt(i / horizontalSlots);
			var box = boxes[i];
			box.css({left: ix * horizontalIncrement, top: iy * verticalIncrement});
		}
    },
    
    initGalleryLayout: function(container, minSpacing, renderFunction, items) {
        var childCount = 0;
    	var boxWidth = null;
    	var boxHeight = null;
    	var boxes = new Array();
    	for (var i = 0; i < items.length; i++) {
    		var item = items[i];
    		var box = renderFunction.call(this, item);
    		boxes.push(box);
    		container.append(box);
    		childCount++;
    		if (boxWidth == null) {
    			boxWidth = box.width();
    			boxHeight = box.height();
    		}
    	}
    	container.data('boxes', boxes);
    	container.data('boxWidth', boxWidth);
    	container.data('boxHeight', boxHeight);
    	container.data('minSpacing', minSpacing);
    	this.galleryLayoutContainer = container;
    	this.galleryDoLayout();
    	$(window).resize($.proxy(this.galleryDoLayout, this));
    },
    
    renderArticleSubpage: function(item) {
    	// <div class="figgjo-gallery-box" onclick="location.href='url'">
    	//   <img src="imgurl"/>
    	//   <div class="caption">caption</div>
    	// </div>
    	box = $('<div/>').addClass('figgjo-gallery-box').click(function(){
    		location.href = item.url;
    	});
    	box.append($('<img/>').attr('src', item.image));
    	box.append($('<div/>').addClass('caption').append(item.caption));
    	return box;
    },
    
//    $data[] = Array(
//          'url' => $urlBase . $category->getId() . '/' . $post->getId(),
//          'title' => $post->getPostTitle(),
//          'excerpt' => $post->getPostExcerpt(),
//          'image' => $imgurl
//        );
    renderNewsCategory: function(item) {
        box = $('<div class="figgjo-gallery-box"/>').click(function(){
            location.href = item.url;
        });
        if (item.image != null) {
            box.append($('<img/>').attr('src', item.image));
        } else {
            box.append($('<img/>').attr('src', '/figgjo-data/news_noimage.png'));
        }
        box.append($('<div class="caption"/>').append(item.title));
    	return box;
    }
};
})(jQuery);



jQuery(document).ready(jQuery.proxy(figgjo.onDocumentReady, figgjo));

