﻿/*

	Q8 - Kuwait Petroleum website
	JavaScript functions
	
	Author: Creuna Danmark A/S / www.creuna.dk
	Copyright: 2009, Creuna Danmark A/S. All rights resevered

-----------------------------------------------------------------------*/

var Q8 = {

    options:
	{
	    variable: 'value'
	},

    initialize: function () {
        this.Popup.initialize();
        this.Forms.initialize();
        this.FormValidator.initialize();
        this.Basket.initialize();
        this.Accordion.initialize();
        this.TimePicker.initialize();
        this.Slider.initialize();
        this.Tube.initialize();
        this.OilShop.initialize();
        this.CustomerCard.initialize();
        this.Products.initialize()
        if (jQuery.browser.msie && jQuery.browser.version < 7 && jQuery('.heatingSection').length) {
            this.IE6Popup.initialize();
        }
    },
    IE6Popup:
    {
        initialize: function () {
            var boxHTML = '<div id="noIE6"><div class="msgBox"><a href="#" class="close">Close</a><h2>Du har en ældre browser, som med fordel kan opdateres.</h2><p><a href="http://www.microsoft.com/danmark/windows/internet-explorer">Klik her</a> for at opdatere din browser.</p><p>Venlig hilsen Q8</p></div></div>';
            jQuery('body').append(boxHTML);
            jQuery('#noIE6 a.close').bind('click', function () {
                jQuery("#noIE6").fadeOut("slow");
            });
        }
    },
    Tube:
    {
        initialize: function () {
            jQuery(".tube").each(function () {
                Q8.Tube.setValue(jQuery(this), jQuery(this).children(".value").text());
            });

        },
        setValue: function (currTube, value) {
            additionalHTML = "<div class=\"top\"></div><div class=\"middle\"></div><div class=\"bottom\"></div><div class=\"light\"></div>";
            currTube.append(additionalHTML);

            //10% ... 90%
            var mediumLevelShiftX = -50;
            if (currTube.parents(".tubeBox").hasClass("greenTube")) {
                mediumLevelShiftX = -650;
            }
            var mediumLevelShiftY = 2;

            //91%, 92% ... 100%
            var topLevelShiftX = Array(-550, -500, -450, -400, -350, -300, -250, -200, -150, -100, -600);
            var topLevelShiftY = 0;
            if (currTube.parents(".tubeBox").hasClass("greenTube")) {
                topLevelShiftY = -41;
            }

            //0%, 1% ... 9%
            var bottomLevelShiftX = Array(-550, -500, -450, -400, -350, -300, -250, -200, -150, -100);
            var bottomLevelShiftY = -20;
            if (currTube.parents(".tubeBox").hasClass("greenTube")) {
                bottomLevelShiftY = -61;
            }

            var topLevelBox = currTube.find(".top");
            var mediumLevelBox = currTube.find(".middle");
            var bottomLevelBox = currTube.find(".bottom");

            if (value < 10) {
                currTube.addClass("low");
                bottomLevelBox.css("background-position", bottomLevelShiftX[value] + "px " + bottomLevelShiftY + "px");
                if (value == 9) {
                    mediumLevelBox.css("background-position", (mediumLevelShiftX + "px ") + "162px");
                }
            }
            else if (value < 92) {
                currTube.addClass("medium");
                mediumLevelBox.css("background-position", (mediumLevelShiftX + "px ") + (mediumLevelShiftY * (100 - value - 10) + "px"));
                if (value == 91) {
                    topLevelBox.css("background-position", (topLevelShiftX[1] + "px ") + topLevelShiftY + "px");
                }
            }
            else {
                currTube.addClass("high");
                topLevelBox.css("background-position", (topLevelShiftX[value - 90] + "px ") + topLevelShiftY + "px");
                if (value == 92) {
                    mediumLevelBox.css("background-position", (mediumLevelShiftX + "px ") + "-2px");
                }
            }
        }
    },
    Slider:
    {
        initialize: function () {
            jQuery(".slider").each(function () {
                Q8.Slider.sliderWork(jQuery(this));
            })
        },
        sliderWork: function (currSlider) {
            var rangeMax = 3;
            var currSliderBox = currSlider.parents(".sliderBox");
            if (currSliderBox.hasClass("four")) {
                rangeMax = 4;
            }
            Q8.Slider.generateLegend(currSliderBox, rangeMax);
            currSlider.slider({
                min: 1,
                max: rangeMax,
                step: 0.01,
                start: function (event, ui) {
                    Q8.Slider.move(currSliderBox, ui.value)
                },
                change: function (event, ui) {
                    Q8.Slider.endChanging(currSliderBox, ui, rangeMax);
                },
                slide: function (event, ui) {
                    Q8.Slider.move(currSliderBox, ui.value);
                }
            });
            currSlider.find("a").text("1");
            currSlider.find("a").hover(function () {
                Q8.Slider.move(currSliderBox, jQuery(this).text());
                jQuery(this).addClass("hovered");
            }, function () {
                //currSliderBox.children(".infoPopup").stop().animate({ "opacity": 0 }, 200, function() { jQuery(this).hide() });
                currSliderBox.children(".infoPopup").hide();
                jQuery(this).removeClass("hovered");
            });
        },
        generateLegend: function (currSliderBox, rangeMax) {
            var i = 0;
            var step = 100 / (rangeMax - 1);
            var scalesAmount = currSliderBox.find("ul.scale li").length - 1;

            currSliderBox.find("ul.scale li").each(function (n) {
                marginLeft = 0;
                if (n) {
                    marginLeft = jQuery(this).width() / 2;
                }
                if (scalesAmount == n) {
                    jQuery(this).css("right", 0);
                }
                else {
                    jQuery(this).css("left", (i++) * step + "%");
                }
                jQuery(this).css("margin-left", "-" + marginLeft + "px");
            })
            currSliderBox.find(".infoPopup").each(function (n) {
                jQuery(this).css("left", 100 / scalesAmount * n + "%");
            });

        },
        move: function (currSliderBox, currValue) {
            currValue = Math.round(currValue);
            currSliderBox.find("a").text(currValue);
            //currSliderBox.children(".infoPopup").stop().animate({ "opacity": 0 }, 200, function() { jQuery(this).hide() });
            //currSliderBox.children(".infoPopup:eq(" + (currValue - 1) + ")").stop().show().animate({ "opacity": 1 }, 200);
            currSliderBox.children(".infoPopup").hide();
            currSliderBox.children(".infoPopup:eq(" + (currValue - 1) + ")").show();

        },
        startChanging: function (currSliderBox, currValue) {
            //currSliderBox.children(".infoPopup").stop().show().animate({ "opacity": 1 }, 500);
        },
        endChanging: function (currSliderBox, handler, range) {
            var uiValue = Math.round(handler.value);
            var uiRange = 100 / (range - 1) * (uiValue - 1);
            handler.value = uiValue;
            currSliderBox.find("a").animate({ "left": uiRange + "%" }, 200);
            if (!currSliderBox.find("a.hovered").length) currSliderBox.children(".infoPopup").hide();
            if (window.onSliderValueChange) {
                setTimeout(window.onSliderValueChange, 100);
            }
        }

    },

    TimePicker:
    {
        initialize: function () {
            jQuery('.timefield input[type="text"]').each(function () {
                var timepickerBox = jQuery(this).parents(".txtInput", this).find('.timepicker', this);
                var txtInput = jQuery(this).parents(".txtInput", this).find('input[type="text"]', this);
                var lnkActivate = jQuery(this).parents(".txtInput", this).find('a.activate', this);

                lnkActivate.click(function () {
                    if (timepickerBox.is(":visible")) {
                        timepickerBox.hide();
                    }
                    else {
                        timepickerBox.show();
                    }
                    return false;

                });
                jQuery(this).blur(function () {
                    setTimeout(function () { timepickerBox.hide(); }, 100);
                });

                timepickerBox.find("a", this).click(function () {
                    txtInput.val(jQuery(this).text());
                    txtInput.focus();
                    timepickerBox.hide();
                    txtInput.blur();
                    return false;
                });
            })
        }
    },

    Accordion:
    {
        initialize: function () {
            if (jQuery(".productList").length) {
                var activeCategory = false;

                if (jQuery(".productList h2.opened").length) {
                    activeCategory = jQuery(".productList h2").index(jQuery(".productList h2.opened"));
                }
                jQuery(".productList").accordion({
                    header: 'h2',
                    collapsible: true,
                    active: activeCategory,
                    autoHeight: false,
                    change: function () {
                        jQuery(this).find('h2').blur();
                        window.location.hash = jQuery(this).find('h2[aria-expanded=true]').attr("id");
                    }
                });
            }
        }
    },

    Basket:
    {
        initialize: function () {
            var basket = jQuery('#shopBasket');
            if (!basket.length) {
                return;
            }
            var topPosBasket = basket.offset();
            topPosBasket = topPosBasket.top;

            if (jQuery.browser.msie && jQuery.browser.version <= "7") {
                topPosColumn = jQuery('#related').offset();
                topPosColumn = topPosColumn.top;
                basket.css({
                    position: 'relative'
                });

                jQuery(window).scroll(function () {
                    var topPosDoc = jQuery(window).scrollTop();
                    var topPosDoc = topPosDoc - topPosColumn;
                    if (topPosDoc > topPosBasket) {
                        basket.css({
                            position: 'absolute',
                            top: topPosDoc + 'px'
                        });
                    }
                    else {
                        basket.css({
                            "top": "0",
                            "position": "relative"
                        });
                    }
                });

            }
            else {
                jQuery(window).scroll(function () {
                    var topPosDoc = jQuery(window).scrollTop();
                    if (topPosDoc > topPosBasket) {
                        basket.css({
                            position: 'fixed',
                            top: 0
                        });
                    }
                    else {
                        basket.css('position', 'relative');
                    }
                });
            }
        }
    },

    Forms:
	{
	    initialize: function () {
	        Q8.Forms.hints();
	    },
	    hints: function () {
	        var lblTitles = jQuery(".txtInput label");
	        var txtInputs = jQuery(".txtInput input[type='text']");

	        lblTitles.click(function () {
	            jQuery(this).hide();
	            jQuery(this).parents(".txtInput").find("input").focus();
	        });
	        txtInputs.blur(function () {
	            if (!jQuery.trim(jQuery(this).val())) {
	                jQuery(this).parents(".txtInput").find("label").show();
	            }
	        });
	        txtInputs.focus(function () {
	            jQuery(this).parents(".txtInput").find("label").hide();
	        });
	        txtInputs.each(function () {
	            if (jQuery.trim(jQuery(this).val())) {
	                jQuery(this).parents(".txtInput").find("label").hide();
	            }
	        });
	    }

	},

    Popup:
	{
	    initialize: function () {
	        var elements = $('a.popup');

	        if (elements.length) {
	            elements.each(function () {
	                $(this).unbind('click').click(function (event) {
	                    Q8.Popup.open(this);

	                    return false;
	                });
	            });
	        }
	    },

	    open: function (element) {
	        var href = element.href || element;
	        var query = href.replace(/^[^\?]+\??/, '');
	        var params = Q8.parseQuery(query);

	        var height = params['height'];
	        var width = params['width'];

	        var left = (screen.width) ? (screen.width - width) / 2 : 100;
	        var top = (screen.height) ? (screen.height - height) / 2 : 100;

	        window.open(href, params['name'], 'height=' + height + ',width=' + width + ', top=' + top + ', left=' + left + ', toolbar=no, status=no, resizable=yes, scrollbars=1');
	    }
	},

    parseQuery: function (query) {
        var params = {};
        if (!query) { return params; }
        var pairs = query.split(/[;&]/);
        var length = pairs.length;
        for (var i = 0; i < length; i++) {
            var keyVal = pairs[i].split('=');
            if (!keyVal || keyVal.length != 2) { continue; }

            var key = unescape(keyVal[0]);
            var val = keyVal[1];
            val = val.replace(/\+/g, ' ');
            params[key] = val;
        }

        return params;
    },
    submit: function (event, target) {
        // Submit form if keyCode is "enter"
        if (event.keyCode == 13 && !(event.srcElement && (event.srcElement.tagName.toLowerCase() == "textarea"))) {
            var defaultButton = document.getElementById(target);

            if (defaultButton && typeof (defaultButton.click) != "undefined") {
                defaultButton.click();
                event.cancelBubble = true;

                if (event.stopPropagation) event.stopPropagation();
                return false;
            }
        }
        return true;
    },
    timePickerWork: function (timepicker) {

    },

    Utils: {

        toggleRelevantValidators: function (selector, enable) {
            var $validators = $(selector)
                .find('*[id*=_uiRfv], *[id*=_uiRev], *[id*=_uiCv]')
                .each(function () {
                    var validator = eval($(this).attr('id'));
                    validator.enabled = enable;
                });
            if (!enable) {
                $validators.hide();
            }
        },

        fireAllValidators: function (selector) {
            var $validators = $(selector)
                .find('*[id*=_uiRfv], *[id*=_uiRev], *[id*=_uiCv]')
                .each(function () {
                    ValidatorValidate($(this).get(0));
                });
        } //,

        //      Hmn a function to find validators associated with input ... so validators with controltovalidate == "the_id_of_the_input" 
        //      and / or validators that end with the same string as the input field ... that requires us to follow code conventions!!!
        //
        //          fireAssociatedValidators: function (selector) {
        //            var idEndsWith = $(selector).attr('id').split('_').pop();
        //			idEndsWith = idEndsWith.replace(/^uiCv/g, 'uiHdn');
        //			args.IsValid = $('input[id$=' + idEndsWith + ']').val() === 'true';
        //
        //            
        //            .each(function () {
        //                ValidatorValidate($(this).get(0));
        //            });
        //        }
    },

    Products:
	{
	    initialize: function () {
	        this.navigationDropdown('#content div.productCategory select.navigationDropdown');
	    },

	    navigationDropdown: function (selector) {
	        var $selector = $(selector);
	        if (!$selector.length) {
	            return;
	        }

	        $selector.change(function () {
	            $(this).next('.buttonAjaxLoader').show();
	            window.location.href = $(this).val();
	            return false;
	        });
	    }
	},

    CustomerCard:
	{
	    initialize: function () {
	        this.disableNext.initialize($('.formGradient span.disableNext'), $('.formGradient div.disableNext'));
	        this.toggleSlide($('#related .toggleSlide, #content div.productCategory a.toggleSlide'));
	        this.initAddressSuggestor('.streetSuggestionContainer');
	        this.initCityFromZipCodeLookup('.getCityContainer');
	        this.fixAutoCompleteInputs('div.customerFlow input[type=text]');
	        this.liveNumberFormatting('input.livenumformat');
	    },

	    fixAutoCompleteInputs: function (selector) {
	        var $selector = $(selector);
	        if (!$selector.length) {
	            return;
	        }

	        // Fix autocomplete by faking a 'keyup' event when change happens
	        $selector
				.change(function () {
				    $(this).trigger('keyup');
				})
	    },

	    /**
	    * Disable elements when radiobutton is checked
	    * @param	element	selectorTrigger	The element who triggers the event
	    * @param	element	selectorContent	The element who contains the input elements who will be disabled
	    */
	    disableNext:
		{
		    initialize: function (selectorTrigger, selectorContent) {
		        var $selectorTrigger = $(selectorTrigger),
					$selectorContent = $(selectorContent);

		        if (!$selectorTrigger.length || !$selectorContent.length) {
		            return;
		        }

		        this.bindDisabler($selectorContent);
		        this.bindTrigger($selectorTrigger);

		        // Trigger when load
		        $selectorTrigger.find('input[type=radio]:checked, input[type=checkbox]:checked').trigger('inputIsChecked');
		    },

		    bindDisabler: function ($selectorContent) {
		        $selectorContent.find('input').bind('disabled', function (e, attribute) {
		            var $input = $(this),
						$container = $input.parent(),
						className = '';

		            $input.attr('disabled', attribute);

		            switch ($input.attr('type')) {
		                case 'text':
		                    $container = $container.parent();
		                    className = 'formfieldRoundDisabled';
		                    break;
		                case 'radio': className = 'radiobuttonDisabled'; break;
		                case 'checkbox': className = 'checkboxButtonDisabled'; break;
		            }

		            if (attribute)
		                $container.addClass(className);
		            else
		                $container.removeClass(className);
		        });
		    },

		    bindTrigger: function ($selectorTrigger) {
		        $selectorTrigger.find('input[type=radio], input[type=checkbox]').bind('inputIsChecked', function () {
		            var $input = $(this),
						$span = $input.parent(),
						$disablers = $span.parent().find('div.disableNext'),
						$nextDisabler = $span.next().next('div.disableNext');

		            if ($input.attr('type') == 'checkbox') {
		                if ($input.is(':checked')) {
		                    $disablers
								.addClass('disableNextEnabled')
								.find('input')
									.each(function () {
									    var $this = $(this);

									    if ($this.is(':checked')) {
									        $this.attr('checked', false);
									        Q8.OilShop.customCheckboxClick($this);
									        $this.parent().removeClass('checkboxButtonHover');
									    }
									})
									.trigger('disabled', true);

		                    Q8.Utils.toggleRelevantValidators($disablers, false);
		                }
		                else {
		                    $disablers
								.removeClass('disableNextEnabled')
								.find('input').trigger('disabled', false);

		                    Q8.Utils.toggleRelevantValidators($nextDisabler, true);
		                }
		            }
		            else {
		                $disablers
							.addClass('disableNextEnabled')
							.find('input').trigger('disabled', true);

		                Q8.Utils.toggleRelevantValidators($disablers, false);

		                $nextDisabler
							.removeClass('disableNextEnabled')
							.find('input').trigger('disabled', false);

		                Q8.Utils.toggleRelevantValidators($nextDisabler, true);
		            }
		        });
		    }
		},

	    initAddressSuggestor: function (containersSelector) {
	        $(containersSelector)
				.each(function () {

				    var $container = $(this);

				    var $street = $container.find(".street input");
				    var $streetNumber = $container.find(".streetNumber input");
				    var $zipCode = $container.find(".zipCode input");

				    if ($street.length === 0 || $streetNumber.length === 0) { return; } // No streets and street numbers in this $container, so just skip it

				    var $addressContainer = $container.find("span.addressSuggestions");
				    var $isPerfectMatch = $container.find("input[id$='PerfectMatch']");

				    // Remove validation error messages
				    var $errorMessage = $street.closest(".formSection").find("span.error").hide();
				    var $ajaxLoader = $container.find("img.streetSuggestionAjaxLoader").hide();

				    var helpers = {

				        addressSuggestionClickHandler: function (e) {
				            // when a pre-fetched address is selected, fill out the form with the selected value, and hide suggestion list
				            var $elm = $(this);

				            // fill in street name with selected value
				            var street = $elm.attr("street");
				            $street.val(street);

				            // hide suggestions
				            $isPerfectMatch.val(true);
				            $addressContainer.hide();

				            // remove validation error message
				            $errorMessage.hide();

				            e.preventDefault();
				        },

				        blurHandler: function (e) {
				            // Onblur, lookup available addresses that match the input values, if input is valid

				            var street = $.trim($street.tooltipNormalizedVal());
				            var streetNumber = $.trim($streetNumber.tooltipNormalizedVal());
				            var zipCode = $.trim($zipCode.tooltipNormalizedVal());

				            // Test if values actually have changed since last request
				            if (street == $street.data("oldvalue") && streetNumber == $streetNumber.data("oldvalue") && zipCode == $zipCode.data("oldvalue")) {
				                return; // No change
				            }

				            // Save values for later comparison
				            $street.data("oldvalue", street);
				            $streetNumber.data("oldvalue", streetNumber);
				            $zipCode.data("oldvalue", zipCode);

				            // Validate new values
				            if (street === "" || streetNumber === "" || zipCode === "") {
				                return; // All three textboxes must be filled in
				            }

				            // Valid and changed - go ahead: lookup address to suggest perfect matches

				            var successHandler = function (result) {
				                $('input[id$=_uiBtnContinue]').removeAttr('disabled');
				                helpers.hideAjaxLoader();

				                // expecting json structure, so we unserialize
				                result.d = $.parseJSON(result.d);

				                if (result.d.PerfectMatch) {
				                    $isPerfectMatch.val(true);
				                    return;
				                }

				                var html = [];
				                for (var n = 0; n < result.d.Addresses.length; n++) {
				                    if (result.d.Addresses[n].StreetNumberMax && result.d.Addresses[n].StreetNumberMin) {
				                        html.push('<a href="#" street="' + result.d.Addresses[n].Street + '" streetnumbermin="' + result.d.Addresses[n].StreetNumberMin + '" streetnumbermax="' + result.d.Addresses[n].StreetNumberMax + '">' + result.d.Addresses[n].Street + '</a>');
				                    } else if (result.d.Addresses[n].StreetNumberMin && result.d.Addresses[n].StreetNumberMax) {
				                        html.push('<a href="#" street="' + result.d.Addresses[n].Street + '" streetnumber="?">' + result.d.Addresses[n].Street + '</a>');
				                    }
				                }
				                html = html.join(", ");

				                $addressContainer.find("span.links").html(html);
				                $addressContainer.find("a").click(helpers.addressSuggestionClickHandler);

				                if (result.d.Addresses.length == 0) {
				                    $container.find(".noStreetsMatchingError").show();
				                } else {
				                    $addressContainer.show();
				                }
				            }

				            var errorHandler = function (jqXHR, textStatus, errorThrown) {
				                $('input[id$=_uiBtnContinue]').removeAttr('disabled');
				                helpers.hideAjaxLoader();
				                // Clear old values for so we will force another trye later
				                $street.data("oldvalue", "");
				                $streetNumber.data("oldvalue", "");
				                $zipCode.data("oldvalue", "");
				                alert("Der er sket en kommunikationsfejl. Prøv igen, eller kontakt venligst Q8 om problemet");
				            }

				            $errorMessage.hide();
				            $isPerfectMatch.val(false);
				            helpers.showAjaxLoader();
				            $('input[id$=_uiBtnContinue]').attr('disabled', 'disabled');
				            LookupAddress(successHandler, errorHandler, street, streetNumber, zipCode || '');
				        },

				        showAjaxLoader: function () {
				            // show ajax loader below street name/number
				            $ajaxLoader.show();
				            $addressContainer.hide();
				            $errorMessage.hide();
				        },

				        hideAjaxLoader: function () {
				            $ajaxLoader.hide();
				        }
				    };

				    $addressContainer.find("a").click(helpers.addressSuggestionClickHandler);

				    // add focus/blur handlers for the COMBINED elements (see plugin at end of q8.js)
				    $street.add($streetNumber).add($zipCode).combine()
						.blur(helpers.blurHandler)
						.blur();
				});
	    },

	    initCityFromZipCodeLookup: function (containersSelector) {
	        $(containersSelector)
                .each(function () {
                    var $container = $(this);
                    var $ajaxLoader = $container.find("img.ajaxLoader");
                    var $zipCode = $container.find(".zipCode input");
                    var $city = $container.find(".city input");
                    var $uiRfvCity = $container.find("span[id$='" + $city.attr("id").split("_").pop().replace("uiTxt", "uiRfv") + "']");

                    $zipCode.blur(function () {

                        $uiRfvCity.hide();

                        function onSuccess(result) {
                            $ajaxLoader.hide();
                            $('input[id$=_uiBtnContinue]').removeAttr('disabled');
                            if (result.d.indexOf('success|') === 0) {
                                $city.val(result.d.substring(8));
                            }
                            else {
                                $city.val('');
                                var errormessage = result.d.substring(6);
                                $uiRfvCity.attr("errormessage", errormessage).text(errormessage);
                                ValidatorValidate($uiRfvCity.get(0));
                            }
                        }

                        function onFailure(jqXHR, textStatus, errorThrown) {
                            $ajaxLoader.hide();
                            $('input[id$=_uiBtnContinue]').removeAttr('disabled');
                            var errormessage = 'Der opstod en fejl, da bynavnet skulle skulle slåes op.';
                            $uiRfvCity.attr("errormessage", errormessage).text(errormessage);
                            ValidatorValidate($uiRfvCity.get(0));
                        }

                        $('input[id$=_uiBtnContinue]').attr('disabled', 'disabled');
                        $ajaxLoader.show();
                        GetCityFromZipCode(onSuccess, onFailure, $(this).val());

                    });
                });
	    },

	    toggleSlide: function (selector) {
	        var $selector = $(selector);
	        if (!$selector.length) {
	            return;
	        }

	        $selector.click(function (e) {
	            var $next = $(this).next();
	            if (!$next.is(':animated')) {
	                $(this).toggleClass('selected');
	                $next.slideToggle(280);
	            }

	            e.preventDefault();
	            return false;
	        });
	    },

	    liveNumberFormatting: function (selector) {
	        var $selector = $(selector);
	        if (!$selector.length) {
	            return;
	        }

	        //New formatter. Not implemented yet
	        //$(selector).autoNumeric( {aSep: '.', aDec: ','} );

	        $(selector)
                .bind('keyup', function (e) {
                    var key = e.which;
                    if ((key > 35 && key < 41) || key == 16) // navigation arrows
                    {
                        return;
                    }

                    var $this = $(this);
                    var val = $this.val();
                    var add = '';

                    if (val.match(/,$/)) {
                        add = ',';
                    }
                    else if (val.match(/,0$/)) {
                        add = ',0';
                    }

                    $this.parseNumber({ format: "#,###.##", locale: "dk" });
                    $this.formatNumber({ format: "#,###.##", locale: "dk" });
                    $this.val($this.val() + add);
                });
	    },

	    validateAtLeastOnePaymentCard: function (sender, args) {
	        args.IsValid = $(sender).parent().find("input[type='checkbox']:checked").length > 0;
	    },

	    validateRadioButtonGroupSelected: function (sender, args) {
	        args.IsValid = $(sender).parent().find("input[type='radio']:checked").length > 0;
	    },

	    validateCprFields: function (sender, args) {

	        var errorMessages = Q8.CustomerCard.cprFieldsErrorMessages;

	        args.IsValid = false;

	        var $formSection = $(sender).closest('.formSection');

	        var birthDay = $formSection.find('.birthNumber1 input');
	        var birthNum = $formSection.find('.birthNumber2 input');

	        birthDay.val($.trim(birthDay.val()));
	        birthNum.val($.trim(birthNum.val()));

	        if (birthDay.val() == '' || birthNum.val() == '') {
	            $(sender).attr("errormessage", errorMessages.fullCprRequired).text(errorMessages.fullCprRequired);
	            return;
	        }

	        if (!birthDay.val().match(/^(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])\d\d$/g)) {
	            $(sender).attr("errormessage", errorMessages.birthDayNotValid).text(errorMessages.birthDayNotValid);
	            return;
	        }

	        if (!birthNum.val().match(/^\d{4}$/g)) {
	            $(sender).attr("errormessage", errorMessages.birthNumNotValid).text(errorMessages.birthNumNotValid);
	            return;
	        }

	        args.IsValid = true;
	    },

	    CprFieldsErrorMessages:
	    {
	        fullCprRequired: "Angiv venligst indehavers fulde CPR-nummer",
	        birthDayNotValid: "Fødselsdatoen er ikke gyldig",
	        birthNumNotValid: "Løbenummeret er ikke gyldigt"
	    } // Can be overwritten with translations by js on the page using the validation
	},

    OilShop:
    {
        initialize: function () {
            var $form = $('form');
            if ($form.length) {
                Q8.RemoveDefaultInputValue.init($form, false);
            }

            this.tooltip('div.formGradient span.tooltip');
            this.customRadioButtons('div.oilFlow span.radiobutton input[type=radio], div.formGradient span.radiobutton input[type=radio]');
            this.customCheckboxButtons('div.formGradient span.checkboxButton input[type=checkbox], div.serviceCheckboxes span.checkboxButton input[type=checkbox]');
            this.bindOilflowBoxEvents('#oilFlowBoxWrapper');
            this.loginBox('div[id$=_uiPnlLoginWrapper]');
            this.initAutoscrollValidate('.autoscrollValidate');
            this.initAddressSuggestor();
            this.setupPejlingPopupValidator();
            this.setupFancybox('a.openFancybox');
            this.PriceCalculator.initialize();
        },

        config: {
            pejling: {
                'square':
                {
                    1200: 9.8128,
                    1800: 12.251,
                    3900: 31.206,
                    5000: 40.6,
                    6000: 40
                },
                'oval':
                {
                    1200: 9.4067,
                    1800: 13.072
                },
                'cylinder':
                {
                    1500: 15.219,
                    2500: 25.114,
                    4000: 39.965,
                    5900: 47.451
                }
            },

            pejlingCalcFix: {
                'square':
                {
                    1200: -0.0072,
                    1800: 0.0985,
                    3900: -0.25,
                    5000: -75,
                    6000: 0
                },
                'oval':
                {
                    1200: -49.433,
                    1800: -80.365
                },
                'cylinder':
                {
                    1500: -118.03,
                    2500: -194.29,
                    4000: -299.53,
                    5900: -475.14
                }
            }
        },

        isLoggedIn: function () {
            // if login box is there, the user is not yet logged in
            return $(".oilLogin .loginWrapper").length == 0;
        },

        getLandingPageMainButton: function () {
            return $("#oilLandingPage .submit input");
        },

        updateAvailableTankTypes: function (tankSizeInLiters, preselect) {
            // disable tank types radio buttons that do not match selected tank size
            var enabledRadioButtons = [];
            var cssClass = { "square": "disablerSquare", "oval": "disablerOval", "cylinder": "disablerCylinder" };
            for (var n in Q8.OilShop.config.pejling) {
                (function (type, enabled) {
                    if (!cssClass[type]) {
                        return; // type not valid
                    }

                    var $elm = $("#numberOfLitersWindow .chooseTankSize ." + cssClass[type]);
                    if (enabled || tankSizeInLiters == 0) {
                        $elm.hide(); // hide disabler, i.e. ENABLE the type
                        enabledRadioButtons.push(type);
                    } else {
                        $elm.show(); // show disabler, i.e. DISABLE the type
                    }
                })(n, Q8.OilShop.config.pejling[n][tankSizeInLiters]);
            }

            if (preselect) {
                // uncheck all radio buttons
                for (var n in Q8.OilShop.config.pejling) {
                    //$("#" + n).attr("checked", "");
                }
                // pre-select first radio button available
                $("#" + enabledRadioButtons[0]).trigger("click");  //attr("checked", "checked");
            }
        },

        isValidAddress: true,

        validateAddress: function (sender, args, skipSelectedAddress) {
            // this method is called both on onblur for both input elements, and on the form onsubmit

            args.IsValid = false;

            // if the user has not selected a value from the list (a VALID addres)
            if (!skipSelectedAddress && !Q8.OilShop.isValidAddress) {
                // not valid (yet)
                return;
            }

            var $street = $(".oilFlowStepOrder .formGradient .street input");
            var $streetNumber = $(".oilFlowStepOrder .formGradient .streetNumber input");

            var street = $.trim($street.tooltipNormalizedVal());
            var streetNumber = $.trim($streetNumber.tooltipNormalizedVal());

            if (!streetNumber.match(/^\d+/)) {
                // street number does not start with a number
                return;
            }

            if (street == "" || streetNumber == "") {
                // if any of the fields are not filled out, validation fails
                return;
            }

            // both filled out all is good (=valid)
            args.IsValid = true;
        },

        initAddressSuggestor: function () {
            var $street = $(".oilFlowStepOrder .formGradient .street input");
            var $streetNumber = $(".oilFlowStepOrder .formGradient .streetNumber input");
            var $zipCode = $(".oilFlowStepOrder .formGradient .zipCode input");

            if ($street.length == 0 || $streetNumber.length == 0) {
                // no streets and street numbers on this page, so just skip it
                return;
            }

            $("span.addressSuggestions a").live("click", function (e) {
                // when a pre-fetched address is selected, fill out the form with the selected value, and hide suggestion list
                var $elm = $(this);

                // fill in steet name with selected value
                var street = $elm.attr("street");
                $street.val(street);

                var streetNumberMin = parseInt($elm.attr("streetnumbermin"));
                var streetNumberMax = parseInt($elm.attr("streetnumbermax"));

                var inputStreetNumber = parseInt($streetNumber.val());

                if (inputStreetNumber < streetNumberMin || inputStreetNumber > streetNumberMax) {
                    // number suggested by user is not within the range of the selected street
                    $("span.streetNumberError").show();
                    $streetNumber.get(0).focus();
                    $streetNumber.get(0).select();

                } else {
                    // focus on next input element
                    $street.closest(".formSection").next().find("input").get(0).focus();
                }

                // hide suggestions
                Q8.OilShop.isValidAddress = true;
                $elm.closest("span.addressSuggestions").hide();

                // remove validation error message
                $errorMessage = $street.closest(".formSection").find("span.error:first");
                $errorMessage.hide();

                e.preventDefault();
            });

            var helpers = {
                focusHandler: function () {
                    // store old values for later comparison
                    $street.data("oldvalue", $street.tooltipNormalizedVal());
                    $streetNumber.data("oldvalue", $streetNumber.tooltipNormalizedVal());
                    $zipCode.data("oldvalue", $zipCode.tooltipNormalizedVal());
                },

                blurHandler: function (e) {
                    // onblur, lookup available addresses that match the input values, if input is valid

                    // test if values actually have changed since last request
                    var street = $street.tooltipNormalizedVal();
                    var streetNumber = $streetNumber.tooltipNormalizedVal();
                    var zipCode = $zipCode.tooltipNormalizedVal();
                    if (street == $street.data("oldvalue") &&
                        streetNumber == $streetNumber.data("oldvalue") &&
                        (typeof (zipCode) === 'undefined' || zipCode == $zipCode.data("oldvalue"))) {
                        // no change
                        return;
                    }

                    // save old values for later comparison
                    $street.data("oldvalue", street);
                    $streetNumber.data("oldvalue", streetNumber);
                    $zipCode.data("oldvalue", zipCode);

                    // validate new values
                    var $addressContainer = $("span.addressSuggestions");
                    var $noStreetsMatchingError = $(".noStreetsMatchingError");
                    var $errorMessage = $street.closest(".formSection").find("span.error");

                    // find and show error message, by pushing for an extra validation
                    var args = {};
                    Q8.OilShop.validateAddress($errorMessage, args, true);
                    if (!args.IsValid) {
                        $errorMessage.show();
                        $addressContainer.hide();
                        return;
                    }

                    // valid and changed - go ahead: lookup address to suggest perfect matches

                    var successHandler = function (result) {
                        helpers.hideAjaxLoader();

                        // expecting json structure, so we unserialize
                        result.d = $.parseJSON(result.d);

                        if (result.d.PerfectMatch) {
                            // address is valid, do nothing (just mark it as valid)
                            Q8.OilShop.isValidAddress = true;
                            return;
                        }

                        var html = [];
                        for (var n = 0; n < result.d.Addresses.length; n++) {
                            if (result.d.Addresses[n].StreetNumberMax && result.d.Addresses[n].StreetNumberMin) {
                                html.push('<a href="#" street="' + result.d.Addresses[n].Street + '" streetnumbermin="' + result.d.Addresses[n].StreetNumberMin + '" streetnumbermax="' + result.d.Addresses[n].StreetNumberMax + '">' + result.d.Addresses[n].Street + '</a>');
                            } else if (result.d.Addresses[n].StreetNumberMin && result.d.Addresses[n].StreetNumberMax) {
                                html.push('<a href="#" street="' + result.d.Addresses[n].Street + '" streetnumber="?">' + result.d.Addresses[n].Street + '</a>');
                            }
                        }
                        html = html.join(", ");
                        $addressContainer.find("span.links").html(html);

                        if (result.d.Addresses.length == 0) {
                            $noStreetsMatchingError.show();
                        } else {
                            $addressContainer.show();
                        }
                    }
                    var errorHandler = function (jqXHR, textStatus, errorThrown) {
                        helpers.hideAjaxLoader();
                        alert("Der er sket en kommunikationsfejl. Prøv igen, eller kontakt venligst Q8 om problemet");
                    }

                    $errorMessage.hide();
                    Q8.OilShop.isValidAddress = false;
                    helpers.showAjaxLoader();
                    LookupAddress(successHandler, errorHandler, street, streetNumber, zipCode || '');
                },

                showAjaxLoader: function () {
                    // show ajax loader below street name/number
                    $("img.streetSuggestionAjaxLoader").show();
                    $("span.addressSuggestions").hide();
                    $(".noStreetsMatchingError").hide();
                },

                hideAjaxLoader: function () {
                    $("img.streetSuggestionAjaxLoader").hide();
                }
            };

            // add focus/blur handlers for the COMBINED elements (see plugin at end of this file)
            $street.add($streetNumber).add($zipCode).combine()
                .blur(helpers.blurHandler)
                .focus(helpers.focusHandler);
        },

        inititalizedFancyboxWindows: {},

        initFancyboxWindows: function ($inner) {
            var isAlreadyInitialized = Q8.OilShop.inititalizedFancyboxWindows[$inner.attr('id')];

            switch ($inner.attr('id')) {
                case 'numberOfLitersWindow':
                    var $pejlingElement = $('input#pejling', $inner),
                        $tankSize = $('div.oilFlow .flow:first select'),
                        $formList = $('dl', $inner),
                        $submitButton = $inner.find('input[type=submit]'),
                        $typeError = $inner.find('p.typeError'),
                        $resultError = $inner.find('p.resultError'),
                        $maxError = $inner.find('p.maxError'),
                        $minError = $inner.find('p.minError');

                    // add tank size to fancybox popup if it has not already been added
                    if ($formList.find('select#tankSize').length == 0) {

                        $formList
                            .find('dt.tankSize, dd.tankSize').remove().end()
                            .prepend('<dt class="tankSize">Tankstørrelse</dt><dd class="tankSize"></dd>')
                            .find('dd:first')
                            .append($tankSize.val());
                    }

                    var isValid = true;
                    var result = 0;

                    var tankSizeInLiters = parseInt($tankSize.val(), 10);
                    Q8.OilShop.updateAvailableTankTypes(tankSizeInLiters, true);

                    if (isAlreadyInitialized) {
                        return;
                    }

                    $submitButton.bind('calculate', function (event) {
                        event.preventDefault();

                        // Look for errors
                        isValid = true;

                        var ddTankSize = $inner.find('dl dd.tankSize');
                        ddTankSize.next('dd.error').remove();
                        if ($tankSize.val() < 1) {
                            ddTankSize.after('<dd class="error"><span class="error">' + $('div.oilFlow .flow:first .errorMessage').text() + '</span></dd>');
                            isValid = false;
                        }

                        var ddPejling = $formList.find('dd.pejling');
                        ddPejling.next('dd.error').remove();
                        if ($pejlingElement.val() <= 0) {
                            ddPejling.after('<dd class="error"><span class="error">Du skal angive en pejling</span></dd>');
                            isValid = false;
                        }

                        var tankSizeInLiters = parseInt($tankSize.val(), 10);
                        Q8.OilShop.updateAvailableTankTypes(tankSizeInLiters);

                        // hide global errors
                        $typeError.hide();
                        $resultError.hide();
                        $maxError.hide();
                        $minError.hide();

                        if (!isValid) {
                            return false;
                        }

                        // Calculate pejling
                        var tankType = $inner.find('p.chooseTankSize input:checked').attr('id');
                        if (Q8.OilShop.config.pejling[tankType][tankSizeInLiters]) {
                            result = $pejlingElement.val() * Q8.OilShop.config.pejling[tankType][tankSizeInLiters];
                            var pejlingFix = Q8.OilShop.config.pejlingCalcFix[tankType][$tankSize.val()];
                            result = parseInt($tankSize.val() - (result + pejlingFix));

                            if (isNaN(result)) {
                                $resultError.show();
                                isValid = false;
                            }
                            else if (result < 0) {
                                $maxError.show();
                                isValid = false;
                            }
                            else if (result > $tankSize.val()) {
                                $minError.show();
                                isValid = false;
                            }
                        } else {
                            $typeError.show();
                            isValid = false;
                        }

                        if (!isValid) {
                            result = '?';
                        }

                        // Append result
                        $formList
                            .find('dt.result, dd.result').remove().end()
                            .append('<dt class="result">Du har plads til</dt><dd class="result">' + result + ' liter</dd>');

                        var $updateButton = $(this).data('clicked', true).parentsUntil('.lightboxWindow');
                        if (isValid) {
                            $(this).val('Opdater beregning');
                            $updateButton.show();
                        }
                        else {
                            $updateButton.hide();
                            return false;
                        }
                    });

                    $submitButton.click(function () {
                        if ($submitButton.data('clicked') && isValid == true) {
                            // Append result to oil flow
                            $('div.oilFlow .flow input[type = "text"]:first').val(result);
                            $.fancybox.close();
                        }
                        else {
                            $(this).trigger('calculate');
                        }

                        return false;
                    });

                    $inner
                        .find('select, input[type=text]').bind('keyup change click', function () {
                            if ($submitButton.data('clicked'))
                                $submitButton.trigger('calculate');
                        }).end()
                        .find('span.radiobutton').bind('click', function () {
                            if ($submitButton.data('clicked'))
                                $submitButton.trigger('calculate');
                        });

                    break;

                case 'zipCodeLoginWindow':
                    var helpers = {
                        doOriginalPostBack: function () {
                            // submit original form through main button
                            var $calculateButton = Q8.OilShop.getLandingPageMainButton();

                            // simulate click on main button
                            $calculateButton.trigger("click", { source: "zipLogin" });
                        },

                        showErrorMessage: function ($errorMessageContainer, text) {
                            $errorMessageContainer.html(text);
                            if (text) {
                                $errorMessageContainer.show();
                            } else {
                                $errorMessageContainer.hide();
                            }
                        },

                        createSuccessHandler: function ($errorContainer) {
                            $button = $errorContainer.closest("div").find("input[type=submit]");
                            helpers.showAjaxLoader($button);
                            return function (result) {
                                if (result.d.indexOf('error|') === 0) {
                                    // The zipcode was not valid or there was an error calling the web service
                                    helpers.showErrorMessage($errorContainer, result.d.substring(6));
                                    helpers.hideAjaxLoader($button);
                                } else {
                                    helpers.doOriginalPostBack();
                                    // do NOT hide ajax loader, as page will post-back automatically
                                }
                            }
                        },

                        createErrorHandler: function ($errorContainer) {
                            return function (jqXHR, textStatus, errorThrown) {
                                helpers.showErrorMessage($errorContainer, "Der er desværre sket en kommunikationsfejl. Prøv igen, eller kontakt venligst Q8 om problemet");
                                $button = $errorContainer.closest("div").find("input[type=submit]");
                                helpers.hideAjaxLoader($button);
                            }
                        },

                        initSubmit: function (e) {
                            helpers.showErrorMessage($errorContainerZipCode, "");
                            helpers.showErrorMessage($errorContainerLogin, "");
                            e.stopImmediatePropagation(); // preventDefault is not enough
                        },

                        showAjaxLoader: function ($button) {
                            isInProgress = true;

                            // show ajax loader next to button
                            $wrapper = $button.closest(".buttonWrapper");
                            $wrapper.prepend('<img class="buttonAjaxLoader" src="/gfx/Q8/ajax-loader-circle.gif" width="16" height="16" alt="Vent venligst..." />');
                        },

                        hideAjaxLoader: function ($button) {
                            isInProgress = false;

                            $wrapper = $button.closest(".buttonWrapper");
                            $wrapper.find(".buttonAjaxLoader").remove();
                        }
                    }

                    $errorContainerZipCode = $("#zipCodeLoginWindow .enterZipCode .errorMessage span").first();
                    $errorContainerLogin = $("#zipCodeLoginWindow .enterCredentials span.error").first();
                    // save sitecore translated text for later validation error message
                    if (!$errorContainerLogin.attr("originalHtml")) {
                        $errorContainerLogin.attr("originalHtml", $errorContainerLogin.html());
                    }

                    // any ajax call or post-back currently in progress?
                    var isInProgress = false;

                    // reset error message output
                    helpers.showErrorMessage($errorContainerZipCode, "");
                    helpers.showErrorMessage($errorContainerLogin, "");

                    if (isAlreadyInitialized) {
                        return;
                    }

                    // zip form ajax action
                    $('#zipCodeLoginWindow .enterZipCode input[type=submit]').click(function (e) {
                        if (isInProgress) {
                            return; // button has already been pressed, and ajax call is in progress, so do nothing
                        }

                        helpers.initSubmit(e);

                        var zipCode = $("#zipCodeLoginWindow input[type=text]").val();

                        // method automatically created by LandingPage.ascx user control
                        SetZipCode(
                            helpers.createSuccessHandler($errorContainerZipCode),
                            helpers.createErrorHandler($errorContainerZipCode),
                            zipCode);
                    });

                    // login form ajax action
                    $('#zipCodeLoginWindow .enterCredentials input[type=submit]').click(function (e) {
                        if (isInProgress) {
                            return; // button has already been pressed, and ajax call is in progress, so do nothing
                        }

                        helpers.initSubmit(e);

                        // validate input elements (asp.net "custom validator" style)
                        var args = { IsValid: false };
                        Q8.OilShop.loginValidate($(this), args);
                        if (!args.IsValid) {
                            helpers.showErrorMessage($errorContainerLogin, $errorContainerLogin.attr("originalHtml"));
                            return;
                        }

                        var enterCredentialsInputs = $("#zipCodeLoginWindow .enterCredentials input");

                        function getInputValue($input) {
                            var inputVal = $input.val();
                            if (inputVal === $input.attr("title")) {
                                return "";
                            }
                            return inputVal;
                        }

                        var customerNumber = getInputValue(enterCredentialsInputs.eq(0));
                        var zipCode = getInputValue(enterCredentialsInputs.eq(1));
                        var email = getInputValue(enterCredentialsInputs.eq(2));
                        var password = getInputValue(enterCredentialsInputs.eq(3));

                        // method automatically created by LandingPage.ascx user control
                        DoLogin(
                            helpers.createSuccessHandler($errorContainerLogin),
                            helpers.createErrorHandler($errorContainerLogin),
                            customerNumber, zipCode, email, password);
                    });

                    break;

                case 'sendForgottenLogInInfoWindow':

                    var helpers = {

                        showErrorMessage: function ($errorMessageContainer, text) {
                            $errorMessageContainer.html(text);
                            if (text) {
                                $errorMessageContainer.show();
                            } else {
                                $errorMessageContainer.hide();
                            }
                        },

                        createSuccessHandler: function ($errorContainer) {
                            $button = $errorContainer.closest("div").find("input[type=submit]");
                            helpers.showAjaxLoader($button);
                            return function (result) {
                                if (result.d.indexOf('error|') === 0) {
                                    // The zipcode was not valid or there was an error calling the web service
                                    helpers.showErrorMessage($errorContainer, result.d.substring(6));
                                    helpers.hideAjaxLoader($button);
                                } else {
                                    helpers.hideAjaxLoader($button);
                                    $('#sendForgottenLogInInfoWindow')
										.find('div.formfieldRound').hide().end()
										.find('p.succesMessage').show().end()
										.find('div.footerElements').hide().end()
										.find('div.clear:last').hide();
                                }
                            }
                        },

                        createErrorHandler: function ($errorContainer) {
                            return function (jqXHR, textStatus, errorThrown) {
                                helpers.showErrorMessage($errorContainer, "Der er desværre sket en kommunikationsfejl. Prøv igen, eller kontakt venligst Q8 om problemet");
                                $button = $errorContainer.closest("div").find("input[type=submit]");
                                helpers.hideAjaxLoader($button);
                            }
                        },

                        initSubmit: function (e) {
                            helpers.showErrorMessage($errorContainerEmail, "");
                            e.stopImmediatePropagation(); // preventDefault is not enough
                        },

                        showAjaxLoader: function ($button) {
                            isInProgress = true;

                            // show ajax loader next to button
                            $wrapper = $button.closest(".buttonWrapper");
                            $wrapper.prepend('<img class="buttonAjaxLoader" src="/gfx/Q8/ajax-loader-circle.gif" width="16" height="16" alt="Vent venligst..." />');
                        },

                        hideAjaxLoader: function ($button) {
                            isInProgress = false;

                            $wrapper = $button.closest(".buttonWrapper");
                            $wrapper.find(".buttonAjaxLoader").remove();
                        }
                    }

                    if (isAlreadyInitialized) {
                        return;
                    }

                    $errorContainerEmail = $("#sendForgottenLogInInfoWindow span.error").first();

                    // save sitecore translated text for later validation error message
                    if (!$errorContainerEmail.attr("originalHtml")) {
                        $errorContainerEmail.attr("originalHtml", $errorContainerEmail.html());
                    }

                    // any ajax call or post-back currently in progress?
                    var isInProgress = false;

                    // login form ajax action
                    $('#sendForgottenLogInInfoWindow input[type=submit]').click(function (e) {
                        if (isInProgress) {
                            return; // button has already been pressed, and ajax call is in progress, so do nothing
                        }

                        helpers.initSubmit(e);

                        // validate input elements (asp.net "custom validator" style)
                        var args = { IsValid: false };
                        Q8.OilShop.forgotEmailValidate($('#sendForgottenLogInInfoWindow'), args);

                        if (!args.IsValid) {
                            helpers.showErrorMessage($errorContainerEmail, $errorContainerEmail.attr("originalHtml"));
                            return;
                        }

                        var email = $("#sendForgottenLogInInfoWindow input[type=text]").val();

                        // method automatically created by LandingPage.ascx user control
                        SendForgottenLogInInfo(
                            helpers.createSuccessHandler($errorContainerEmail),
                            helpers.createErrorHandler($errorContainerEmail),
                            email);
                    });

                    break;
            }

            Q8.OilShop.inititalizedFancyboxWindows[$inner.attr('id')] = true;
        },

        setupPejlingPopupValidator: function () {
            // make sure pejling popup cannot be shown before tank size has been filled out
            $("#openPejling").click(function (e) {
                var elm = $("#oilLandingPage .errorMessage span.error").get(0);
                ValidatorValidate(elm, 'vgLandingPage', null);
                if (!elm.isvalid) {
                    e.stopImmediatePropagation();
                }
            });
        },

        setupFancybox: function (selector) {
            // call fancybox
            var fancyBoxConfig = {
                padding: 0,
                autoDimensions: true,
                transitionOut: 'none',
                overlayColor: '#000',
                overlayOpacity: 0.6,
                onComplete: function () {
                    var $inner = $(this.href);
                    Q8.OilShop.customRadioButtons($inner.find('span.radiobutton input[type=radio]'));
                    Q8.OilShop.initFancyboxWindows($inner);
                },
                onCleanup: function () {
                    var $inner = $(this.href);
                    var location = $inner.find('input[id$=_uiHdnRedirectOnClose]').val()
                    if (location) {
                        window.location.href = location;
                    }
                }
            };
            var fancyBoxes = $(selector);
            if (fancyBoxes.length) {
                var triggerThis;
                fancyBoxes.each(function () {
                    var that = $(this);

                    if (that.hasClass('modal')) {
                        fancyBoxConfig.modal = true;
                        that.fancybox(fancyBoxConfig);
                        fancyBoxConfig.modal = false;
                    }
                    else {
                        that.fancybox(fancyBoxConfig);
                    }

                    if (that.hasClass('autoopen')) {
                        triggerThis = that;
                    }
                });
                if (typeof (triggerThis) !== 'undefined') {
                    triggerThis.trigger('click');
                };
            }

            // add special handling for landing page main button
            var $calculateButton = Q8.OilShop.getLandingPageMainButton();
            if ($calculateButton.length) {
                // only ONE button to handle
                $calculateButton = $calculateButton.first();

                $calculateButton.click(function (e, data) {
                    // make sure base form validates before showing the popup
                    if (!Page_ClientValidate("vgLandingPage")) {
                        e.preventDefault();
                        return;
                    }

                    if (data && data.source == "zipLogin") {
                        // click comes from our script, just let the event pass through
                        //$.fancybox.close();
                        return true;
                    }

                    if (!Q8.OilShop.isLoggedIn()) {
                        // show fancybox to enter zip/login
                        $("#zipCodeLoginWindowTrigger").click();
                        e.preventDefault();
                        return;
                    }
                });
            }
        },

        PriceCalculator: {

            initialize: function () {
                // Shop data is not generated
                if (typeof (heatingOilShopData) === 'undefined') {
                    return;
                }

                // Calculate prices at init
                this.attachPrices(heatingOilShopData, $('div.formGradient'));

                // Calculate prices when any change happens
                $('div.formGradient input[type=radio], div.formGradient span.checkboxButton').bind('inputIsChecked', function () {
                    Q8.OilShop.PriceCalculator.attachPrices(heatingOilShopData, $('div.formGradient'));
                    Q8.OilShop.PriceCalculator.attachTracking(this);
                });
            },

            // Omniture tracking for "Beregn" page
            attachTracking: function (selector) {
                var $selector = $(selector);
                if (!$selector.length || typeof (s_account) == 'undefined') {
                    return;
                }

                // Products with radiobuttons
                if ($selector.attr('type') == 'radio') {
                    var $radioButtons = $selector.parent().siblings('span.radiobutton').find('input[type=radio]');

                    $radioButtons.each(function (i, element) {
                        var $input = $(this);

                        // If a new radio is choosen
                        if ($input.data('oldValue') == true) {
                            // Check if choosen input is delivery
                            var deliveryElment = $selector.parents('div.DeliveryTypes'),
								deliveryText = '',
				                oldDeliveryText = '',
				                newDeliveryText = '';

                            if (deliveryElment.length) {
                                var deliveryJsonData = heatingOilShopData.DeliveryTypes,
									deliveryElements = deliveryElment.find('input[type=radio]'),
									newDeliveryIndex = deliveryElements.index(deliveryElements.filter(':checked')),
									oldDeliveryIndex = deliveryElements.index($input),
									newDeliveryText = "Levering om " + deliveryJsonData[newDeliveryIndex].DurationInDays + " dage",
									oldDeliveryText = "Levering om " + deliveryJsonData[oldDeliveryIndex].DurationInDays + " dage";
                            }

                            // Remove from basket
                            var $oldProductText = $input.parent().next('label').children('strong').text().replace(',', '').replace(';', '');
                            if (oldDeliveryText != '') $oldProductText = oldDeliveryText;
                            var s = s_gi(s_account);
                            s.linkTrackVars = 'events,products';
                            s.linkTrackEvents = 'scRemove';
                            s.events = 'scRemove';
                            s.products = ';' + $oldProductText;
                            s.tl(element, 'o', 'Fjern produkt');


                            // Add product to basket
                            var $newProductText = $selector.parent().next('label').children('strong').text().replace(',', '').replace(';', '');
                            if (newDeliveryText != '') $newProductText = newDeliveryText;
                            var s = s_gi(s_account);
                            s.linkTrackVars = 'events,products';
                            s.linkTrackEvents = 'scAdd';
                            s.events = 'scAdd';
                            s.products = ';' + $newProductText;
                            s.tl(selector, 'o', 'Tilføj produkt');
                        }
                    });
                }

                // Products with checkbox
                else if ($selector.hasClass('checkboxButton')) {
                    var $input = $selector.find('input[type=checkbox]'),
						$productText = $selector.next('label').children('strong').text().replace(',', '').replace(';', '');

                    if ($input.attr('checked') == true) {
                        // Add product to basket
                        var s = s_gi(s_account);
                        s.linkTrackVars = 'events,products';
                        s.linkTrackEvents = 'scAdd';
                        s.events = 'scAdd';
                        s.products = ';' + $productText;
                        s.tl($input, 'o', 'Tilføj produkt');
                    }
                    else {
                        // Remove from basket
                        var s = s_gi(s_account);
                        s.linkTrackVars = 'events,products';
                        s.linkTrackEvents = 'scRemove';
                        s.events = 'scRemove';
                        s.products = ';' + $productText;
                        s.tl($input, 'o', 'Fjern produkt');
                    }
                }
            },

            attachPrices: function (heatingOilShopData, selector) {
                var selector = $(selector);
                if (!selector.length || selector.filter('.Products').length === 0) {
                    // no point in proceeding if there aren't any products on the page
                    return;
                }


                // Remove old boobles
                var oldBoobles = selector.find('p.choose span.boobleAdd, p.choose span.boobleSave').remove();
                var litersWanted = heatingOilShopData.LitersWanted;
                var tankSize = heatingOilShopData.TankSize;


                // Full tank
                var fullTankDiscount = 0,
					fullTankJson = heatingOilShopData.FullTankDiscount,
					fullTankDiscountAmount = fullTankJson / 1000 * litersWanted * -1,
					fullTankInput = selector.filter('.FullTank').find('input:checkbox'),
					fullTankIsChecked = $('div.FullTank input[type=checkbox]').is(':checked');

                if (fullTankIsChecked) {
                    fullTankDiscount = fullTankDiscountAmount;
                }
                else {
                    var booble = Q8.OilShop.PriceCalculator.attachBooble(fullTankDiscountAmount, fullTankDiscount, false);
                    fullTankInput.parent().next().after(booble);
                }

                $('dl.oilPrices dd.FullTankDiscount').text(this.formatPrice(fullTankDiscount) + ' kr.').end();


                // Products variables
                var literPrice = 0;
                var productsJson = heatingOilShopData.Products;
                var productsElm = selector.filter('.Products');
                var productsInput = productsElm.find('input:radio');
                var productsInputSelected = productsInput.filter(':checked');
                var productsInputIndex = productsInput.index(productsInputSelected);
                literPrice = productsJson[productsInputIndex].PricePer1000Liters / 1000; // Current price in liters

                // Introduction discount
                var introductionDiscount = 0,
					introductionJson = heatingOilShopData.IntroductionDiscount,
                    introductionDiscountAmount = introductionJson / 1000 * litersWanted * -1,
                    introductionDiscountEligible = productsInputIndex < productsInput.length - 1;

                if (introductionDiscountEligible) {
                    introductionDiscount = introductionDiscountAmount;
                }

                $('dl.oilPrices dd.IntroductionDiscount').text(this.formatPrice(introductionDiscount) + ' kr.').end();

                // More product calculations
                var calculatedPrice = litersWanted * literPrice;
                $('dl.oilPrices')
					.find('dd.Products')
					.text(this.formatPrice(calculatedPrice) + ' kr.').end()
					.find('dt.title')
					.text(productsJson[productsInputIndex].Name);

                var selectedProductPrice = calculatedPrice + introductionDiscount;

                // Find other products and add bobble
                $.each(productsJson, function (i) {
                    if (i != productsInputIndex) {
                        var currentProductsInput = productsInput.filter(':eq(' + i + ')');
                        var currentLiterPrice = productsJson[i].PricePer1000Liters / 1000;
                        var currentPrice = litersWanted * currentLiterPrice + (i < productsInput.length - 1 ? introductionDiscountAmount : 0);

                        var booble = Q8.OilShop.PriceCalculator.attachBooble(currentPrice, selectedProductPrice, true);
                        currentProductsInput.parent().next().after(booble);
                    }
                });


                // Payment methods
                var paymentMethodsJson = heatingOilShopData.PaymentMethods;
                var paymentMethodsElm = selector.filter('.PaymentMethods');
                var paymentMethodsInput = paymentMethodsElm.find('input:radio');
                var paymentMethodsInputSelected = paymentMethodsInput.filter(':checked');
                var paymentMethodsInputIndex = paymentMethodsInput.index(paymentMethodsInputSelected);
                var paymentMethodsDiscount = paymentMethodsJson[paymentMethodsInputIndex].DiscountPer1000Liters;
                var paymentMethodsPrice = paymentMethodsDiscount / 1000;

                var calculatedPaymentMethodsPrice;
                if (paymentMethodsJson[paymentMethodsInputIndex].Id == 3)
                    calculatedPaymentMethodsPrice = paymentMethodsJson[paymentMethodsInputIndex].DiscountPer1000Liters * -1;
                else
                    calculatedPaymentMethodsPrice = paymentMethodsPrice * litersWanted * -1;

                $('dl.oilPrices dd.PaymentMethods').text(this.formatPrice(calculatedPaymentMethodsPrice) + ' kr.').end();

                // Find other payment methods and add boobles
                $.each(paymentMethodsJson, function (i) {
                    if (i != paymentMethodsInput) {
                        var currentPaymentMethodsInput = paymentMethodsInput.filter(':eq(' + i + ')');
                        var currentLiterPrice = paymentMethodsJson[i].DiscountPer1000Liters;

                        if (paymentMethodsJson[i].Id == 3)
                            var currentPrice = paymentMethodsJson[i].DiscountPer1000Liters;
                        else
                            var currentPrice = currentLiterPrice / 1000 * litersWanted;

                        if (paymentMethodsJson[i].Id == 3)
                            var booble = Q8.OilShop.PriceCalculator.attachBooble(currentPrice * -1, calculatedPaymentMethodsPrice, false, true);
                        else
                            var booble = Q8.OilShop.PriceCalculator.attachBooble(currentPrice * -1, calculatedPaymentMethodsPrice, false);
                        currentPaymentMethodsInput.parent().next().after(booble);
                    }
                });

                // Delivery
                var deliveryJson = heatingOilShopData.DeliveryTypes;
                var deliveryElm = selector.filter('.DeliveryTypes');
                var deliveryInput = deliveryElm.find('input:radio');
                var deliveryInputSelected = deliveryInput.filter(':checked');
                var deliveryInputIndex = deliveryInput.index(deliveryInputSelected);
                var deliveryDiscount = deliveryJson[deliveryInputIndex].DiscountPer1000Liters;
                var deliveryPrice = deliveryDiscount / 1000;

                if (deliveryJson[deliveryInputIndex].DurationInDays == 1)
                    var calculatedDeliveryPrice = deliveryJson[deliveryInputIndex].DiscountPer1000Liters * -1;
                else
                    var calculatedDeliveryPrice = deliveryPrice * litersWanted * -1;

                $('dl.oilPrices dd.DeliveryTypes').text(this.formatPrice(calculatedDeliveryPrice) + ' kr.').end();

                // Find other delivery discounts and add boobles
                $.each(deliveryJson, function (i) {
                    if (i != deliveryInputIndex) {
                        var currentdeliveryInput = deliveryInput.filter(':eq(' + i + ')');
                        var currentLiterPrice = deliveryJson[i].DiscountPer1000Liters;

                        if (deliveryJson[i].DurationInDays == 1)
                            var currentPrice = deliveryJson[i].DiscountPer1000Liters;
                        else
                            var currentPrice = deliveryJson[i].DiscountPer1000Liters / 1000 * litersWanted;

                        var booble = Q8.OilShop.PriceCalculator.attachBooble(currentPrice * -1, calculatedDeliveryPrice, false);
                        currentdeliveryInput.parent().next().after(booble);

                    }
                });

                // Discounts
                var discounts = heatingOilShopData.SumOfPreCalculatedDiscounts;
                discounts = discounts + fullTankDiscount + introductionDiscount + calculatedPaymentMethodsPrice + calculatedDeliveryPrice;
                $('dl.oilPrices dd.discount').text(this.formatPrice(discounts) + ' kr.');

                // Update total price
                var totalPrice = calculatedPrice + discounts;
                $('dl.oilPrices dd.em').text(this.formatPrice(totalPrice) + ' kr.');

                // Update discount per 1000 liters
                var discountPer1000Liters = heatingOilShopData.SumOfDiscountsPer1000Liters;
                var discount1000Liters = discountPer1000Liters + paymentMethodsDiscount + deliveryDiscount;

                if (fullTankIsChecked) {
                    discount1000Liters += fullTankJson;
                }

                if (introductionDiscountEligible) {
                    discount1000Liters += introductionJson;
                }

                $('dl.oilPrices dd.note span.literPrice').text(this.formatPrice(discount1000Liters));
            },

            /**
            * @param	number	currentPrice	The current price
            * @param	number	calculatedPrice	The calculated price
            * @param	boolean	showGrayBooble	If true, booble always is gray
            */
            attachBooble: function (currentPrice, calculatedPrice, showGrayBooble, dontShowOnlyText) {
                showGrayBooble = (typeof showGrayBooble == 'undefined') ? false : showGrayBooble;
                dontShowOnlyText = (typeof dontShowOnlyText == 'undefined') ? false : dontShowOnlyText;
                var className = (showGrayBooble == true) ? 'boobleAdd' : 'boobleSave';
                var price = currentPrice - calculatedPrice;

                if (price > -0.01 && price < 0.01)
                    return;

                if (price < 0)
                    var output = '<span class="' + className + '"><span>Spar kr. ' + this.formatPrice(calculatedPrice - currentPrice) + '</span></span>';
                else 
                {
                    if (dontShowOnlyText)
                        var output = '<span class="boobleAdd"><span>kr. ' + this.formatPrice(price) + ' mere</span></span>';
                    else
                        var output = '<span class="boobleAdd"><span>Kun kr. ' + this.formatPrice(price) + ' mere</span></span>';
                }

                return output;
            },

            formatPrice: function (price) {
                if (price == 0)
                    return '0,00';
                else {
                    return $.formatNumber(price, { format: '#,###.00', locale: 'dk' })
                }
            }
        },

        loginBox: function (selector) {
            var loginWrapper = $(selector);
            if (!loginWrapper.length) {
                return;
            }

            loginWrapper.each(function () {
                var $self = $(this).parent();

                $self
					.find('a.openLogin').click(function () {
					    loginWrapper.find(".error").hide();
					    loginWrapper.slideDown(280);
					    $(this).hide().next().show();
					    return false;
					}).end()
					.find('a.close').click(function () {
					    loginWrapper.slideUp(280).parent().find('a.openLogin').show().next().hide();
					    return false;
					});

                // Fake an input on top of a password field to enable a default text
                var $passwordInput = $self.find('.formfieldRound.password input'),
					$fakeInput = $self.find('.formfieldRound.password .fakeInput');

                $fakeInput
					.click(function () {
					    $(this).hide();
					    $passwordInput.focus();
					    return false;
					});

                $passwordInput
					.focus(function () {
					    if ($fakeInput.is(':visible')) {
					        $fakeInput.hide();
					    }
					})
					.blur(function () {
					    if (!$(this).val().length > 0) {
					        $fakeInput.show();
					    }
					});
            });

        },

        forgotEmailValidate: function (source, args) {

            args.IsValid = false;

            var $emailField = source.find('input[type=text]').first();
            var emailVal = $.trim($emailField.val());
            var emailIsEmpty = !emailVal || emailVal == $emailField.attr('title');

            // if the field don't have default value or is pure whitespace
            if (!emailIsEmpty) {
                args.IsValid = true;
            }

            // blur all the fields to get back the default values (watermarks)
            setTimeout(function () { $emailField.blur(); }, 0);
        },

        loginValidate: function (source, args) {

            args.IsValid = false;

            var $loginWrapper = $(source).parents('.loginWrapper:first');
            if (!$loginWrapper.length) {
                return;
            }

            var $fields = $loginWrapper.find('input.formfield');

            var custNoVal = $.trim($fields.eq(0).val());
            var zipCodeVal = $.trim($fields.eq(1).val());
            var emailVal = $.trim($fields.eq(2).val());
            var passwordVal = $.trim($fields.eq(3).val());

            var custNoIsEmpty = !custNoVal || custNoVal == $fields.eq(0).attr('title')
            var zipCodeIsEmpty = !zipCodeVal || zipCodeVal == $fields.eq(1).attr('title')
            var emailIsEmpty = !emailVal || emailVal == $fields.eq(2).attr('title')
            var passwordIsEmpty = !passwordVal || passwordVal == $fields.eq(3).attr('title')

            // if any of the fields don't have default value or is pure whitespace
            if (!custNoIsEmpty || !zipCodeIsEmpty || !emailIsEmpty || !passwordIsEmpty) {

                // if ONLY custNo and zipCode is filled in and none of the other two then OK
                // or if ONLY email and password is filled in and none of the other two then also OK
                args.IsValid = (!custNoIsEmpty && !zipCodeIsEmpty && emailIsEmpty && passwordIsEmpty) || (custNoIsEmpty && zipCodeIsEmpty && !emailIsEmpty && !passwordIsEmpty);
            }

            // blur all the fields to get back the default values (watermarks)
            setTimeout(function () { $fields.blur(); }, 0);
        },

        initAutoscrollValidate: function (selector) {
            $(selector).parents("form").bind("submit", function (e) {
                if (!Page_IsValid) {
                    var scrolling = false;

                    // find first error message and scroll to show it
                    $(selector).find(".error").filter(":visible").each(function () {
                        // elements hidden with visibility:hidden are not filtered out with ":visible", so test for this
                        if (!scrolling && $(this).css("visibility") == "visible") {
                            // scroll to position just above the elements parent
                            $('html,body').animate({
                                scrollTop: $(this).parent().offset().top - 20
                            }, 500);

                            scrolling = true;
                        }
                    });
                }
            });
        },

        bindOilflowBoxEvents: function (selector) {
            var oilFlowBox = $(selector);
            if (!oilFlowBox.length) {
                return;
            }
            var topPosBox = oilFlowBox.offset();
            topPosBox = topPosBox.top;

            if (jQuery.browser.msie && jQuery.browser.version <= "7") {
                topPosColumn = jQuery('#related').offset();
                topPosColumn = topPosColumn.top;
                oilFlowBox.css({
                    position: 'relative'
                });

                jQuery(window).scroll(function () {
                    var topPosDoc = jQuery(window).scrollTop() + 10;
                    var topPosDoc = topPosDoc - topPosColumn;
                    if (topPosDoc > 0) {
                        oilFlowBox.css({
                            position: 'absolute',
                            top: (topPosDoc) + 'px'
                        });
                    }
                    else {
                        oilFlowBox.css({
                            "top": "10px",
                            "position": "static"
                        });
                    }
                });
            }
            else {
                jQuery(window).scroll(function () {
                    var topPosDoc = jQuery(window).scrollTop() + 10;
                    if (topPosDoc > topPosBox) {
                        oilFlowBox.css({
                            position: 'fixed',
                            top: 10
                        });
                    }
                    else {
                        oilFlowBox.css('position', 'static');
                    }
                });
            }
        },

        tooltip: function (selector) {
            var $selector = $(selector);
            if (!$selector.length) {
                return;
            }

            $selector.each(function () {
                var $span = $(this);
                $span.parent().hover(
                    function () {
                        // Fix IE opacity bug
                        if ($.browser.msie)
                            $span.show();
                        else
                            $span.fadeIn(100);
                    },
                    function () {
                        if ($.browser.msie)
                            $span.hide();
                        else
                            $span.fadeOut(200);
                    }
                );
            });

        },

        customCheckboxButtons: function (selector) {
            var $selector = $(selector);
            if (!$selector.length) {
                return;
            }

            // Check for checked checkboxes and attach className
            $selector.each(function () {
                var $input = $(this);

                if ($input.is(':checked')) {
                    $input.parent().addClass('checkboxButtonSelected');
                }

                $input.parent('span.checkboxButton').click(function () {
                    if ($(this).hasClass('checkboxButtonDisabled'))
                        return;

                    if ($input.is(':checked'))
                        $input.attr('checked', false);
                    else
                        $input.attr('checked', true);

                    $input.trigger('inputIsChecked');
                    Q8.OilShop.customCheckboxClick($input);
                });


                // Fix IE event bug on checkboxes
                if ($.browser.msie) {
                    $input.click(function () {
                        this.blur();
                        this.focus();
                    });
                }
            });

            // Change className when any change happens
            $selector.click(function () {
                if ($(this).is(':checked'))
                    $(this).attr('checked', false);
                else
                    $(this).attr('checked', true);

                Q8.OilShop.customCheckboxClick($(this));
            });

            Q8.OilShop.customCheckboxHover($selector.parent('span.checkboxButton'));

            $selector.parent('span.checkboxButton').next('label').hover(
                function () {
                    $(this).prev().trigger('mouseover');
                },
                function () {
                    $(this).prev().trigger('mouseout');
                }
            );
        },

        customCheckboxHover: function ($selector) {
            $selector.hover(
                function () {
                    if ($(this).hasClass('checkboxButtonDisabled'))
                        return;

                    if ($(this).hasClass('checkboxButtonSelected'))
                        $(this).addClass('checkboxButtonSelectedHover');
                    else
                        $(this).addClass('checkboxButtonHover');
                },
                function () {
                    $(this).removeClass('checkboxButtonHover checkboxButtonSelectedHover')
                }
            );
        },

        customCheckboxClick: function ($input) {
            // Set className for checked inputs elements
            var $span = $input.parent();

            if ($input.is(':checked')) {
                $span.addClass('checkboxButtonSelected');

                if ($span.hasClass('checkboxButtonHover')) {
                    $span
                        .removeClass('checkboxButtonHover')
                        .addClass('checkboxButtonSelectedHover');
                }
            }
            else {
                $span
                    .addClass('checkboxButtonHover')
                    .removeClass('checkboxButtonSelected checkboxButtonSelectedHover');
            }
        },

        customRadioButtons: function (selector) {
            var $selector = $(selector);
            if (!$selector.length) {
                return;
            }

            // Check for checked radiobuttons and attach className
            $selector.each(function () {
                var $input = $(this);

                if ($input.is(':checked')) {
                    $input.parent().addClass('radiobuttonSelected');
                }

                $input.parent('span.radiobutton').click(function (event) {
                    if ($(this).hasClass('radiobuttonDisabled'))
                        return;

                    var inputName = $input.attr('name');
                    var inputName = inputName.substring(inputName.lastIndexOf('$')),
						inputId = $input.attr('id');

                    var $inputsByName = $("input[name$='" + inputName + "']");

                    $inputsByName.each(function (i) {
                        var $that = $(this),
							thatId = $that.attr('id'),
							oldValue = !!$that.attr('checked');

                        if (thatId == inputId) {
                            oldValue = false;
                        }

                        $that
							.data('oldValue', oldValue)
							.attr('checked', false);
                    });

                    $input
						.attr('checked', 'checked')
						.trigger('inputIsChecked');

                    Q8.OilShop.customRadioClick($input);

                    // Check to see if there is a hidden field whose value has to be set to signal that user has
                    // actually chosen one of the radio button options. It may be that none of the radio buttons are checked
                    $('input[id$=uiHdn' + inputName.toUpperCase().substr(1, 1) + inputName.substring(2) + 'HasBeenChosen]').val('true');
                });

                // Fix IE event bug on radiobuttons
                if ($.browser.msie) {
                    $input.click(function () {
                        this.blur();
                        this.focus();
                    });
                }
            });

            // Change className when any change happens
            $selector.change(function () {
                Q8.OilShop.customRadioClick($(this));

                // Removed because of double event clicking
                //$(this).trigger('inputIsChecked');
            });

            Q8.OilShop.customRadioHover($selector.parent('span.radiobutton'));

            $selector.parent('span.radiobutton').next('label').hover(
                function () {
                    $(this).prev().trigger('mouseover');
                },
                function () {
                    $(this).prev().trigger('mouseout');
                }
            );
        },

        customRadioHover: function ($selector) {
            $selector.hover(
                function () {
                    if ($(this).hasClass('radiobuttonSelected'))
                        $(this).addClass('radiobuttonSelectedHover');
                    else
                        $(this).addClass('radiobuttonHover');
                },
                function () {
                    $(this).removeClass('radiobuttonHover radiobuttonSelectedHover')
                }
            );
        },

        customRadioClick: function ($input) {
            // Set className for checked inputs elements
            var $span = $input.parent();

            if ($input.is(':checked')) {
                $span
                    .addClass('radiobuttonSelected')
                    .siblings('span.radiobuttonSelected')
                    .removeClass('radiobuttonSelected');

                /* If all input have same name, use this
                if ( $span.parent('.chooseSmall').length > 0 )
                {
                var $inputId = $input.attr('id');
                    
                $formGradient = $span.parent().parent('.formGradient');
                $formGradient.find('input').each(function(){
                if ( $(this).attr('id') != $inputId )
                {
                $(this)
                .parent()
                .removeClass('radiobuttonSelected');
                }
                });
                }*/

                if ($span.hasClass('radiobuttonHover')) {
                    $span
                        .removeClass('radiobuttonHover')
                        .addClass('radiobuttonSelectedHover');
                }
            }
            else {
                $span.addClass('radiobuttonSelected');
            }
        },

        validateHdnValTrue: function (source, args) {
            // Validates that the matching hidden field has the value 'true'. The matching hidden field is a hidden field
            // with where the id matches the name of the source parameter (which is a CustomValidator). The ids should
            // adhere to CCC like so uiCvChosenName / uiHdnChosenName ... the value 'true' can then be set by code behind
            // or by the click event on a set of matching radio buttons (search this file for 'HasBeenChosen' to see example)
            var idEndsWith = source.id.split('_');
            idEndsWith = idEndsWith[idEndsWith.length - 1];
            idEndsWith = idEndsWith.replace(/^uiCv/g, 'uiHdn');
            args.IsValid = $('input[id$=' + idEndsWith + ']').val() === 'true';
        },

        validateCbIsChecked: function (source, args) {
            var idEndsWith = source.id.split('_');
            idEndsWith = idEndsWith[idEndsWith.length - 1];
            idEndsWith = idEndsWith.replace(/^uiCv/g, 'uiCb');
            args.IsValid = $('input[id$=' + idEndsWith + ']').is(':checked');
        }
    },

    RemoveDefaultInputValue:
    {
        init: function ($form, $isCallback) {
            $form.each(function () {
                var $thisForm = $(this),
                    $inputItems = $thisForm.find('input.defaultvalue');

                if ($inputItems.length) {
                    $inputItems.each(function () {
                        Q8.RemoveDefaultInputValue.setRemoveAction($(this), $thisForm, $isCallback);
                    });
                }
            });
        },
        setRemoveAction: function ($inputitem, $form, $isCallback) {
            if ($form.is('form')) {
                $form.submit(function () {
                    // don't change anything unless page is actually about to be submitted
                    if (!Page_IsValid) {
                        return false;
                    }
                    if ($inputitem.val() == $inputitem.attr("title")) {
                        $inputitem.val("");
                    }

                    return true;
                });
            }

            if (!$isCallback) {
                if ($inputitem.val() == '') {
                    $inputitem.val($inputitem.attr("title")).addClass('enableDefaultColor');
                }
                else if ($inputitem.val() != $inputitem.attr("title")) {
                    $inputitem.removeClass('enableDefaultColor');
                }
                else {
                    $inputitem.addClass('enableDefaultColor');
                }
            }

            /* If value not is equal to title. Change type to password -(buggy in ie)
            *
            if ( $inputitem.hasClass('passInput') && $inputitem.val() != $inputitem.attr("title") && $inputitem.attr('type') == 'text' )
            {
            var $parent = $inputitem.parent();
            var $clone = $('<div>').append($inputitem.clone()).remove().html().replace('text', 'password');
            var value = $inputitem.val();
            $inputitem.replaceWith($clone);
            $parent.find('input.defaultvalue').val(value).focus();
            Q8.RemoveDefaultInputValue.init( $parent, false );
            }*/

            $inputitem.bind("focus", function (event) {
                if ($inputitem.val() == $inputitem.attr("title")) {
                    $inputitem.val("").removeClass('enableDefaultColor');
                }

                if ($inputitem.hasClass('passInput')) {
                    $inputitem.unbind();
                    var $parent = $inputitem.parent();
                    // Clone object to enable change of input type.
                    var $clone = $('<div>').append($inputitem.clone()).remove().html().replace('text', 'password');
                    var value = $inputitem.val();
                    $inputitem.replaceWith($clone);
                    $parent.find('input.defaultvalue').val(value).focus();
                    Q8.RemoveDefaultInputValue.init($parent, true);
                }
            })
            .bind("blur", function (event) {
                if ($inputitem.val() == "") {
                    if ($inputitem.hasClass('passInput')) {
                        $inputitem.unbind();
                        var $parent = $inputitem.parent();
                        var $clone = $('<div>').append($inputitem.clone()).remove().html().replace('password', 'text');
                        $inputitem.replaceWith($clone.replace('password', 'text'));
                        $parent.find('input.defaultvalue').val($inputitem.attr("title")).addClass('enableDefaultColor');
                        Q8.RemoveDefaultInputValue.init($parent, false);
                    }
                    else {
                        $inputitem.val($inputitem.attr("title")).addClass('enableDefaultColor');
                    }
                }
            });
        }
    },

    PageMethodHandler:
    {
        defaultOnSuccess: function (result) { },

        defaultOnError: function (jqXHR, textStatus, errorThrown) { },

        callMethod: function (control, method, onSuccess, onError) {

            var args = '';
            for (var i = 4; i < arguments.length; i++) {
                if (args.length != 0)
                    args += ',';
                args += "'" + arguments[i] + "'";
            }

            var finalArgs = '"control":"' + control + '","method":"' + method + '","args":"' + args + '"';
            jQuery.ajax({
                type: "POST",
                url: "/PageMethodHandler.ashx",
                data: "{" + finalArgs + "}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                cache: false,
                success: onSuccess || defaultOnSuccess,
                error: onError || defaultOnError
            });
        }
    },
    FormValidator:
    {
        initialize: function (formSelector, ruleSelector) {
            var $formSelector = $(formSelector),
					$ruleSelector = $(ruleSelector);

            if (!$formSelector.length || !$ruleSelector.length) {
                return;

            }
            // intinitialize
            this.startValidation($("#form"));
            this.setupRules($("#submit"));
            this.settings();
            // start debug
            $.validator.setDefaults({
                debug: true
            });
        },
        startValidation: function ($formSelector) {
            $formSelector.validate();
        },
        setupRules: function ($ruleSelector) {
            $ruleSelector.validate({
                rules: {
                    radio: "required",
                    email: {
                        required: true,
                        email: true
                    },
                    cardNumber: "required"
                },
                messages: {
                    radio: "required",
                    kiosk: "Udfyld venligst brændstof",
                    email: "Please enter a valid email address",
                    cardNumber: "Udfyld venligst"
                }
            });

            //test - assign validation to classes instead of name
            $(".formradio").rules("add", {
                required: true
                //minlength:3
            });
        },
        settings: function () {
            // custom error placement
            $.validator.setDefaults({
                errorPlacement: function (error, element) {
                    error.appendTo('.error');
                    // alert("Error!");
                }
            });
        }
    }
};

$(document).ready(function() {
	Q8.initialize();
});

// Debug plugins
$.fn.log = function(msg) {
    msg = msg || 'log';
    console.log("%s: %o", msg, this);
    return this;
};

// if an input element contains a "tooltip" text, i.e. a text that is written inside 
// the input element but acts a label, that text is removed before the value is returned
$.fn.tooltipNormalizedVal = function() {
    if (this.is("input") && this.attr("title") && this.val() == this.attr("title")) {
        return "";
    }
    return this.val();
}

$.fn.combine = function() {
    if(this.length < 2) {
        // a combined element must be at least two elements
        throw "jquery.combine: A combined element must be at least two elements";
        return false;
    }
    
    var $self = this;
    var focusId = null;
    var usedToHaveFocus = false;
    
    // create dummy element that have all external handlers (see return statement at the end)
    var $dummy = $('<div style="display: none;"/>');
    
    this.focus(function() {
        // track that one of our elements currently have focus
        focusId = $(this).attr("id");
        
        if(!usedToHaveFocus) {
            usedToHaveFocus = true;
            $dummy.trigger("focus");
        }
    });
    
    this.blur(function() {
        // about to blur the previously focused element, so we reset tracker first
        focusId = null;
        
        // might be a sign of the combo having blurred, give it a few milliseconds, to see where focus lands 
        // (if it's in the other control, then we lost focus)
        setTimeout(function() {
            var focus = false;
            $self.each(function() {
                focus = (focusId == $(this).attr("id") || focus);
            });
            if (!focus) {
                usedToHaveFocus = false;
                $dummy.trigger("blur");
            }
        }, 100);
    });
    
    return $dummy;
}

$.fn.CharsLeftCounter = function (outputElement, max) {
    var o = outputElement;
    var maxchar = max;
    var me = $(this);
    var backspace = 8;
    var del = 46;

    o.text(maxchar);

    this.bind('keydown', function (e) {
		var key = e.which;
		if ((key > 36 && key < 41) || key == backspace || key == del)  // ignore navigation arrows and backspace
            return true;
        if ($(this).val().length == maxchar) {
            o.text(0);

			if ( key != 9 )
				return false;
        }
    });

    this.bind('keyup', function (e) {
        var key = e.which;
        if ((key > 36 && key < 41)) { // ignore navigation arrows
            return $(this);
        }
        if ($(this).val().length > (maxchar) && key != 8) {
            $(this).val($(this).val().substring(0, maxchar));
            o.text(0);
            return false;
        }
		var inputLength = $(this).val().length;
		if ($(this).hasClass('defaultvalue') && $(this).val() == $(this).attr('title'))
		{
			inputLength = 0;
		}
        o.text(maxchar - inputLength);
        return $(this);
    });

    var removeCharsAboveMax = function () { // resolve paste issue
        if (me.val().length > (maxchar)) {
            me.val(me.val().substring(0, maxchar));
        }
    };

    var timer = null;

    this.bind('focusin', function (e) {
        timer = window.setInterval(removeCharsAboveMax, 1000);
    });

    this.bind('focusout', function (e) {
        window.clearInterval(timer);
    });

};

(function($){
    '$:nomunge'; // Used by YUI compressor.
  
    $.fn.iff = function( test ) {
        var failed = !test || $.isFunction( test)
                && !test.apply( this, Array.prototype.slice.call(arguments, 1) ),
            $new = this.pushStack( failed ? [] : this, 'iff', [test] );

        $new.els = function() {
            return this.end().pushStack(
                failed ? this.prevObject : [],
                this.selector.substr(this.prevObject.selector.length + 1) + '.else',
                []
            );
        };

        return $new;
    };

    $.fn.els = function() { return this; };

})(jQuery);

jQuery.fn.report = function(msg) {
    if(this.length) console.log(jQuery.fn.report.idx++ + '. ' + msg + ' | selector="' + this.selector + '"');
    return this;
};
/*
	If statements in chain - benalman.com/projects/jquery-iff-plugin/

jQuery.fn.report = function(msg) {
    if(this.length) console.log(jQuery.fn.report.idx++ + '. ' + msg + ' | selector="' + this.selector + '"');
    return this;
};
jQuery.fn.report.idx = 1;

jQuery('div')
    .els()
        .report('els is noop without iff')
    .iff(false)
        .report('iff block entered')
    .els()
        .report('els block entered')
        .iff(true)
            .report('nested iff block entered')
        .els()
            .report('nested els block entered')
        .end()
        .report('still in else block')
    .end()
    .report('Back to orig');


Output:
1. els is noop without iff | selector="div"
2. els block entered | selector="div.iff(false).else()"
3. nested iff block entered | selector="div.iff(false).else().iff(true)"
4. still in else block | selector="div.iff(false).else()"
5. Back to orig | selector="div"
*/

