var wishlist,
adsenseUrl,
cgBar = [],
cgSlider;
/*
 * JavaScript Debug - v0.4 - 6/22/2010
 * http://benalman.com/projects/javascript-debug-console-log/
 * 
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 * 
 * With lots of help from Paul Irish!
 * http://paulirish.com/
 */
window.debug=(function(){var i=this,b=Array.prototype.slice,d=i.console,h={},f,g,m=9,c=["error","warn","info","debug","log"],l="assert clear count dir dirxml exception group groupCollapsed groupEnd profile profileEnd table time timeEnd trace".split(" "),j=l.length,a=[];while(--j>=0){(function(n){h[n]=function(){m!==0&&d&&d[n]&&d[n].apply(d,arguments)}})(l[j])}j=c.length;while(--j>=0){(function(n,o){h[o]=function(){var q=b.call(arguments),p=[o].concat(q);a.push(p);e(p);if(!d||!k(n)){return}d.firebug?d[o].apply(i,q):d[o]?d[o](q):d.log(q)}})(j,c[j])}function e(n){if(f&&(g||!d||!d.log)){f.apply(i,n)}}h.setLevel=function(n){m=typeof n==="number"?n:9};function k(n){return m>0?m>n:c.length+m<=n}h.setCallback=function(){var o=b.call(arguments),n=a.length,p=n;f=o.shift()||null;g=typeof o[0]==="boolean"?o.shift():false;p-=typeof o[0]==="number"?o.shift():n;while(p<n){e(a[p++])}};return h})();

/*
 * On document.ready
 */
$(function() {
	isFooterPresent();
	if (cgBar) {
		cgBar = new MyCGBar();
	}
	initListeners();
	if ( $('#shoplist').length > 0 ) {
		var cgAccordion = new CgAccordion( $('#shoplist') );
	}

	checkAds();
	if (typeof toggleExtraOffers == 'function')
		toggleExtraOffers();
	if (typeof initFacetGATracking == 'function')
		initFacetGATracking();
	if (typeof initPromoGATracking == 'function')
		initPromoGATracking();
	if (typeof initGAQueryLink == 'function')
		initGAQueryLink();
	if (typeof initMiniFlightsForm == 'function')
		initMiniFlightsForm();
	if (typeof initWishlistTab == 'function')
		initWishlistTab();

	if (typeof tooltipInit == 'function')
		tooltipInit();

	if (typeof tinyGalleryInit == 'function')
		tinyGalleryInit();
	if (typeof fancyboxInit == 'function')
		fancyboxInit();
	if (typeof cgSliderInit == 'function')
		cgSliderInit();
	if (typeof googleAdsAjaxInit == 'function')
		googleAdsAjaxInit();
	if (typeof googleAdsMoveInit == 'function')
		googleAdsMoveInit();
	if (typeof analyticsEventInit == 'function')
		analyticsEventInit();
	if (typeof clickTaleEventInit == 'function')
		clickTaleEventInit();
	if (typeof compareTabInit == 'function')
		compareTabInit();
	if (typeof facetInit == 'function')
		facetInit();
	if (typeof pageInit == 'function')
		pageInit();
	initDropdowns();
	ajaxTooltipInit();

	var ytVideo = $(".youtube-video");
	$('tr.show-more a').click( function() {
		registerAnalyticsEvent('button-click', $(this).attr('href') , $('body').attr('class'));
	});

	if ( ytVideo.length > 0 ) {
		ytVideo.click(function() {
			$.fancybox({
				'padding'		: 0,
				'autoScale'		: false,
				'transitionIn'	: 'fade',
				'transitionOut'	: 'fade',
				'title'			: this.title,
				'width'			: 680,
				'height'		: 495,
				'href'			: this.href.replace(/watch\?v=/i, 'v/'),
				'type'			: 'swf',
				'swf'			: {
					'wmode'				: 'transparent',
					'allowfullscreen'	: 'true'
				}
			});
			return false;
		});
	}
	$('#review-tool .products').xfinxGallery({
		animationSpeed		: 150
	});

	$('#global-search').cgSearch({
		'url'				: '/q/',
		'urlPostFix'		: '/',
		'data'				: $(this).find('input.searchwords').data('cg-search')
	});

	$('#user-reviews-tool-search').cgSearch({
		'searchName'		: 'ac_review-tool-search',
		'data'				: $(this).find('input.searchwords').data('cg-search')
	});


	$('#feedback .iframe').fancybox({
		'centerOnScroll' : 'false',
		'hideOnOverlayClick' : 'false',
		'frameHeight' : 444,
		'width' : 760
	});
	initFormValidation();
	var pwdStrength	= new PasswordStrength();

	$('#new-password').live('change' , function() {
		pwdStrength.printScore( $(this) );
	});

	var hashParams = new HashParams();
	hashParams.scrollToAnchor();

	initJavaTimings();
	
	initFancyboxLinks();
	
	$('input[name="paymentMethod"]').bind('click', choosePaymentMethod);
});
function initializeMap() {
	var locationLong = $('#location_long').html();
	var locationLat = $('#location_lat').html();
	var street = ($('#location_street').html())? $('#location_street').html() : '';
	var houseNum = ($('#location_house_number').html())? $('#location_house_number').html() + ' ,' : '';
	var zip = ($('#location_zipcode').html())? $('#location_zipcode').html() + ' ,' : '';
	var address = street + houseNum + zip + $('#location_city').html();
	var latLng;
	
	if (locationLong.length && locationLat.length) {
		latLng = new google.maps.LatLng(locationLat, locationLong);
		createMap(latLng);
	} else if (address.length) {
		var geocoder = new google.maps.Geocoder();
		geocoder.geocode( {'address': address}, function(results, status) {
		  if (status == google.maps.GeocoderStatus.OK) {
			var location = results[0].geometry.location;
			latLng = new google.maps.LatLng(location.lat(), location.lng());
			createMap(latLng);
		  } else {
			$('#location_map').html("Geocode was not successful for the following reason: " + status);
			$('#location_map').show();
		  }
		});
	}
}

function createMap(latLng) {
	$('#location_map').show();
	var myOptions = {
		zoom: 18,
		center: latLng,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};
	var map = new google.maps.Map(document.getElementById("location_map"), myOptions);
	var marker = new google.maps.Marker({
		map: map,
		position: latLng,
		icon: '/images/location_map.png'
	});
}

function choosePaymentMethod(event) {
	$('.payment-method').animate({
		"background-color" : "#FFFFFF"
	}, 200, 'linear');
	$(this).parent().parent().animate({		
		"background-color" : "#EFF4F8"
    }, 600, "linear");
}

function setFancyboxBorders() {	
	if ($('html').hasClass('ie7') || $('html').hasClass('ie8')) {
		var height = ($("#fancybox-wrap").height() - 10) + "px";
		var width = ($("#fancybox-wrap").width() - 10) + "px";
		$("#fancybox-bg-e").css("height", height);
		$("#fancybox-bg-w").css("height", height);
		$("#fancybox-bg-n").css("width", width);
		$("#fancybox-bg-s").css("width", width);
	}
}

function removeFancyboxBorders() {
	if ($('html').hasClass('ie7') || $('html').hasClass('ie8')) {
		$("#fancybox-bg-e").removeAttr("style");
		$("#fancybox-bg-w").removeAttr("style");
		$("#fancybox-bg-n").removeAttr("style");
		$("#fancybox-bg-s").removeAttr("style");
	}
}

function initFancyboxLinks() {
	$('body').delegate('.fancybox', 'click', function() {
		var self    = $(this),
		fbData  = self.data('cgfancybox');
		$.fancybox({
			autoScale           : false,
			width               : fbData && fbData.width    ? Number(fbData.width) : '400',
			height              : fbData && fbData.height   ? Number(fbData.height): '400',
			type                : fbData && fbData.type ? fbData.type : '',
			hideOnOverlayClick  : fbData && fbData.hideonoverlayclick   ? fbData.hideonoverlayclick : false,
			href				: self.attr('href') ? self.attr('href') : false,
			onClosed			: fbData && fbData.onClosed == 'reload' ? top.location.reload : $.noop,
			transitionIn        : 'elastic',
			transitionOut       : 'elastic',
			onComplete			: function() {
				setFancyboxBorders();				
			},
			onCleanup			: function() {
				removeFancyboxBorders();
			}
		});
		return false;
	});	
}
if (!Modernizr.input.placeholder) {
	var inputPlaceholder = $('input[placeholder]');
	if (inputPlaceholder.length > 0 && inputPlaceholder.val() === '') {
		inputPlaceholder.val( inputPlaceholder.attr('placeholder') );
	}
	inputPlaceholder.mousedown( function() {
		$(this).val('');
	}).blur( function() {
		inputPlaceholder.val( inputPlaceholder.attr('placeholder') );
	});
}

/*
 * On load
 */
if (window.addEventListener) {
	window.addEventListener('load',function() {
		measurePageSpeed();
	},false);
} else if (window.attachEvent) { // IE DOM
	window.attachEvent("onload", function(){
		measurePageSpeed();
	});
}

function getTranslationsForValidation() {
	var ret = $.ajax({
		type: "GET",
		url: "/ajax/getTranslationsForValidation/",
		async:false
	}).responseText;
	return $.parseJSON(ret);
}

function initFormValidation() {
	if ( $('form.validate').length > 0 ) {
		$('form.validate').validate({
			errorPlacement: function(error, element) {
				element.after(error);
			},
			errorElement: "strong"
		});
		
		initFormValidationConfig();
	}
}

function initFormValidationConfig() {
	var validationTranslations = getTranslationsForValidation();

	jQuery.extend(jQuery.validator.messages, {
		required: validationTranslations['compare_validation_required'],
		remote: validationTranslations['compare_validation_remote'],
		email: validationTranslations['compare_validation_email'],
		url: validationTranslations['compare_validation_url'],
		date: validationTranslations['compare_validation_date'],
		dateISO: validationTranslations['compare_validation_date_iso'],
		number: validationTranslations['compare_validation_number'],
		digits: validationTranslations['compare_validation_digits'],
		creditcard: validationTranslations['compare_validation_creditcard'],
		equalTo: validationTranslations['compare_validation_equal_to'],
		accept: validationTranslations['compare_validation_accept'],
		maxlength: jQuery.validator.format(validationTranslations['compare_validation_maxlength']),
		minlength: jQuery.validator.format(validationTranslations['compare_validation_minlength']),
		rangelength: jQuery.validator.format(validationTranslations['compare_validation_rangelength']),
		range: jQuery.validator.format(validationTranslations['compare_validation_range']),
		max: jQuery.validator.format(validationTranslations['compare_validation_max']),
		min: jQuery.validator.format(validationTranslations['compare_validation_min'])
	});

	jQuery.validator.addMethod("custom-validation", function(value, element) {
		var regexp = new RegExp( $('#'+element.id).data('validation').replace(/\\/g,'\\') ,'g');
	  return this.optional(element) || regexp.test(value);
	}, validationTranslations['compare_validation_incorrect']);
}

/*
 * If JS has an error, we want to know that
 */
function registerJSError(msg, url, lineNr) {
	var errorMessage = '~errorMessage: "' + msg + '"';
	if (url) {
		errorMessage += ' | errorUrl: "' + url + '"';
		if (lineNr) {
			errorMessage += ' | lineNr: "' + lineNr + '"';		
		}
		errorMessage += ' | pageUrl: "' + document.location + '" | referrer: "' + document.referrer;
	}
	errorMessage += '"~';
	$.ajax({
		type: "GET",
		url: "/log/jserror/",
		data: ({
			type:'jsError',
			errorMessage:errorMessage
		}),
		dataType: "text"
	});
}
/*
 * Used to create a bookmark for Vergelijk.nl
 */
function createBookmarkLink() {
	var title = document.title;
	var d = document;
	var w = window;
	var url = d.location.href + "";
	if (w.sidebar) { // Mozilla Firefox Bookmark
		w.sidebar.addPanel(title, url, "", "", "");
	} else {
		if (w.external) { // IE Favorite
			w.external.AddFavorite(url, title);
		} else {
			if (w.opera && w.print) { // Opera Hotlist
		}
		}
	}
	return false;
}

function isFooterPresent() {
	if ( $('header').length ) {
		if ( $('footer').length ) {
			return true;
		}
		registerJSError('JSERROR: no footer!');
	}
	return false;
}

function initDropdowns() {
	var dr = $('select.dropdown-replace');
	var dd = $('.dropdown-trigger');

	if (dd.length > 0 && !dd.next().hasClass('dd-all')) {
		dd.dropdownReplacement({
			options			: function() {
				return $( '#' + this.data('dropdown') + '-options');
			}
		});
	}
	if (dr.length > 0 && !dr.next().hasClass('dd-all')) {
		dr.dropdownReplacement({
			optionsClass: 'dropdown-options',
			resizeOptionsToFitSelect: true,			
			onSelect : function(value, text, selectIndex){				
				//in this context, this = select
				if(dr.attr('class') == 'dropdown-replace'){
					var paymentMethodIdeal = $('#paymentMethodIdeal');					
					if(paymentMethodIdeal.attr('checked') == false){
						paymentMethodIdeal.attr("checked", "checked");
						paymentMethodIdeal.trigger('click', choosePaymentMethod);
					}
				}
			}			
		});
	}

}

function getLocaleSpecifics(locale) {
	var specifics = {
		"nl_NL"	: {
			"currency"	: "&euro; AMOUNT",
			"delimiter"	: ","
		},
		"nl_EC"	: {
			"currency"	: "&euro; AMOUNT",
			"delimiter"	: ","
		},
		"fr_FR"	: {
			"currency"	: "AMOUNT &euro;",
			"delimiter"	: ","
		},
		"fi_FI"	: {
			"currency"	: "AMOUNT &euro;",
			"delimiter"	: ","
		},
		"fr_BE"	: {
			"currency"	: "AMOUNT &euro;",
			"delimiter"	: ","
		},
		"nl_BE"	: {
			"currency"	: "AMOUNT &euro;",
			"delimiter"	: ","
		}
	};
	return specifics[locale];
}

function returnWithCurrencyFormat(amount) {
	amount += '';
	var localeSpecifics = getLocaleSpecifics( $('html').attr('lang') );
	if ( !amount.match(/\./) ) {
		amount += '.00';
	}
	var numbers = amount.split('.').join( localeSpecifics.delimiter );

	return localeSpecifics.currency.replace(/AMOUNT/g, numbers);
}

function ajaxTooltipInit() {
	var ttTrigger	= $('.tooltip-trigger-ajax'),
	ttName		= 'cg-tooltip-ajax';

	if ( ttTrigger.length > 0 ) {
		$('body').append('<div class="tool-tip" id="' + ttName + '" />');
		ttTrigger.tooltip({
			position: 'bottom left',
			delay: 500,
			predelay: 500,
			offset: [0,0],
			tip: '#'+ttName,
			onBeforeShow: function(){
				var data = this.getTrigger().data( "cg-tooltip" );
				if ( data.className ) {
					$('#cg-tooltip-ajax').addClass( data.className );
				}

				var url = data.url,
				$tip = this.getTip();

				$tip.html('<div class="small-spinner"></div>');
				$tip.html( getTooltipContent(url) );
			}
		}).dynamic();
	}
}
function initPlugins() {

}
function initListeners() {
	// show more button on offerpage

	$('#fancybox-overlay').live('click',function() {
		$.scrollTo($('#fancybox-wrap'));
	});
	$('.bookmark').click( function() {
		return createBookmarkLink();
	});

	$('a.submit-form').click(function() {
		$(this).parents('form').submit();
	});
	$('#googleads a').mouseover(function() {
		changeStatus($(this).find('.line2 a').html());
	}).mouseout(function() {
		changeStatus('');
	});
	$('.tooltip-trigger').each( function() {
		var self		= $(this),
		tmpTitle	= self.attr('title'),
		content		= tmpTitle ? tmpTitle : self.next().html(),
		ttData		= self.data('cg-tooltip'),
		activation	= self.attr('cg-tooltip-activation'),
		width		= '350px';
			
		if ( ttData && ttData.width ) {
			width = ttData.width;
		}
		activation = activation ? activation : 'hover';

		var tooltipActivated = false;
		var allowExit = false;
		function exit() {
			//debug.info(exit);
			//alert(exit.caller);
			if (tooltipActivated && !allowExit && activation == 'click') {
				// the only way (I could find) to obtain a reference to the close method
				var deactive_tiptip = exit.caller;
				allowExit = true;

				//debug.info('binding click');// to ' + deactive_tiptip);
				var el = $('#tiptip_holder a.close');
				el.bind('click', deactive_tiptip);

				//debug.info('unbinding hover from ');
				//debug.info(self);

				// [keepAlive = false] means the tooltip will close when the mouses moves outside the button and we don't want that
				self.unbind('mouseleave');
				// prevent premature closing
				throw 'nah';
			}
			self.attr('title', tmpTitle);
		}
		self.tipTip({
			activation		: activation,
			// make keepAlive false for the click activation to force exit() to be called
			keepAlive		: activation != 'click',
			maxWidth		: width,
			edgeOffset		: 15,
			delay			: activation == 'click' ? 0 : 1200,
			content			: function() {
				self.attr('title', '');
				if ( ttData ) {
					if ( ttData.url ) {
						content = getTooltipContent( ttData.url );
					} else if (ttData.element) {
						content = $(ttData.element).html();
					}
				}
				/*
				// this.deactive_tiptip() is not correct
				if (content == '') {
					this.deactive_tiptip();
					return content;
				}
				*/
				if (activation == 'click') {
					var holder = $('#tiptip_holder');
					if (holder.find('a.close').length <= 0) {
						holder.prepend('<a class="close"></a>');
					}
				}
				var ttContent = $('#tiptip_content');
				ttContent.html( content );
				return content;
			},
			enter			: function() {
				tooltipActivated = true;
			},
			exit			: exit
		});
	});
}

function measurePageSpeed() {
/*
	if (typeof gaTimeMeasureStart != 'undefined') { // this is a global variable
		var gaTimeMeasureElapsed = new Date().getTime() - gaTimeMeasureStart;
		var fn = document.location.pathname;
		if( document.location.search)
			fn += document.location.search;
		registerAnalyticsEvent('Page Load', 'Loading Pages', fn, gaTimeMeasureElapsed);
	}
    */
}

function initGAQueryLink() {
	// google wants to have the content of the link clicked.
	$('a[href]').click(function() {
		var base = $(this);
		if (base.attr('target') != '_blank') { // only do internal clicks
			var content = $.trim(base.html().replace(/<\/?(?!img)[^>]+>/g,''));
			$.cookie('query_link', content.substring(0,250), {
				path: '/'
			});
		}
	});
}

function initJavaTimings() {
	if ($('#java-timings').length > 0) {
		$('#java-timings h1').click(function(){
			var parent = $(this).parent();
			parent.find('div').toggle(50);
		});
	}
}
/*
 * Used as a short version for document.getElementById
 */
function getobj(name) {
	return document.getElementById(name);
}


(function($){
	$.miniFlightsForm = function(obj, options){
		// To avoid scope issues, use 'base' instead of 'this'
		// to reference this class from internal events and functions.
		var base = this;
		// Access to jQuery and DOM versions of element
		base.$obj = $(obj);
		base.obj = obj;

		// Add a reverse reference to the DOM object
		base.$obj.data("miniFlightsForm", base);

		base.init = function(){
			base.options = $.extend({},$.miniFlightsForm.defaultOptions, options);
			// Put your initialization code here
			base.initDates({
				element1		: 'date1',
				element2		: 'date2',
				altField1YM		: '#departureYearMonth',
				altField1D		: '#departureDay',
				altField2YM		: '#returnYearMonth',
				altField2D		: '#returnDay',
				altField1YMObj	: $('#departureYearMonth'),
				altField1DObj	: $('#departureDay'),
				altField2YMObj	: $('#returnYearMonth'),
				altField2DObj	: $('#returnDay'),
				altFormat		: 'yymm'
			});
			base.initAutocomplete();
		};
		// Sample Function, Uncomment to use
		base.initDates = function(options) {
			var date1 = $('.dates .' + options.element1);
			var date2 = $('.dates .' + options.element2);
			date1.datepicker({
				numberOfMonths: 1,
				dateFormat: base.options.dateFormat,
				dayNamesMin: base.options.dayNames,
				monthNames: base.options.monthNames,
				defaultDate: base.options.defaultDate1 + 'd',
				minDate: +1,
				altField: options.altField1YM,
				altFormat: options.altFormat,
				firstDay: 1,
				duration: '',
				monthNames: base.options.monthNames,
				onClose: function (datetxt, inst) {
					if (inst.selectedDay > 0) {
						base.checkPickerDates(datetxt, inst, options.element2, options);
						options.altField1DObj.val(inst.selectedDay);
					}
					$(this).removeClass('error');
					$('.' + options.element2).datepicker('option',{
						dateFormat: base.options.dateFormat,
						minDate: new Date(inst.currentYear, inst.currentMonth, inst.currentDay)
					});
				}
			});
			date2.datepicker({
				numberOfMonths: 1,
				dateFormat: base.options.dateFormat,
				dayNamesMin: base.options.dayNames,
				monthNames: base.options.monthNames,
				minDate: base.options.defaultDate1 + 'd',
				defaultDate: base.options.defaultDate2 + 'd',
				altField: options.altField2YM,
				altFormat: options.altFormat,
				firstDay: 1,
				duration: '',
				onClose: function (datetxt, inst) {
					if (inst.selectedDay > 0) {
						base.checkPickerDates(datetxt, inst, options.element1, options);
						options.altField2DObj.val(inst.selectedDay);
					}
					$(this).removeClass('error');
				}
			});

			if (date1.length > 0) {
				if (date1.val().length < 1) {
					date1.val(base.setInputDate(base.options.defaultDate1));
					options.altField1DObj.val(base.setInputDate(base.options.defaultDate1,'day'));
					options.altField1YMObj.val(base.setInputDate(base.options.defaultDate1,'yearmonth'));
				}
				if (date2.val().length < 1) {
					date2.val(base.setInputDate(base.options.defaultDate2));
					options.altField2DObj.val(base.setInputDate(base.options.defaultDate2,'day'));
					options.altField2YMObj.val(base.setInputDate(base.options.defaultDate2,'yearmonth'));
				}
			}
		};

		base.checkPickerDates = function(datetxt, inst, current, options) {
			var d; // day
			var ym;  // yearmonth
			var txt;  // visible value
			if (inst.selectedDay < 10) {
				inst.selectedDay = '0' + inst.selectedDay;
			}
			inst.selectedMonth += 1; // the month starts with 0
			if (inst.selectedMonth < 10) {
				inst.selectedMonth = '0' + inst.selectedMonth;
			}
			var cym = Number(inst.selectedYear + '' + (inst.selectedMonth)); // current year month

			if (current == options.element1) {
				d = options.altField2DObj;
				ym = options.altField2YMObj;
				txt = $('.' + options.element2);
				if (cym >= Number(ym.val())) {
					if (inst.selectedDay >= Number(d.val()) || cym > Number(ym.val()) ) {
						d.val( inst.selectedDay );
						ym.val( cym );
						txt.val( datetxt );
					}
				}
			}
		};
		base.initAutocomplete = function() {
			var autocompleteUrl = '/polling/destinationSearch';
			$('.cities input[type=text]').autocomplete(autocompleteUrl, {
				minChars: 2,
				max: 25,
				width: 176,
				matchContains: true,
				autoFill: false,
				delay: 150,
				matchSubset: false,
				scrollHeight: 220,
				submitWithEnter: false,
				formatItem: function(row, i, max) {
					return "<span class=\"city\">" + row[1] + "</span>" + "<span class=\"iata\">[" + row[0] + "]</span>" + " - " + "<span class=\"country\">" + row[2] + "</span>" ;
				},
				formatResult: function(row) {
					return row[1] + " - " + row[2] + " [" + row[0] + "]";
				}
			}).result( function (event, row, formatted) { // the iata input field should be updated also
				$(this).siblings('input[type=hidden]').val(row[0]);
			});
		};
		base.setInputDate = function (daysMore, returnValue, val) {
			var date = new Date();
			var day = date.getDate(val);
			var month = date.getMonth();
			var year = date.getFullYear();
			var nextWeekDay;
			nextWeekDay = new Date(year, month, day + daysMore); // first monday in that week
			// an array starts at 0 and our months numbers start at 1
			var rMonth = Number(nextWeekDay.getMonth() + 1);
			if (rMonth < 10) {
				rMonth = 0 + '' + rMonth;
			}

			if (returnValue == 'yearmonth') {
				return nextWeekDay.getFullYear() + '' + rMonth;
			} else if (returnValue == 'day') {
				return nextWeekDay.getDate();
			}
			if (nextWeekDay.getDate() < 10) {
				day = '0' + nextWeekDay.getDate();
			} else {
				day = nextWeekDay.getDate();
			}
			return day + '-' + rMonth + '-' + nextWeekDay.getFullYear();
		};
		// Run initializer
		base.init();
	};
	$.fn.miniFlightsForm = function(options){
		return this.each(function() {
			(new $.miniFlightsForm(this, options));
		});
	};
})(jQuery);


	
/*
 * Used for collapsing and uncollapsing facets
 */
function toggleHeight(item1) {
	var x = getobj("ml_" + item1);
	if (x) {
		x.innerHTML = toggleText(x.innerHTML, "[+]", "[-]");
	}
	var r = getobj(item1);
	if (r) {
		if (r.style.height == "1px") {
			r.style.height = "auto";
			r.style.overflow = "";
		} else {
			r.style.height = "1px";
			r.style.overflow = "hidden";
		}
	}
}


/*
 * Used on adsense. It will display the url in the statusbar
 */
function changeStatus(text) {
	window.status = text;
	return false;
}

/*
 * Function which calls the backend and asks for translations
 * expects
 * - array list
 * returns
 * list with results in json formattoolt
 */
function getTranslations(list) {
	var ret = $.ajax({
		type: "GET",
		url: "/ajax/getTranslations/",
		data: ({
			list:list.join(',')
		}),
		async:false
	}).responseText;
	return $.parseJSON(ret);
}

function getTranslationsForGlobalSearch() {
	var ret = $.ajax({
		type: "GET",
		url: "/ajax/getTranslationsForGlobalSearch/",
		async:false
	}).responseText;
	return $.parseJSON(ret);
}

/* plugin for our globalsearch
 * expects:
 *  - 'searchName'		: 'ac_globalSearch',
 *  - you being sweet for the creator ;-)
 *
 * optional:
 *  - suggestSearchUrl (default false)
 *  - url (default '')
 *  - urlPostFix (default '')
 *  - translation
 *    - noSearchWord (default english translation)
 *    - suggest	(default false)
 */
(function($){
	$.cgSearch = function( obj, options ){
		var self = this;
		// Access to jQuery and DOM versions of element
		self.$obj = $( obj );
		self.obj = obj;
		// Add a reverse reference to the DOM object
		self.$obj.data( "cgSearch", self );
		self.options = options;
		/* First add some default options.
		 * to make sure it works out of the box.
		*/
		self.defaultOptions = {
			'url'				: '', // string
			'urlPostFix'		: '', // string
			'searchName'		: 'ac_global-search',
			'data'				: {
				'suggest-search-url'	: '' // string || false
			},
			/* We make use of another plugin here which is autocomplete.
			 * We want to have some default options for this to.
			 */
			autocomplete		: {
				'minChars'			: 2,
				'max'				: 10,
				'width'				: 405,
				'matchContains'		: true,
				'autoFill'			: false,
				'delay	'			: 150,
				'cacheLength'		: 1,
				'matchSubset'		: false,
				'selectFirst'		: false,
				'scroll'			: false,
				'extraParams'		: {
					'q	'				: '',
					'search	'			: function () {
						return self.searchInput.val();
					}
				}
			}

		};

		/* We do not want to use global variables So we grab them with ajax
		 */
		self.defaultOptions.translation = getTranslationsForGlobalSearch();
		
		/* Now we are overwriting the self specified options with the default options
		 */
		self.options = $.extend( {}, self.defaultOptions, self.options );

		/* This is an initialisation function. Everything that has to be done automatically should be entered here
		 */
		self.init = function(){
			self.searchInput	= self.$obj.find('input.searchwords');
			self.setFocus();
			if ( self.options.data && self.options.data['suggest-search-url'] ) {
				self.searchSuggest();
			}
			self.addListeners();
		};

		/* The listeners listens to a click for instance and behaves the same as the "onclick" attribute
		 * on a tag
		 */
		self.addListeners = function() {
			self.$obj.submit( function() {
				return self.sanitiseSearch();
			});
			self.searchInput.click( function () {
				if ($(this).val() === self.options.translation['compare_global_search_no_search_term_selected'] ) {
					$(this).removeClass('error').val('');
				}
			});
			self.$obj.find('.submit-button , .submit-button-end').click(function() {
				$(this).parents('form').submit();
			});
			return self;
		};

		/* Semetimes we want to have default focus on the searchbox. The function below
		 * sets that focus if it the right conditions apply
		 */
		self.setFocus = function() {
			var hashParams = new HashParams();
			if (options.focus != 'false' && !hashParams.getAnchor()) {
				self.searchInput.focus();
			}
			return self;
		};
		/* By default people can put crap in the searchbox.
		 * This function sanitises that input and in some cases, if we want to have a nice url out of it,
		 * it will navigate to that url (/q/wasmachine/)
		 */
		self.sanitiseSearch = function (){
			var sw = self.searchInput.val();
			// if no searchword is filled in, replace the empty value with an errormessage
			// set class to error, so the text is red
			// make sure when people alter the text again, the errorclass is removed
			if ( sw === self.options.translation['compare_global_search_no_search_term_selected'] ) {
				self.searchInput.addClass('error');
				return false;
			} else {
				sw = filterSearchTerm(sw);
				if ( sw.replace(/^\s*$/g, '') === '' ) {
					self.searchInput.addClass( 'error' ).val( self.options.translation['compare_global_search_no_search_term_selected'] );
					return false;
				}
				if (self.options.url != '') {
					top.location.href = self.options.url +  encodeURIComponent( sw ) + self.options.urlPostFix;
				} else {
					return true;
				}
			}
			// To make sure the form doesn't actually submits;
			return false;
		};
		/*
 *  The function below invokes the suggest search
 *  this requires old version of autocomplete (http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/)
 */
		self.searchSuggest = function() {
			var xsSuggest = "<span class=\"over-top-left\"></span><span class=\"over-top-right\"></span><span class=\"suggestion\">"+self.options.translation['compare_global_suggest_search_suggestion']+"</span>";
			self.searchInput.autocomplete(self.options.data['suggest-search-url'], {
				dataType: 'json',
				// This will parse the fredhopper string into something autocomplete can eat.
				parse: function(data) {
					var rows = [];
					if (data != null && data.suggestionGroups[0]) {
						data = data.suggestionGroups[0].suggestions;
						for(var i=0; i<data.length; i++){
							rows[i] = {
								data	: data[i],
								value	: data[i].searchterm,
								result	: data[i].searchterm
							};
						}
					}
					return rows;
				},

				minChars		: self.options.autocomplete.minChars,
				max				: self.options.autocomplete.max,
				width			: self.options.autocomplete.width,
				matchContains	: self.options.autocomplete.matchContains,
				autoFill		: self.options.autocomplete.autoFill,
				delay			: self.options.autocomplete.delay,
				cacheLength		: self.options.autocomplete.cacheLength,
				matchSubset		: self.options.autocomplete.matchSubset,
				selectFirst		: self.options.autocomplete.selectFirst,
				scroll			: self.options.autocomplete.scroll,
				extraParams		: {
					q				: self.options.autocomplete.q,
					search			: function () {
						return self.searchInput.val();
					}
				},
				resultsClass: self.options.searchName,
				formatItem: function(row, i, max) {
					if (row['searchterm']) {
						$( '.' + self.options.searchName ).css( 'visibility','' );
						if ( $( '.' + self.options.searchName + ' span' ).length == 0 ) {
							$( '.' + self.options.searchName ).append(xsSuggest);
						}
						return "<span class=\"searchterm\">" + row['searchterm'] + "</span>";
					}
					$( '.' + self.options.searchName ).css('visibility','hidden');
					return false;
				}
			}).result( function (event, data, formatted) {
				if (formatted == null) {
					self.searchInput.parents('form').submit();				
				} else {
					self.searchInput.val(formatted).parents('form').submit();					
				}
			});
		};
		self.init();
	};

	/*	This is some plugin specific stuff
 */

	$.fn.cgSearch = function(options){
		if (!options) {
			options = [];
		}
		return this.each(function(){
			(new $.cgSearch(this, options));
		});

	};

})(jQuery);

function filterSearchTerm(sw) {
	// now use regexp to 'style' the searchword and get to a new url
	// replace1: convert strange chars to spaces
	// replace2: convert multiple spaces to single spaces
	// trim string
	sw = $.trim(sw.replace(/[\/:%~\\;]/g, " ").replace(/\s{2,}/g, " ").replace(/^\s(.+?)\s$/, "$1"));
	return sw;
}

function TinyGallery(smallImagesList, smallSize, bigImagesList, bigSize) {
	var bigImageWrapper = $('.product-images span');
	var smallImageWrapper = $('.small-images span');
	var navigationElements = $('.small-images-navigation a');
	var smallImageViewPort = $('.small-images');
	this.effects = 'easeOutQuint';

	var i = 0;
	for (i = 0; i < smallImagesList.length; i++) {
		smallImageWrapper.append('<img src="'+smallImagesList[i]+'" alt="" width="'+smallSize+'"/>');
	}
	for (i = 0; i < bigImagesList.length; i++) {
		bigImageWrapper.append('<img src="'+bigImagesList[i]+'" alt="" width="'+bigSize+'"/>');
	}

	// if a small image is hovered, move the big image to the display location
	var bigImage = bigImageWrapper.find('img');
	var smallImage = smallImageWrapper.find('img');

	var moveBigImages = function (o) {
		position = '-'+ bigSize * (o.index());
		bigImageWrapper.clearQueue().animate({
			left: position+'px'
		},{
			duration: 300,
			easing: this.effects
		});

	};
	smallImage.mouseover(function () {
		moveBigImages($(this));
	});

	var currentGalleryPosition = '';
	if (smallImageWrapper.css('left') ){
		currentGalleryPosition = smallImageWrapper.css('left').replace(/px/,'');
	}
	var steps = smallSize;
	var newPos = 0;
	
	var moveSmallImages = function (o) {
		var doAnimate = true;
		currentGalleryPosition = smallImageWrapper.css('left').replace(/px/,'');
		if (o.attr('class') == 'next') {
			// calculate new position
			newPos = ((-1 * currentGalleryPosition) + steps);
			if (newPos < smallImageWrapper.width() - smallImageViewPort.width()) {
				// change the active state
				o.removeClass('inactive');
				o.siblings('a').removeClass('inactive');
			} else {
				// set position to maximum
				newPos = smallImageWrapper.width() - smallImageViewPort.width();
				// change the active state
				o.addClass('inactive');
				o.siblings('a').removeClass('inactive');
				doAnimate = false;
			}
			if (doAnimate) {
				smallImageWrapper.animate({
					left: '-' + newPos + 'px'
				}, {
					duration: 200,
					easing: this.effects
				});
			}
		} else if (o.attr('class') == 'prev') {
			// calculate new position
			newPos  = ((1 * currentGalleryPosition) + steps );
			if (newPos < 1) {
				// change active state
				o.removeClass('inactive');
				o.siblings('a').removeClass('inactive');
			} else {
				// set position to minimum
				newPos = 0;
				// change active state
				o.addClass('inactive');
				o.siblings('a').removeClass('inactive');
				doAnimate = false;
			}
			if (doAnimate) {
				smallImageWrapper.animate({
					left: newPos + 'px'
				}, {
					duration: 200,
					easing: this.effects
				});
			}
		}
	};
	navigationElements.mousedown(function() {
		return false; // disable selecting the images and text in navigation
	}).click(function () {
		moveSmallImages($(this));
		return false;
	});
}

/*
 * Compare functionality
 * used on related.xhtml, product_list.xhtml, product_grid.xhtml
 */
/*
 * Getting the cookie and redirecting to the comparison page
 */
function makeCompareUrl() {
	var idList = $.cookie('productCompare');
	if (idList) {
		var selectedItems = idList.split(';');
		if (idList != '' && selectedItems.length > 1) {
			idList = idList.replace(/;/g,'/');
			document.location.href="/compare/"+idList+"/";
		} else {
			alert(compareNotEnough);
			return false;
		}
		return true;
	}
	return false;
}

/*
 * Js for bar which is on the bottom of our site
 * expects
 *
 */

function MyCGBar(cgBar) {
	var list = $('#my-lists');
	if ( !list.hasClass('hidden') ) {
		this.bar = {
			'object'		: list.show(),
			'tabs'			: {
				'objects'		: list.find('.tabs li'),
				'active'		: ''
			}
		};
		this.bar.object.animate({
			bottom: '0px'
		},750);
		this.checkTabs();
		this.listener();
	}	
}
/*
 * adding a tab to the bar
 * expects:
 * - tabShort (short name for tab)
 * - tabName (normal name of the tab, can include funny chars, no "-char though
 * optional
 * - contentDefault (some written text about this tab)
 * - htmlDefault (some html)
 */
MyCGBar.prototype.addTab = function (tabOptions) {
	if (tabOptions) {
		var promotion = tabOptions.promotion || '';
		this.bar.object.find('.tabs').prepend("<li class=\""+tabOptions.tabShort+"\"><a rel=\"nofollow\">"+tabOptions.tabName+"<strong>(0)</strong>"+promotion+"</a></li>");
		this.bar.object.find('#tab-content').prepend('<div id="'+tabOptions.tabShort+'" class="my-lists-content"><div class="wrap"></div></div>');
		var wrap = $('#'+tabOptions.tabShort+' .wrap');
		if (tabOptions.contentDefault) {
			wrap.html('<p class="content-default">'+tabOptions.contentDefault+'</p>');
		}
		if (tabOptions.htmlDefault) {
			wrap.append(tabOptions.htmlDefault);
		}
		return true;
	}
	return false;
};

MyCGBar.prototype.checkTabs = function() {
	if ( this.bar.tabs.length ) {
		var tabs = this.bar.tabs;
		tabs.objects.each(function() {
			var className = $(this).attr('class');
			if (tabs[className] === true) {
				$(this).css('display','inline');
			}
		});
	}
};
/*
 * This function sets the correct bar height
 * expecting:
 * - object (of
 * optional:
 * - forceClose
 */
MyCGBar.prototype.setBarHeight = function(options) {

	if (options.forceClose) {
		$('.my-lists-content').animate({
			height:'0px'
		},600);
	} else {
		options.object.animate({
			height:(options.object.find('.wrap').height()+20)+'px'
		},300).siblings('.my-lists-content').animate({
			height:'0px'
		},300);
	}
};

/*
 * Function to set active tab and remove them from others
 * expects
 * - object (jquery tab object)
 * optional
 * - force (open/close)
 */
MyCGBar.prototype.setActiveTab = function(options) {
	if (options) {
		if (options.object) {
			var tabName = options.object.attr('class');
		}
		if ((options.object.hasClass('active') && options.force !== 'open') || options.force === 'close') {
			this.bar.tabs.active = '';
			if (!options.object.hasClass('nactive')) { // nactive = never active
				options.object.removeClass('active').siblings().removeClass('active');
			}
			this.setBarHeight({
				'object'		: this.bar.object.find('#'+tabName),
				'forceClose'	: true
			});
		} else {
			this.bar.tabs.active = tabName;
			if (!options.object.hasClass('nactive')) { // nactive = never active
				options.object.addClass('active').siblings().removeClass('active');
			}
			this.setBarHeight({
				'object'		: this.bar.object.find('#'+tabName)
			});
		}
		return true;
	}
	return false;
};
/*
 * This function listenes to actions on some elements
 */
MyCGBar.prototype.listener = function() {
	var thisCGBar = this;

	this.tabListener = function() {
		this.bar.object.find('.tabs').delegate('li','click',function() {
			thisCGBar.setActiveTab({
				'object' : $(this)
			});
		});
	};

	this.buttonListener = function() {
		var myList = this.bar.object;
		var tabs = this.bar.tabs.objects;
		myList.find('a.close').click(function(){
			thisCGBar.setActiveTab({
				'object' : tabs,
				'force' : 'close'
			});
		});
	};

	this.buttonListener();
	this.tabListener();
};

/*
 * JS to control lists of products (wishlist for example)
 * cgBar needs to exist
 * expecting:
 * - options
 * - name
 * - cookieName
 * optional
 * - maxItems
 * - buttonText
 * - onAdd
 *   - originalClassName
 *   - addClassName
 *   - buttonText
 */
function MyList(options) {
	if (cgBar) {
		this.list = {
			'object'		: options.object,
			'wrapObject'	: options.object.find('.wrap'),
			'name'			: options.name,
			'buttonText'	: options.buttonText,
			'maxItems'		: options.maxItems,
			'maxItemsError'	: options.maxItemsError,
			'cookieName'	: options.name,
			'onAdd'			: {
				originalClassName		: options.onAdd.originalClassName,
				addClassName			: options.onAdd.addClassName,
				buttonText				: options.onAdd.buttonText
			},
			products		: {}
		};
	}
	this.listener();
}

MyList.prototype.listener = function() {
	var myList = this;
	this.list.wrapObject.delegate('.remove','click',function() {
		myList.removeProduct({
			'p_id'	: $(this).attr('name')
		});
	});
	this.list.wrapObject.delegate('.makeCompareUrl','click',function() {
		myList.makeCompareUrl();
	});
	$('.add-to-wishlist').live('click',function() {
		var p_id = $(this).attr('name'); // name
		if (cgBar) {
			wishlist.addProduct({
				'p_id'			: p_id,
				'ajaxAddUrl'	: "/ajax/wishlist/add/" + p_id + "/",
				'ajaxRemoveUrl'	: "/ajax/wishlist/remove/" + p_id + "/",
				'forceShowBar'	: true
			});
		}
	});
};

MyList.prototype.productsAmount = function() {
	var amount = 0;
	for (var i in this.list.products) {
		amount++;
	}
	return amount;
};

MyList.prototype.updateHTML = function(product) {
	var cgTab = cgBar.bar.object.find('.tabs .'+this.list.name);
	var html = '<li class="xg-inner-element '+this.list.name+'-p_'+product.id+'"><img src="'+product.imgSrc+'" alt="" width="35"/><a href="'+product.href+'">'+product.name+'</a><a class="remove" name="'+product.id+'"></a></li>';
	if (product.addOnLoad === true) {
		/*
		 * When loading the products, they are inserted 1 by 1. Doing that appending will sort them in a different way
		 * than they get in.
		 */
		this.list.wrapObject.find('ul').append(html);
	} else {
		/*
		 * By default we want products to be inserted in the beginning. You'll see the product coming
		 * in at all times.
		 */
		this.list.wrapObject.find('ul').prepend(html);
	}


	if (this.list.onAdd.originalClassName) {
		var productActionItem = $('.'+this.list.onAdd.originalClassName+'[name='+product.id+']');
		if (this.list.onAdd.buttonText) {
			productActionItem.html(this.list.onAdd.buttonText);
		}
		if (this.list.onAdd.addClassName) {
			productActionItem.addClass(this.list.onAdd.addClassName);
		}
	}

	if (cgTab.find('strong').length == 0) {
		cgTab.find('a').append('<strong>('+this.productsAmount()+')</strong>');
	} else {
		cgTab.find('strong').html('('+this.productsAmount()+')');
	}
	if (product.forceShowBar) {
		if ((product.forceShowBar === 'firstItem' && this.productsAmount() == 1) || product.forceShowBar === true) {
			cgBar.setActiveTab({
				'object'		: cgTab,
				force			: 'open'
			});
		}
	}
	this.writeCompareCookie();
};

/*
 * Adding a product to a list
 * Expecting:
 * - imgSrc
 * - name
 * - href
 * - id
 * optional:
 * - forceShowBar (false, true, 'firstItem')
 * - ajaxAddUrl - should be used icw below
 * - ajaxRemoveUrl - should be used icw up
 */
MyList.prototype.addProduct = function(options) {
	var base = this;
	if (options) {
		var cgTab = cgBar.bar.object.find('.tabs .'+this.list.name);
		if (!this.list.products[options.p_id]) { // product already exists
			if ((this.productsAmount() < this.list.maxItems) || options.addOnLoad) {
				var imgSrc = '';
				if (options.imgSrc) {
					imgSrc = options.imgSrc.replace(/\d+x\d+/g,'70x52');
				}
				var product = {
					imgSrc			: imgSrc, // giving the image the correct size
					name			: options.name,
					href			: options.href,
					id				: options.p_id,
					addOnLoad		: options.addOnLoad,
					ajax			: {
						add				: options.ajaxAddUrl,
						remove			: options.ajaxRemoveUrl
					},
					forceShowBar	: options.forceShowBar,
					textSwitch		: options.textSwitch
				};
				if (product.ajax.add) {
					$.ajax({
						url: product.ajax.add,
						dataType: "json",
						success : function(data) {
							product.name = data.name;
							product.href = data.href;
							product.imgSrc = data.imgSrc;
							product.name = data.name;
							product.id = data.id;
							base.list.products[product.id] = product;
							base.updateHTML(product);
							registerAnalyticsEvent(base.list.name,product.name,$('body').attr('class'));
						}
					});
				} else {
					base.list.products[options.p_id] = product;
					base.updateHTML(product);
				}
			} else { // too much products
				alert(this.list.maxItemsError);
				cgBar.setActiveTab({
					'object'		: cgTab,
					force			: 'open'
				});
			}
		}
	}
	return false;
};

MyList.prototype.writeCompareCookie = function() {
	var selectedItems = [], i=0;
	for (var productId in this.list.products) {
		selectedItems[i++] = this.list.products[productId].id;
	}
	$.cookie(this.list.cookieName, selectedItems.join(';'), {
		path: '/',
		expires: 30
	});
	return true;
};

/*
 * removing product from bar
 * expected
 * - p_id (id of product)
 */
MyList.prototype.removeProduct = function(options) {
	if (options) {
		var cgTab = cgBar.bar.object.find('.tabs .'+this.list.name);

		this.list.object.find('.'+this.list.name+'-p_'+options.p_id).animate({
			'width' : '0px'
		},50, function() {
			$(this).remove();
		});

		$('#pa_'+this.list.products[options.p_id]+' .'+this.list.onAdd.originalClassName).removeClass(this.list.onAdd.addClassName).html();
		if (this.list.onAdd.originalClassName) {
			var productActionItem = $('#pa_'+options.p_id+' .'+this.list.onAdd.originalClassName);
			if (this.list.buttonText) {
				productActionItem.html(this.list.buttonText);
			}
			if (this.list.onAdd.addClassName) {
				productActionItem.removeClass(this.list.onAdd.addClassName);
			}
		}
		if (this.list.products[options.p_id].ajax.remove) {
			$.ajax({
				url: this.list.products[options.p_id].ajax.remove,
				dataType: "html"
			});
		}
		delete this.list.products[options.p_id];
		cgTab.find('strong').html('('+this.productsAmount()+')');
		this.writeCompareCookie();
	}
	return false;
};

/*
 * Compare functionality
 * used on related.xhtml, product_list.xhtml, product_grid.xhtml
 *
 * Getting the cookie and redirecting to the comparison page
 * expects:
 *
 */
MyList.prototype.makeCompareUrl = function() {
	var cookieName = this.list.cookieName;
	var idList = $.cookie(cookieName);
	if (idList) {
		var selectedItems = idList.split(';');
		if (idList != '' && selectedItems.length > 1) {
			idList = idList.replace(/;/g,'/');
			document.location.href="/compare/"+idList+"/";
		} else {
			alert(compareNotEnough);
			return false;
		}
		return true;
	}
	return false;
};

/*
 * Copyright (c) 2010 Bjorn Boonen
	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
 * Basic jquery plugin to add a small gallery.
 * Version
 *
 * expected
 * - interval (how many ms to check the width of the ul again?
 * - the following html-code: <div class="list xg-list"><ul></ul></div>
 */
(function($){
	$.xfinxGallery = function( obj, options ){
		// To avoid scope issues, use 'self' instead of 'this'
		// to reference this class from internal events and functions.
		var self = this;

		// Access to jQuery and DOM versions of element
		self.$obj = $( obj );
		self.obj = obj;

		self.defaultOptions = {
			recalculate				: false,
			activeControls			: false,
			innerBox				: 'xg-inner',
			innerElement			: 'xg-inner-element',
			animationSpeed			: 300,
			animationType			: 'swing',
			autoAnimate				: false,
			autoAnimateRestartTime	: 10000,
			autoAnimateInterval		: 1000
		};

		self.options = $.extend( {}, self.defaultOptions, options );
		self.$innerBox = self.$obj.find( '.' + self.options.innerBox );

		// Add a reverse reference to the DOM object
		self.$obj.data( "xfinxGallery", self );
		self.animating = false;

		self.init = function(){
			// add the class xg-wrap fir styling purposees
			self.$obj.addClass( 'xg-wrap' );
			// if no xg-list is defined, create our own.
			if (self.$obj.find( '.' + self.options.innerBox ).length === 0) {
				self.$obj.append( '<ul class="'+self.options.innerBox+'"></ul>' );
			}

			// some basic initialisations
			self.innerWidth		= 0;
			self.itemWidth		= 0;
			self.ul				= {
				$obj				: self.$innerBox,
				'location'			: 0
			};

			// First calculate the width of the ul/xg-inner
			if ( self.options.recalculate ) {
				setInterval( function() {
					self.setInnerWidth();
				}, self.options.recalculate );
			} else {
				self.setInnerWidth();
			}
			self.listener();
			if ( self.options.autoAnimate ) {
				self.autoAnimation();
			}
		};


		self.setInnerWidth = function() {
			self.innerWidth = 0;
			var contentObj = self.$innerBox.find('.'+self.options.innerElement);
			self.innerWidth += contentObj.outerWidth(true); // true gives margin and border also
			self.itemWidth = self.innerWidth;
			// now multiply the width per item by the number of items
			self.innerWidth *= contentObj.length;

			// The ul can have padding also, as in the (current) normal boxmodal
			// padding extends the width, so there is no trouble there yet. Might
			// be interesting later though ;-)
			self.ul.$obj.width( self.innerWidth );
			if (!self.activeControls) {
				if ( self.innerWidth > self.$obj.outerWidth(true) ) {
					self.addControls();
				}
			} else {
				if ( self.innerWidth < self.$obj.outerWidth(true) ) {
					self.removeControls();
				}
			}
		};

		self.addControls = function() {
			self.activeControls = true;
			var html = '';
			html = '<a class="xg-navigate xg-navigate-left disabled"></a><a class="xg-navigate xg-navigate-right"></a>';
			self.$obj.append( html );
		};

		self.removeControls = function() {
			self.activeControls = false;
			self.$obj.find('.xg-navigate').remove();
		};


		self.listener = function() {
			self.$obj.delegate( '.xg-navigate-left', 'click', function() {
				if ( !self.animating ) {
					self.killAutoAnimation();
					self.moveItems({
						'direction':'left'
					});
				}
			});
			self.$obj.delegate( '.xg-navigate-right', 'click', function() {
				if ( !self.animating ) {
					self.killAutoAnimation();
					self.moveItems({
						'direction':'right'
					});
				}
			});
		};

		self.moveItems = function( options ) {
			// we might want to continue automating.
			if ( !options.autoAnimation && self.options.autoAnimate === true && self.options.autoAnimateRestartTime > 0 ) {
				clearTimeout( self.restartAutoAnimation );
				self.restartAutoAnimation = setTimeout( function() {
					self.autoAnimateDirection = options.direction;
					self.autoAnimation();
				}, self.options.autoAnimateRestartTime );
			}

			// this sets animating to true, so clicking twice will result in only 1 action
			self.animating = true;
			var location = Number( self.ul.$obj.css( 'left' ).replace( /-?(\d+)px/g,'$1' ) );
			if ( options.direction === 'left' && -location < 0 ) {
				self.ul.location = ( -location + self.itemWidth );
			} else if ( options.direction === 'right' && ( location < ( self.innerWidth - self.$obj.width() ) ) ) {
				self.ul.location = ( -location - self.itemWidth );
			}

			// We want to trigger if a button is disabled or not.
			if ( self.ul.location < 0 ) { // is positioned to the left
				self.$obj.find( '.xg-navigate-left' ).removeClass( 'disabled' ); // if the beginning is not reached
			} else {
				self.$obj.find( '.xg-navigate-left' ).addClass( 'disabled' );
				self.ul.location = 0;
			}
			if ( -self.ul.location < ( self.innerWidth - self.$obj.width() ) ) { // if the end is not reached
				self.$obj.find( '.xg-navigate-right' ).removeClass( 'disabled' );
			} else {
				self.$obj.find( '.xg-navigate-right' ).addClass( 'disabled' );
				self.ul.location = self.$obj.width() - self.innerWidth;
			}

			// do animate!
			self.ul.$obj.animate({
				left : self.ul.location+'px'
			},self.options.animationSpeed, self.options.animationType, function() {
				self.animating = false;
			});
		};

		// this method starts the autoanimation.
		self.autoAnimation = function() {
			self.autoAnimateDirection = 'right';
			self.autoAnimateIntervalId = setInterval( function() {
				if ( -self.ul.location >= ( self.innerWidth - self.$obj.width() ) ) { // it reached the end, not go left
					self.autoAnimateDirection = 'left';
				} else if ( self.ul.location >= 0 ) { // it reached the beginning, now go right
					self.autoAnimateDirection = 'right';
				}
				self.moveItems({
					'direction' : self.autoAnimateDirection,
					'autoAnimation' : true
				});
			}, self.options.autoAnimateInterval);

		};

		//this method can kill the autoanimation
		self.killAutoAnimation = function() {
			clearInterval( self.autoAnimateIntervalId );
		};

		// Run initializer
		self.init();
	};

	$.fn.xfinxGallery = function(options) {
		if (!options) {
			options = [];
		}
		return this.each(function(){
			(new $.xfinxGallery(this, options));
		});
	};

})(jQuery);

/*
 * show or hide the comparison bar
 */
function toggleComparison(o, force, save) {
	//			$('#productComparison .tab, #productComparison .close').click(function () {
	//								toggleComparison($('#productComparison .comparison .wrap'));
	//							});
	if (force == 'show') {
		showComparison(o, save);
	} else if (force == 'hide') {
		hideComparison(o, save);
	} else if (!o.hasClass('visible')) {
		showComparison(o, save);
	} else if (o.hasClass('visible')) {
		hideComparison(o, save);
	}
}
function hideComparison(o, save) {
	if (save == true) {
		saveSettings({
			'category'	: compareCategoryUrl,
			'key'		: 'listComparison',
			'value'		: 'hide'
		});
	}
	o.animate({
		height:'0px'
	},300);
}
function showComparison(o, save) {
	if (save == true) {
		saveSettings({
			'category'	: compareCategoryUrl,
			'key'		: 'listComparison',
			'value'		: 'show'
		});
	}
	o.animate({
		height:'103px'
	},300);
}

/*
 * Add basic comparison tags
 */
function addProductComparisonHtml(compareButtonText) {
//$('#compare .wrap').append('<div class="actions"><a onclick="makeCompareUrl();" class="cg-button cg-button-right">'+compareButtonText+'<span></span></a><a onclick="$(\'#compare li .remove\').click()" class="remove-all">'+removeAllText+'</a></div><ul></ul>');
}
/*
 * remove a product from the comparison bar.
 * This is done if the cross is clicked
 */
function removeProductsFromComparisonList(id) {
	$('#compare ul li.p_'+id).animate({
		width: '0px'
	},50, function() {
		$(this).remove();
	});
	$('#pa_'+id+' input.product-compare').attr('checked',false);
	$.cookie('p_id_'+id,null, {
		path: compareCategoryUrl,
		expires: -10
	});
}
/*
 * Add product to comparions list
 */
function addProductsToComparisonList(id, href, img, name) {
	$('#compare .content-default').hide();
	var imgSrc = '';
	if (img.match(/108x88/)) {
		imgSrc = img.replace(/108x88/g,'70x52');
	} else if (img.match(/183x160/)) {
		imgSrc = img.replace(/183x160/g,'70x52');
	}

	var targetStr = '';
	if (href.indexOf('/clickout/') != -1) {
		targetStr = ' target="_blank" ';
	}

	$('#compare ul').append('<li class="p_'+id+'"><img src="'+imgSrc+'" alt="" width="35"/><a ' + targetStr + 'href="'+href+'">'+name+'</a><a class="remove" rel="'+id+'" onclick="compareProduct('+id+',true);"></a></li>');

	/*
	 * First we want to remove the old version of this cookie.
	 */
	if ($.cookie('p_id_'+id)) {
		$.cookie('p_id_'+id,null, {
			path: compareCategoryUrl,
			expires: -10
		});
	}
	/*
	 * Now we create a new cookie for this product. making sure it has all the latest and greates data
	 */
	var productCookie = id+';'+href+';'+img+';'+name;
	$.cookie('p_id_'+id, productCookie, {
		path: compareCategoryUrl,
		expires: 30
	});
}
/*
 * Adding the product to for comparison
 * This is the basic function which calls other functions
 */
function compareProduct(id,remove,visibility, isRelated) {
	var cookieName = 'productCompare';
	o = $('#pa_'+id+' input.product-compare').attr('checked',true);
	if ($('#compare ul').length == 0) {
		addProductComparisonHtml(compareButtonText);
	}
	var selectedItems = [];
	var currentCookie = $.cookie(cookieName);
	if (currentCookie) {
		selectedItems = currentCookie.split(';');
		// below is needed for deleting and adding a duplicate..
		for (var i=0; i<=selectedItems.length;i++) {
			if (selectedItems[i] == id) {
				// removing the elements
				if (i > 0) {
					selectedItems.splice(i,1);
				} else {
					selectedItems.shift();
				}
				removeProductsFromComparisonList(id);
			}
		}
	}
	var details = $('#p_'+id).find('.product-image');
	if ((o.is(':checked') || isRelated) && !remove && selectedItems.length < maxCompare) {
		if ( details.find('a').length > 0 ) { // is lister page
			addProductsToComparisonList(id, details.find('a').attr('href'), details.find('img:not(.imagemapoverlay)').attr('src'), details.find('img:not(.imagemapoverlay)').attr('alt'));
		} else { // is grid view page
			addProductsToComparisonList(id, details.attr('href'), details.find('img').attr('src'), details.find('img').attr('alt'));
		}
		saveSettings({
			'key'	: 'myListVerticalTabActive',
			'value'	: 'compare'
		});

		// add the product
		selectedItems.push(id);
		if (visibility != 'hidden') {
			toggleComparison($('#mylist'),'show');
			cgBar.setActiveTab({
				'object'		: cgBar.bar.object.find('.tabs .compare'),
				force			: 'open'
			});
		}
		$('#compare .actions').show();
	} else if (!remove && selectedItems.length >= maxCompare) {

		alert(compareIntroductionTooMany);
		cgBar.setActiveTab({
			'object'		: cgBar.bar.object.find('.tabs .compare'),
			force			: 'open'
		});
		o.attr('checked',false);
	} else {
		if (selectedItems.length < 1) {
			toggleComparison($('#mylist'),'hide');
			cgBar.setActiveTab({
				'object'		: cgBar.bar.object.find('.tabs .compare'),
				force			: 'close'
			});
			$('#compare p').show();
			$('#compare .actions').hide();
		}
		removeProductsFromComparisonList(id);
	}
	/*
	 *Add the master cookie with all productid's in them
	 */
	if (selectedItems.length > 0) {
		var newCookie = selectedItems.join(';');
		$.cookie(cookieName, newCookie, {
			path: compareCategoryUrl,
			expires: 30
		});
	} else {
		$.cookie(cookieName, '', {
			path: compareCategoryUrl,
			expires: -10
		});
	}
	$('#my-lists .tabs .compare strong').html('('+ selectedItems.length +')');

}

/*
 * Called on pageload. This function checks the cookies, and adds something on the page if needed.
 * Or removes the cookie if invalid
 */
function initialiseCompareProducts (related) {
	//$('#my-lists .tabs .compare a').append('<strong>(0)</strong>');
	var cookieName = 'productCompare';
	if ($('#compare ul').length == '0') {
		addProductComparisonHtml(compareButtonText);
	}

	var selectedItems = [];
	var currentCookie = $.cookie(cookieName);
	var deleteMasterCookie = false;
	/*
	 * If the masterCookie exisist we want to perform actions
	 */
	if (currentCookie) {
		selectedItems = currentCookie.split(';');

		for (var i=0; i<selectedItems.length;i++) {
			var p_id = selectedItems[i];
			if (i < maxCompare ) {
				var productCookie = $.cookie('p_id_'+p_id);
				var product = [];
				if (productCookie) {
					product = productCookie.split(';');
				}
				/* cookielayout:
				 * productName;productHref;productImageSrc;
				 */
				if (product.length > 0) {
					if (related) {
						if (related == p_id) {
							continue;
						}
					}
					addProductsToComparisonList(p_id, product[1], product[2], product[3]);
					$('#pa_'+p_id).find('input.product-compare').attr('checked',true);
				} else {
					/*
					 * This means that we do not have the correct cookies. So the mastercookie should be removed
					 */
					deleteMasterCookie = true;
				}
			}
		}
		
		if (deleteMasterCookie != false) {
			$.cookie(cookieName, '', {
				path: compareCategoryUrl,
				expires: -10
			});

		}

	}
	if (selectedItems.length > 0) {
		$('#my-lists .tabs .compare strong').html('('+ selectedItems.length +')');
	}
}



/*
CGSlider will use some html to create a slider for facets.
 */
function CGSlider(name, buttonText, range) {
	this.isRange		= range;
	this.buttonText		= buttonText;
	this.htmlObject		= $('#slider_'+name);
	this.name			= name;
	this.values			= {
		'htmlMin'		: this.htmlObject.find('.range-min span'),
		'htmlMax'		: this.htmlObject.find('.range-max span'),
		'elementMin'	: this.htmlObject.find('.min-value').val(),
		'elementMax'	: this.htmlObject.find('.max-value').val(),
		'selectedMin'	: this.htmlObject.find('.selected-min-value').val(),
		'selectedMax'	: this.htmlObject.find('.selected-max-value').val()
	};
	this.link			= {
		'url'			: this.htmlObject.find('.slider-link').val(),
		'queryString'	: '?' + window.location.search.substring(1)
	};
	this.dimensions		= {};
	// now hide the SEO-list elements and rely on jQuery's error handling (not showing errors by default)
	this.htmlObject.siblings('ul').hide();
	this.htmlObject.parents('.'+this.name).siblings('.'+this.name).remove();
	if (this.values.elementMin == this.values.elementMax) { // when this happens, showing a slider is not very helpful
		this.htmlObject.parents('.facet').hide();
	} else {
		if (this.values.elementMin) {
			// We need real numbers to calculate with, not 'strings'
			this.values.min = Number(this.values.elementMin.replace(/^.*?(\d+).*/g,'$1'));
			this.values.selectedMin = Number(this.values.selectedMin.replace(/^.*?(\d+).*/g,'$1'));
			if (this.values.selectedMin == 0) {
				this.values.selectedMin = this.values.min;
			} else {
			//			this.values.selectedMin++; // fredhopper only shows values between. excluding the selected values. The link is set to be -1 so it needs to be corrected here
			}

			if (this.isRange) {
				// We need real numbers to calculate with, not 'strings'
				this.values.max = Math.ceil(Number(this.values.elementMax.replace(/^.*?([\d.]+).*/g,'$1')));
				this.values.selectedMax = Math.ceil(Number(this.values.selectedMax.replace(/^.*?([\d.]+).*/g,'$1')));
				if (this.values.selectedMax == 0) {
					this.values.selectedMax = this.values.max;
				} else {
			//				this.values.selectedMax--; // fredhopper only shows values between. excluding the selected values. The link is set to be +1 so it needs to be corrected here
			}
			}
			// The dimensions will be used to position handles on the slider
			this.dimensions = {
				pixels		: this.htmlObject.width(),
				power		: 25,
				powerValue	: 2500 / (Math.log(this.values.max/(0.1 + this.values.min)) / Math.log(10))
			};

			// These values are purely for display, that is the reason they are below here. No calculations with them.
			this.values.min = Math.round(this.values.min);
			this.values.htmlMin.html(this.values.selectedMin);

			if (this.isRange) {
				this.values.max = Math.round(this.values.max);
				this.values.htmlMax.html(this.values.selectedMax);
			}
		}
		if (this.isRange) {
			this.initiateRangeSlider();
		}
		else {
	// this.initiateRegularSlider();
	}
	}
}

CGSlider.prototype.initiateRangeSlider = function () {
	var cgSliderObject = this; // We need that is 'this' should be available from within the slide function
	var re = new RegExp( '(' + cgSliderObject.name + '.*__c__.*?/|/$)' , '' );
	this.htmlObject.find('.slider').slider({
		range: true,
		min: 0,
		max: cgSliderObject.dimensions.pixels,
		values: [cgSliderObject.rikkertsPixelFormula(cgSliderObject.values.selectedMin), cgSliderObject.rikkertsPixelFormula(cgSliderObject.values.selectedMax)],
		slide: function(event, ui) {
			var realVal1 = cgSliderObject.rikkertsValueFormula(ui.values[0]);
			var realVal2 = cgSliderObject.rikkertsValueFormula(ui.values[1]);
			cgSliderObject.values.htmlMin.html(realVal1);
			cgSliderObject.values.htmlMax.html(realVal2);
			cgSliderObject.link.url = cgSliderObject.link.url.replace(re,cgSliderObject.name+'/'+(realVal1)+'__c__0__a__'+cgSliderObject.name+'__a__'+(realVal2)+'__c__0/');
			if (cgSliderObject.htmlObject.find('a.cg-button-small').length == 0) {
				cgSliderObject.htmlObject.append('<a href="'+cgSliderObject.link.url+'" alt="" class="cg-button-small cg-button-small-right" >'+cgSliderObject.buttonText+'<span></span></a>');
				initFacetGATracking($('a.cg-button-small'));
			}
			cgSliderObject.htmlObject.find('a.cg-button-small').attr('href',cgSliderObject.link.url);
		}
	});
};

/*
 * This formula gets the amount in pixels and returns the amount in a certain euros ;;; pixel to value
 */
CGSlider.prototype.rikkertsValueFormula = function(sliderPosition) {
	if ((this.values.max - this.values.min) < this.dimensions.pixels) {
		return Math.round((((this.values.max - this.values.min) / this.dimensions.pixels) * sliderPosition) + this.values.min);
	}
	return  Math.round(this.values.min + ((this.values.max - this.values.min) * ((Math.pow(sliderPosition + this.dimensions.powerValue, this.dimensions.power) - Math.pow(this.dimensions.powerValue, this.dimensions.power)) / (Math.pow(this.dimensions.pixels + this.dimensions.powerValue, this.dimensions.power) - Math.pow(this.dimensions.powerValue, this.dimensions.power)))));
};
/*
 * This formula gets the amount in euros and returns the amount in a certain pixels ;;; value to pixel
 */
CGSlider.prototype.rikkertsPixelFormula = function(valuePosition) {
	if ((this.values.max - this.values.min) < this.dimensions.pixels) {
		return Math.round((this.dimensions.pixels / (this.values.max - this.values.min)) * (valuePosition - this.values.min) );
	}
	return Math.round(Math.pow(((((valuePosition - this.values.min) / (this.values.max - this.values.min)) * (Math.pow(this.dimensions.pixels + this.dimensions.powerValue, this.dimensions.power) - Math.pow(this.dimensions.powerValue, this.dimensions.power))) + Math.pow(this.dimensions.powerValue, this.dimensions.power)), 1/this.dimensions.power) - this.dimensions.powerValue);
};

function initHiddenFacets() {
	var collapsedFacet = $('#offer-facets .collapsed'),
		showAll = $('#offer-facets .facet .show-all');
		
	if (!getSetting({'category':compareCategoryUrl, 'key':'listFacets', 'value':'showAll'})) {		
			
		if (collapsedFacet.length > 0) {
			showAll.parents('.facet').show();
		}
		showAll.click(function () {
			showAll.parents('.facet').hide();
			collapsedFacet.slideDown('50');
			saveSettings({
				'key'		:	'listFacets',
				'value'		:	'showAll',
				'category'	:	compareCategoryUrl
			});
		});
	} else {
		collapsedFacet.show();
	}
}

/*
 * This function will save settings to a cookie
 */
function saveSettings(options) {
	this.settings = options;
	this.settings.category = this.settings.category ? this.settings.category : '/';
	var cookieName = 'settings_'+this.settings.category;
	var settingsCookie = $.cookie(cookieName);
	if (!getSetting({
		'key':this.settings.key,
		'value':this.settings.value
	})) {
		var setting = cookieString2Obj(settingsCookie);
		setting[this.settings.key] = this.settings.value;
		settingsCookie = ''; //making it empty
		if (setting > 0) {
			for (var i in setting) {
				if (setting[i]) {
					settingsCookie += i+':'+setting[i]+';';
				}
			}
		}
		else {
			settingsCookie += this.settings.key+':'+this.settings.value+';';
		}
		$.cookie(cookieName, settingsCookie, {
			path: this.settings.category,
			expires: 7
		});
	}
}
function cookieString2Obj(str) {
	var setting = {};	
	if (str) {
		var settings = str.split(';');
		var keyVal = [];
		for (var i=0,settingsLength = settings.length; i < settingsLength;i++) {
			keyVal = settings[i].split(':');
			setting[keyVal[0]] = keyVal[1];
		}
	}
	return setting;
}
/*
 * This function will read a single setting from a cookie
 * return true/false or the value
 */
function getSetting(options) {
	this.settings = options;
	this.settings.category = this.settings.category ? this.settings.category : '/';
	var cookieName = 'settings_'+this.settings.category;
	var	settingsCookie = $.cookie(cookieName);
	if (settingsCookie) {
		var setting = cookieString2Obj(settingsCookie);
		if (!this.settings.value) {
			return setting[this.settings.key];
		} else {
			return (setting[this.settings.key] == this.settings.value);
		}
	}
	return false;
}



/*
 * Used for writing a review. It will calculate the score
 */
function calcTotalReviewWriteScore() {
	var nrOfRatings = 0;
	var totalValue = 0;
	var avgValue = 0;
	$('#write .rating').each(function() {
		if ($(this).val() > 0 && $(this).val() <= 10) {
			nrOfRatings++;
			totalValue += Number($(this).val());
		}
	});
	if (nrOfRatings > 0) {
		avgValue = totalValue / (nrOfRatings);
		avgValue = (Math.round (avgValue * 10)) / 10;
	} else {
		avgValue = '?';
	}
	var reviewBlock = $('#write .total-rating .review-block');
	reviewBlock.find('.review-block-rating').html(avgValue);
	if (avgValue >= 7 ) {
		reviewBlock.find('.review-block-thumb').removeClass('review-block-thumb-down');
		reviewBlock.find('.review-block-thumb').removeClass('review-block-thumb-neutral');

		reviewBlock.find('.review-block-thumb').addClass('review-block-thumb-up');
	} else if (avgValue < 5 ) {
		reviewBlock.find('.review-block-thumb').removeClass('review-block-thumb-up');
		reviewBlock.find('.review-block-thumb').removeClass('review-block-thumb-neutral');

		reviewBlock.find('.review-block-thumb').addClass('review-block-thumb-down');
	} else {
		reviewBlock.find('.review-block-thumb').removeClass('review-block-thumb-up');
		reviewBlock.find('.review-block-thumb').removeClass('review-block-thumb-down');

		reviewBlock.find('.review-block-thumb').addClass('review-block-thumb-neutral');
	}

	reviewBlock.find('.review-block-rating').html(avgValue);

}
/*
 * slider for reviews
 */

function reviewSlider() {
	// initiate the slider
	$('.cg-slider .slider').slider({
		min: 1,
		max: 10,
		value: 6,
		slide: function(event, ui) {
			var reviewBlock = $(this).parents('.cg-slider').siblings('.review-block');
			$(this).parents('.cg-slider').siblings('input.rating').val(ui.value);
			reviewBlock.html(ui.value);
			if (reviewBlock.attr('class').match(/shop/)) {
				reviewBlock.addClass('review-block-shop');
				reviewBlock.removeClass('review-block-shop-add-review');
			} else {
				reviewBlock.removeClass('review-block-add-review');
			}
			$(this).parents('li').find('.errormessage').remove();
			calcTotalReviewWriteScore();
			$(this).parents('li').removeClass('error');
		}
	});
	// changed the reviewblock and disabling them
	$('.cg-slider').siblings('label').find('input').change(function () {
		var cgSlider = $(this).parent().siblings('.cg-slider');
		var reviewBlock = cgSlider.siblings('.review-block');
		if ($(this).is(':checked')) {
			cgSlider.addClass('disabled');
			reviewBlock.siblings('.rating-tmp').val(reviewBlock.html());
			reviewBlock.html('?');
			if (reviewBlock.attr('class').match(/shop/)) {
				reviewBlock.removeClass('review-block-shop');
				reviewBlock.addClass('review-block-shop-add-review');
			} else {
				reviewBlock.addClass('review-block-add-review');
			}
			cgSlider.siblings('.rating').val(0);
		} else {
			var origVal = reviewBlock.siblings('.rating-tmp').val();
			reviewBlock.siblings('.rating').val(origVal);
			reviewBlock.html(origVal);
			if (reviewBlock.attr('class').match(/shop/)) {
				reviewBlock.addClass('review-block-shop');
				reviewBlock.removeClass('review-block-shop-add-review');
			} else {
				reviewBlock.removeClass('review-block-add-review');
			}

			cgSlider.removeClass('disabled');
		}
		calcTotalReviewWriteScore();

	});
	// set the default value
	$('.cg-slider .slider').each(function() {
		var cgSlider = $(this).parent();
		var reviewBlock = cgSlider.siblings('.review-block');
		if (cgSlider.siblings('.rating').val() > 0) {
			$(this).slider('value',cgSlider.siblings('.rating').val());
			var origVal = cgSlider.siblings('.rating').val();
			reviewBlock.siblings('.rating').val(origVal);
			reviewBlock.html(origVal);
			if (reviewBlock.attr('class').match(/shop/)) {
				reviewBlock.addClass('review-block-shop');
				reviewBlock.removeClass('review-block-shop-add-review');
			} else {
				reviewBlock.removeClass('review-block-add-review');
			}

			cgSlider.removeClass('disabled');
		}
		calcTotalReviewWriteScore();
	});
}
function validateSliders(errors) {
	var nrSliders = $('#write .ratings .cg-slider').length;
	var isDisabled = $('#write .ratings .cg-slider.disabled').length;
	if (nrSliders == isDisabled) {
		var li = $('#write .ratings li');

		li.addClass('error');
		if (li.find('.errormessage').length == 0) {
			li.prepend('<span class="errormessage">'+sliderEmptyMessage+'</span>');
		}
		errors++;
	} else {
		$('#write .ratings li .review-block').each(function() {
			var li = $(this).parents('li');
			if ($(this).html().match(/\?/) && !$(this).siblings('.cg-slider').hasClass('disabled')) {
				isDisabled++;
				li.addClass('error');
				if (li.find('.errormessage').length == 0) {
					li.prepend('<span class="errormessage">'+sliderEmptyMessage+'</span>');
				}
				errors++;
				if (errors == 1) {
					li.focus();
				}
			} else {
				li.removeClass('error');
				$(this).siblings('errormessage').remove();
			}
		});
	}
	return errors;
}

/*
 * Used to display adsense using ajax
 * Google does not like this, so we only use this
 * for some live search categories like flights.
 */
function loadGoogleAds() {
	$.ajax({
		url: adsenseUrl,
		dataType: "html",
		success: function(html){
			// insert the bottom ads block
			html = html.replace(/^<div class="googleads" id="googleads">/gi,'').replace(/<\/div.*/gi,'');
			$("#googleads").html(html);
			moveGoogleAds();
		}
	});
}
/*
 * Used to move googleads code to placeholders defined in Java
 *
 */
function moveGoogleAds() {
	var googleAd = $("#googleads li");
	if ( googleAd.length ) {
		var numberOfAds = googleAd.size();
		googleAd.each( function(i) {
			if ($('.top-ad').hasClass("ph_" + i)) {
				$(".ph_" + i).append($(this));
				//$(this).remove();
				$(".phcont_" + i).show();
				if (i == (numberOfAds - 1)) {
					$("#googleads").remove();
				};
			}
		});
	}
}

/*
 * Some partners needs some extra tracking
 * a pixel for instance. We can add the 'pixel' to a ajax request
 */
function fireTrackingRequest(url) {
	if (url.length > 0) {
		$.ajax({
			url: url,
			dataType: "html",
			success: function(html) {
			}
		});
	}
}


/*
 * Sometimes we want to register an event in ClickTale.
 * To make sure we do not repeat ourselves here a function to call
 * whenever the call needs to be made.
 * This function should have all checks to keep it safe
 */

function registerClickTaleEvent(CTEvent) {
	if ($('#ClickTaleDiv').length > 1) {
		ClickTaleTag(CTEvent);
	}
}

/*
 * Google Analytics event tracking
 * As we can have multiple implementations, we have an async and normal variant.
 * Method accepts 2-4 arguments (varargs).
 */
function registerAnalyticsEvent() {
	var args = Array.prototype.slice.call(arguments);
	
	if (typeof(args[3]) != 'number') {
		args[3] = 9999999;
	}

	if (args.length < 2 || args.length > 4) return;
	if (window.pageTracker) {
		if (!args[2]) args[2] = ''; // default to ''
		if (!args[3]) args[3] = ''; // default to ''
		
		pageTracker._trackEvent(args[0], args[1], args[2], args[3]);
	} else if (window._gaq) { // ASYNC
		args.unshift('_trackEvent'); // put as first parameter
		_gaq.push(args);
	}
}

function checkAds () {
	var adsE = $('.ads');
	adsE.each(function() {
		if ($(this).length > 0) { // First check if the element actually exists (it will always have content)
			if ($(this).height() <= 30) { // If no banner is shown, there is no height
				if ($(this).hasClass('skyscraper')) {
					$('.overlay-site').addClass('overlay-wide');
				}
			}
		}
	});
}

function toggleExtraOffers () {
	if ($('#mainoffers').length > 0) {
		$('.shop-list-toggle div').click(function() {
			$(this).hide().siblings().show();
			$(this).parents('.show-more-offers').next('.more-offers').toggle();
		});
	}
}

/**
 * Initializes GA tracking for promos.
 */
function initPromoGATracking() {
	// Product promos
	if ($('#promotional').length > 0) {
		$('#promotional a').click(function() {
			var productTitle = '';

			var types = ["h3", "div.item-title"];

			for (var i = 0; i < types.length; i ++) {
				if ($(this).siblings(types[i]).length > 0) {
					productTitle = $(this).siblings(types[i]).html();
				} else if ($(this).parent().is(types[i])) {
					productTitle = $(this).html().replace(/^\s+|\s+$/g, '');
				} else if ($(this).parent().siblings(types[i]).find('a').html()) {
					productTitle = $(this).parent().siblings(types[i]).find('a').html().replace(/^\s+|\s+$/g, '');
				}
			}

			if (productTitle == '') {
				productTitle = 'n/a';
			}

			registerAnalyticsEvent('Promos', urlFriendlyCategoryName, productTitle);
		});
	}

	// Facet promos (products)
	if ($('#facet-promos .product-promo').length > 0) {
		$('#facet-promos .product-promo a').click(function() {
			registerAnalyticsEvent('Promos', urlFriendlyCategoryName, $(this).parent('div').siblings('h2').html());
		});
	}

	// Facet promos (static)
	if ($('#facet-promos .static-promo').length > 0) {
		$('#facet-promos .static-promo a').click(function() {
			var title = 'Static promo';

			if ($(this).siblings('h2').length > 0) {
				title = $(this).siblings('h2').html();
			}

			registerAnalyticsEvent('Promos', urlFriendlyCategoryName, title);
		});
	}
}

/**
 * Initializes GA tracking for facets.
 */
function initFacetGATracking(ob) {
	if ($('.facet').length == 0) return;

	if (!ob) ob = $('.facet li a');

	ob.click(function() {
		var headerStr = $(this).parents('.facet-values').siblings('h2').attr('title');

		if (headerStr) {
			var val = '';

			if($(this).parents('.facet').hasClass('is-slider')) {
				val = $(this).siblings('.range-min').find('span').html() + '-' + $(this).siblings('.range-max').find('span').html();
			} else {
				val = $(this).html().replace(/^(.*)\(([0-9]+)\)/, "$1").replace(/<\/?span[^>]*>/g, "").trim();
			}

			var regName = 'Facets';

			if ($('#product-header').length > 0) {
				regName = 'Offer-Facets';
			}

			registerAnalyticsEvent(regName, urlFriendlyCategoryName, headerStr + ','+ val);
		}
	});
}

/*
 * This function gets the variable from the querystring and returns the value
 * which is requested, or if not found, returns 0
 */
function getQueryVar(varName) {
	var query = window.location.search.substring(1);
	var vars = query.split("&");
	for (var i=0;i<vars.length;i++) {
		var pair = vars[i].split("=");
		if (pair[0] == varName) {
			if (pair[1] == '') {
				return '0';
			}
			return pair[1];
		}
	}
	return '0';
}

function HashParams() {
	this.currentUrlHash		= '';
}

HashParams.prototype.getCurrentUrlHash = function () {
	return this.currentUrlHash;
};

HashParams.prototype.setCurrentUrlHash = function (param) {
	this.currentUrlHash = param;
	return this;
};

HashParams.prototype.scrollToAnchor = function () {
	var base = this;
	var anchor = base.getAnchor();
	if (anchor && $( 'a[name= ' + anchor + ']' ).offset()) {
		$('html, body').animate({
			scrollTop: $( 'a[name= ' + anchor + ']' ).offset().top
		}, 0 ,'jswing');
	} else {
		var param = base.getHashParams();
		if (param['customAnchor'] && param['customAnchor'] != '') {
			$('html, body').animate({
				scrollTop: $( 'a[name= ' + param['customAnchor'] + ']' ).offset().top
			}, 500 ,'jswing');
		}
	}
	return base;
};


HashParams.prototype.getAnchor = function () {
	return window.location.hash.replace(/^\#([^\!]*).*/,'$1');
};

HashParams.prototype.getHashParams = function () {
	var base = this;
	if (window.location.hash != base.getCurrentUrlHash() && window.location.hash) {
		base.setCurrentUrlHash(window.location.hash);
		var returnParams	= {};
		var hashParams		= [];
		var urlHash			= window.location.hash.replace(/\#.*?!/,'');
		hashParams			= urlHash.split('&');
		for (var param in hashParams) {
			var tmpArr = [];
			tmpArr = hashParams[param].split('=');
			returnParams[tmpArr[0]] = tmpArr[1];
		}
		return returnParams;
	}
	return false; // unchanged hash
};

HashParams.prototype.createHashParamLink = function (hashParams) {
	var link = '#' + this.getAnchor();
	for (var param in hashParams) {
		link += param + '=' + hashParams[param] + '&';
	}
	return link.replace(/\&$/,'');
};

function enableFeedbackForm() {
	$('#feedback .iframe').click( function() {
		var href = $(this).attr('href');

		if (href.indexOf('iframe=1') == -1) { // don't add again
			var url = '?';
			url += 'iframe=1&';
			url += escape('pagename='+$('body').attr('class'));
			url += '&url='+escape(document.location.href);
			url += '&useragent='+escape(navigator.userAgent);
			url += '&operatingsystem='+escape(navigator.platform);
			$(this).attr('href', href + url);
		}
		
		$('#feedback .content').toggle(150);
	});
	$('#feedback .iframe').fancybox({
		'centerOnScroll' : 'false',
		'hideOnOverlayClick' : 'false',
		'frameHeight' : 444,
		'width' : 760
	});
}

function logToJSErrorLog(options) {
	if (options.errorMessage) {
		this.ipAddress		= options.ipAddress		? options.ipAddress		: "127.0.0.1";
		this.errorMessage	= options.errorMessage;
		this.errorUrl		= options.errorUrl		? options.errorUrl		: document.location;
		this.lineNr			= options.lineNr		? options.lineNr		: -1;
		this.ipAddress		= options.ipAddress		? options.ipAddress		: "127.0.0.1";
		this.pageUrl		= options.pageUrl		? options.errorUrl		: document.location;
		this.referrer		= options.referrer		? options.referrer		: document.referrer;
		$.ajax({
			type: "GET",
			url: "/log/jserror/",
			data: ({
				type:'jsError',
				errorMessage: "ipAddress: \""+this.ipAddress+"\" | errorMessage: \""+this.errorMessage+"\" | errorUrl: \""+this.errorUrl+"\" | lineNr: \""+this.lineNr+"\" | pageUrl: \""+this.pageUrl+"\" | referrer: \""+this.referrer+"\""
			}),
			dataType: "text"
		});
	}
}

function getAjaxData(url, $tip) {
	$tip.html('<div class="small-spinner"></div>');
	$.ajax({
		url		: url,
		dataType: 'html',
		type: "GET",
		contentType: "text/html",
		success	: function(html) {
			$tip.html(html);
		}
	});

}
/*
 * Sometimes we want to use a fancybox without google see the url
 * That is where iseUseful come in
 */
function isUseful(a, url) {
	a.href=url;
	return true;
};

/*
 * Accordion which uses an extra bar above to move to specific accordion items
 */
function CgAccordion( el ) {
	this.accordionObj = el;
	this.accordionObj.accordion({
		header: 'a.header',
		autoheight: false
	});
	this.anchor = $('.shopletter a');
	this.anchorHeader = $('#shoplist a.header');
	var letter = '_nums';

	if (location.hash.match(/^#_[A-Z]$/)) {
		letter = location.hash.replace(/#/,'');
	} else {
	}
	this.pickLetter( $("#link_for" +  letter) );
	this.listener();
}

CgAccordion.prototype.pickLetter = function(el) {
	this.accordionObj.accordion('activate', '#_' +el.data('anchor-letter'));
	if (this.lastSelected) {
		this.lastSelected.removeClass('selected');
	}
	this.lastSelected = $('#link_for_'+ el.data('anchor-letter'));
	this.lastSelected.addClass('selected');
	setTimeout( function() {
		location.hash = '#_' +el.data('anchor-letter');
	}, 1000);
};

CgAccordion.prototype.listener = function() {
	var self = this;
	self.anchor.click( function() {
		self.pickLetter( $(this) );
	});
	self.anchorHeader.click( function() {
		self.pickLetter( $(this) );
	});
};

function getTooltipContent(url) {
	var ret = $.ajax({
		type: "GET",
		url: url,
		async:false
	}).responseText;
	return ret;
}

function getTranslationsForPasswordStrength() {
	var ret = $.ajax({
		type: "GET",
		url: "/ajax/getTranslationsForPasswordStrength/",
		async:false
	}).responseText;
	return $.parseJSON(ret);
}

/*******************************************************************************
 * PasswordStrength
 * Calculates the strength of a password
 ******************************************************************************/	
function PasswordStrength()  {
	var self = this;
}

PasswordStrength.prototype.getScore = function( password ) {
	var self = this;
	self.score = 0;

	if (password.length < 1)
		return self.score;
	
	self.score++;

	if (password.length < 3)
		return self.score;

	if (password.length >= 4)
		self.score++;
	if (password.length >= 12)
		self.score++;
	if (password.length >= 20)
		self.score++;
	if (password.match(/\d+/))
		self.score++;
	if ( password.match(/[a-z]/) && password.match(/[A-Z]/) )
		self.score++;
	if ( password.match(/.[!,@,#,$,%,^,&,*,?,_,~,-,�,(,)]/) )
		self.score++;
	
	return self.score > 5 ? 5 : self.score;
};

PasswordStrength.prototype.printScore = function(el) {
	var self = this;
	self.message = getTranslationsForPasswordStrength();

	var score = self.getScore( el.val() );
	var message = self.message['compare_password_strength_' + score];
	var pwdMeter = $('.password-strength-meter');
	var width = score * 12;
	
	if (!pwdMeter.length) {
		el.after('<div class="password-strength-meter"><div class="strength-' + score + '" style="width: ' + width + 'px"></div><span class="score">' + message + '</span></div>');
	} else {
		pwdMeter.find('div').attr('class', 'strength-' + score).animate({'width' : width}, 100).siblings('.score').html(message);
	}
};
