/* Observes and assigns the primary nav selected state */
$(document).observe('dom:loaded', function(){
    var notification = getCookie('Liberty.Product.notification'),
        m = document.uniqueID /*IE*/ && document.compatMode /*>=IE6*/ && !window.XMLHttpRequest /*<=IE6*/ && document.execCommand,
        protectLinks = $$('.protect');

    if (notification) {
        Liberty.Common.notify(notification);
        eraseCookie('Liberty.Product.notification');
    }
    try{if(!!m){m("BackgroundImageCache", false, true) /* = IE6 only */}}catch(oh){};
    if (protectLinks.length > 0) {
        protectLinks.invoke('observe', 'click', Liberty.Common.protectLink);
    }
    
    var comingSoonLink = $('boutiqueCategory_soon');
    if (comingSoonLink) {
        new Ajax.Request('/event/previewEvents', {
            method: 'get',
            asynchronous: false, //block until this AJAX call returns
            parameters: {},
            onComplete: function(transport) {
                if (comingSoonLink && transport.request.success() && transport.responseText != '') {
                    comingSoonLink.insert({after: transport.responseText});
                    var modalLinks = $$('#categoryBoutiques_soon a.modal');
                    if (modalLinks.length) {
                        modalLinks.invoke('observe', 'click', handleModalLinkClick);
                    }
                }
            }
        });
    }
});


function FinishRondavuData(TempRondavuData){
	//rondavu-sl-start
  	if( typeof(TempRondavuData) !== 'undefined'){
		
  		a = document.createElement('a');
		a.href = document.URL;
		var path = a.pathname.toLowerCase() ;
		var isRegPage = path.search(/registration/i);
		 
		  
		 if( getCookie('rusersign') && getCookie('ruserbase') && (isRegPage < 0) ){
		
			var rUserSign = getCookie('rusersign');
			var rUserBase = getCookie('ruserbase');
			var rNewRegistration = getCookie('newRegistration');
			
			TempRondavuData.user_base64 = rUserBase;
			TempRondavuData.signature.user = rUserSign;
			
			if(rNewRegistration === 'true'){
				//set the new registration page property
				TempRondavuData.page.is_new_registration = rNewRegistration;
				//set the tags array page property
				if(typeof(TempRondavuData.page.tags) !== 'undefined'){
					TempRondavuData.page.tags.push("first_login");
					
				}else{
					TempRondavuData.page.tags = ["first_login"];
				}
				
				eraseCookie('newRegistration');
			}
			
			window.RondavuData = TempRondavuData;
			
		}
		
		else if(isRegPage >= 0){
			window.RondavuData = TempRondavuData;
		}
		
		if(typeof(console) !== 'undefined') {
		    console.log(window.RondavuData)
		}	
	} 
  	//rondavu-sl-end
}

/*
 * common.js - Common javascript functions for the Liberty storefront.
 *
 */

//check to see if we are missing the Liberty object, if so make a bogus object .... Kinda like Congress but different.
if (typeof Liberty == "undefined") Liberty = {};

Object.extend(Liberty, {
    ServerTimeOffset : null,
    Common : {
        cmsTipVal : '',
        loaded : false,
        loadingBoxId : 'loading_box',
        
        focusOnFirstInput : function (container) {
            var parent = container || $(document.body),
                inputs = parent.select('textarea, select, input');
            if (inputs.length > 0) {
                try {
                    inputs.each(function (element) {
                        if (element.type != 'hidden' && !element.disabled) {
                            element.focus();
                            throw $break;
                        }
                    });
                } catch (e) {}
            }
        },
        
        noLabelBlur : function (event) {
            var defaultValue = this.readAttribute('data-default');
            if (defaultValue && this.value === '') {
                this.value = defaultValue;
            }
        },
        
        noLabelFocus : function (event) {
            var defaultValue = this.readAttribute('data-default');
            if (defaultValue && this.value === defaultValue) {
                this.value = '';
            }
        },
        
        tagPage : function (page, group) {
            if (typeof cmCreatePageviewTag == 'function' && arguments.length === 2) {
                try { cmCreatePageviewTag(page, group); } catch (e) {};
            }
        },

        daysRemaining: function(expiresTs) {
            var ts = Math.round(new Date().getTime());
            return Math.floor( (expiresTs - ts)/86400000 );
        },

        protectLink : function(event) {
            event.stop();
            if (!!window.protectedLinkClicked){ return false; }
            window.protectedLinkClicked = true;
            var elem = Event.findElement(event, '.protect'),
                href = elem.href;
                elem.removeAttribute('href');
                elem.addClassName('disabled');
                document.location.href = href;
        },
        toggleBttn : function(buttonId) {
            var button = $(buttonId);
            if (button) {
                if (button.disabled===true) {
                    button.enable().removeClassName('disabled');
                } else {
                    button.disable().addClassName('disabled');
                }
            }
        },
        toggleSpinnerButton : function (sel) {
            //show spinner, hide button
            $$(sel).each(function(elem, i) {
                elem.toggle();
                elem.next('.spinner').toggle();
            });
        },
        postLoad : function(cmsTipVal) {
            if ( typeof(cmsTip) == 'function' ) {
                cmsTip(Liberty.Common.cmsTipVal);
            } else {
                Liberty.Common.updateInviteContainer();
            }
        },

        postUnload : function() {
            Tips.visible.each(Element.hide);
        },

        notify : function(message) {
            var el = new Element('div', {'class': 'success notice'});
            el.innerHTML = message;
            $('main').insert({top: el});
        },

        startLoading : function() {
            Liberty.Common.loaded = false;
            Liberty.Common.showLoadingImage();
        },

        stopLoading : function() {
            if ($(Liberty.Common.loadingBoxId)) {
                Element.hide(Liberty.Common.loadingBoxId);
                Liberty.Common.loaded = true;
            }
        },

        showLoadingImage : function() {
            var el = $(Liberty.Common.loadingBoxId);
            if (el && !Liberty.Common.loaded) {
                el.show();
                el.innerHTML = '<img src="/img/loading.gif" alt="loading">';
            }
        },

        mod10check : function(cc) {
            var validate = 0;
            cc.toArray().reverse().each(function(digit, idx) {
                digit = Number(digit);
                // if odd then double the value and add each resulting digit to validate
                if (idx % 2 == 1) {
                    String(digit * 2).toArray().map(Number).each(function(n) {
                        validate += n;
                    });
                // else just add the digit to validate
                } else {
                  validate += digit;
                }
            });
            // if validate is a factor of 10, then the cc number is valid
            return (validate % 10 == 0);
        },

        disableTextSelection : function(target){
            if (typeof target.onselectstart!='undefined') { //IE route
                target.onselectstart=function(){return false}
            } else if (typeof target.style.MozUserSelect!='undefined') {//Firefox route
                target.style.MozUserSelect='none'
            } else { //All other route (ie: Opera)
                target.onmousedown=function(){return false}
                target.style.cursor = 'default'
            }
        },

        rememberScrollPosition : function(event){
            var elem = Event.findElement(event, 'a.productImage');
            if(elem){
                var offsets = document.viewport.getScrollOffsets(),
                    href = document.location.pathname,
                    matches = href.match(/\d+/);
                if(matches && matches.length > 0){
                    var eventId = matches[0];
                    if(!isNaN(parseInt(eventId,10))){
                        createCookie( 'eventPageScrollPosition', offsets[0] + "|" + offsets[1] + "|" + eventId );
                    }
                }
            }
        },

        adjustScrollPosition : function(){
            var positionCookie = readCookie('eventPageScrollPosition');
            if(positionCookie!=null){
                var bits = unescape(positionCookie).split("|");
                if(bits.length == 3){
                    var xPos = parseInt(bits[0],10),
                        yPos = parseInt(bits[1],10),
                        prevEvent = parseInt(bits[2],10);
                    if(!isNaN(xPos) && !isNaN(yPos) && !isNaN(prevEvent) && document.location.pathname.indexOf(prevEvent)!=-1){
                        scrollTo(xPos,yPos);
                    }
                }
                eraseCookie('eventPageScrollPosition');
            }
        },

        digitRegExp : /[\D]+/g,
        currencyRegExp : /(\d+)(\d{3})/,

        parseDisplayedPrice : function(text){
            var arr = text.split('-'),
                x = arr.length;
            if (x > 1) {
                while (x--) {
                    arr[x] = +(arr[x].replace(this.digitRegExp,''));
                }
                return arr;
            } else {
                return +text.replace(this.digitRegExp,'');
            }
        },

        recalculateDisplayedRangePrice : function(rangeArr,qty){
            var x = rangeArr.length,
                  newArr = [];

            while (x--) {
                newArr.unshift(this.getDisplayPrice(rangeArr[x]*qty));
            }

            return newArr;
        },

        canQuickBuy : function() {
            return (readCookie('Liberty.QuickBuy.canQuickBuy') === '1');
        },

        /**
         * Returns a display formatted price for a range of
         * prices, or just one.
         */
        getDisplayPrice : function(min, max) {
            if (typeof min == 'number' && min <= 1) {
                return this.getDisplayCredits((min/100).toFixed(2));
            }
            if (min == null) min = 0; //ensures that this function works in the same manner as our PHP get_display_price()
            if (null == max || min == max) {
                if (min < 0) {
                    min = -min;
                    return '-' + this.getDisplayCredits((min/100).toFixed(2));
                } else {
                    return this.getDisplayCredits((min/100).toFixed(2));
                }
            } else {
                return this.getDisplayCredits((min/100).toFixed(2)) + ' - ' + this.getDisplayCredits((max/100).toFixed(2));
            }
        },

        /**
         * Returns a display credits with comma
         */

        getDisplayCredits : function(nStr) {
            nStr += '';
            var x = nStr.split('.'),
                x1 = x[0],
                x2 = x.length > 1 ? '.' + x[1] : '';

            while (this.currencyRegExp.test(x1)) {
                x1 = x1.replace(this.currencyRegExp, '$1' + ',' + '$2');
            }
            return '$' + x1 + x2;
        },


        /**
         * Returns a display formatted price for shipping
         */
        getShippingDisplayPrice : function(min, max) {
            if ((min == 0 || null == min) && (null == max || min == max)) {
                return "<span class='noCost'>FREE</span>";
            } else {
                return this.getDisplayPrice(min, max);
            }
        },

        /**
        * Uses product's styleNum to return page to product image
        * @param style
        * @param attr
        * @param secure
        * @param imageSuffix
        * @return formatted image path (Text)
        * @see Product.loadImageAngles
        */    
        getItemImage : function( style, attr, secure, imageSuffix ) {
            var path = 'images/product/' + style.substr(0, 6) + '/';
            var colorNameSuffix = '';
            if ( attr !=null && attr.length()>0 ) {
                var uScoreIndex = attr.indexOf('_');
                var dotIndex = attr.indexOf('.');
                var colorNameSuffix = attr.substr(uScoreIndex, dotIndex - uScoreIndex);
            }
            var fileName = style + '_' + imageSuffix + (colorNameSuffix!=null?colorNameSuffix:'') + '.jpg';
            return imgHost + path + fileName;
        },

        /**
         * Returns true if object is an Array.
         *
         * @param Object object
         */
        isArray : function(object) {
            return object
                  && !(object.propertyIsEnumerable('length'))
                  && typeof(object) === 'object'
                  && typeof(object.length) === 'number';
        },

        associativeArrayLength : function(array) {
            var length = 0, key;
            for(key in array) {
                length++;
            }
            return length;
        },

        isHidden : function(object) {
            return (object.style.display == 'none');
        },

        hide : function(object) {
            object.style.display = 'none';
        },

        show : function(object) {
            object.style.display = '';
        },

        max : function(a, b) {
            return (a > b ? a : b);
        },

        min : function(a, b) {
            return (a < b ? a : b);
        },

        /**
         * Changes the first letter of each word in string to upper case.
         *
         *   http://kevin.vanzonneveld.net
         *   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
         *   improved by: Waldo Malqui Silva, Onno Marsman
         *
         * @param string words
         * @return string
         */
        ucWords : function(words) {
            return words.replace(/^(.)|\s(.)/g, function($1) { return $1.toUpperCase(); });
        },

        padValue : function(value){
            return value < 10 ? '0'+value : value.toString();
        },

        initializeBagLink : function(){
            var bagLink = $('bagLink');
            if (bagLink) {
                bagLink.observe('click',this.handleBagLinkClick);
            }
        },

        handleBagLinkClick : function(event){
            event.stop();
            Modalbox.show(this.href, {title:this.title, width:950});
        },

        fixModalFormSubmitIE : function(event) {
            var loginField = $('txtEmailLogin')
                , passField = $('txtPass');
            if (loginField && passField) {
                loginField.observe('keydown', this.checkForEnterKey);
                passField.observe('keydown', this.checkForEnterKey);
            }
        },

        checkForEnterKey : function(event) {
            if(event.keyCode == 13) {
                $('loginAccess').submit();
            }
        },

        initializePreviewLinks : function(){
            var comingSoonDiv = $('comingSoon');
            if (comingSoonDiv) {
                comingSoonDiv.observe('click',this.handlePreviewLinkClick);
            }
            var previewLocalDiv = $('previewLocal');
            if (previewLocalDiv) {
                previewLocalDiv.observe('click',this.handlePreviewLinkClick);
            }
        },

        handlePreviewLinkClick : function(event){
            var choice = Event.findElement(event, 'a');
            if(choice){
                event.stop();
                Modalbox.show(
                    choice.href,
                    {
                        height:500,
                        onShow : function() {
                            Liberty.Common.setTeaserDisableStyle()
                        },
                        overlayDuration:0,
                        title:'Preview this Boutique',
                        width:950
                    }
                );
            }
        },

        setTeaserDisableStyle : function() {
            $('MB_frame').addClassName('teaserReelHeader');
            $('MB_content').addClassName('teaserReelContent');
        },

        URLEncode : function(clearString) {
            var output = '',
                x = 0,
                regex = /(^[a-zA-Z0-9_.]*)/;
            clearString = clearString.toString();
            while (x < clearString.length) {
                var match = regex.exec(clearString.substr(x));
                if (match != null && match.length > 1 && match[1] != '') {
                    output += match[1];
                    x += match[1].length;
                } else {
                    if (clearString[x] == ' ') {
                        output += '+';
                    } else {
                        var charCode = clearString.charCodeAt(x),
                            hexVal = charCode.toString(16);
                        output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase();
                    }
                    x++;
                }
            }
            return output;
        },

        confirmAction : function(url, message, cmPage, altButtons) {
            var messageParam = message || '',
                fullUrl = '/common/confirmAction?url=' + url + '&messageCode=' + encodeURIComponent(messageParam);

            if (typeof cmPage != 'undefined') {
                fullUrl += '&cmPage=' + cmPage
            }
            
            if (typeof altButtons != 'undefined') {
                fullUrl += '&altButtons=' + altButtons;
            }

            Modalbox.show(fullUrl, {
                title: '&nbsp;',
                width: 300,
                overlayClose: false,
                afterLoad : function() {
                    $('confirmForm').observe('submit', function() {
                        var loadingBox = $('loading_box'),
                            confirmForm = $('confirmForm'),
                            deleteConfirm = $('deleteConfirm');
            
                        if (loadingBox && confirmForm) {
                            confirmForm.disable();
                            deleteConfirm.addClassName('disabled').disable();
                            loadingBox.show();
                        }
                        return true;
                    });
                }
            });
        },

        closeAndUpdate : function(container,type,id) {
            if(typeof Modalbox != 'undefined'){
              Modalbox.hide();
            }
            switch(type) {
                case "address":
                    new Ajax.Updater(container, '/account/fetchAddress?txtAddressId=' + id + '&container=' + container, {onComplete:function(){Liberty.Common.updateAccountInfo(container);Liberty.Common.showUpdated(container);},asynchronous:true,evalScripts:true});
                    break;
                case "payment":
                    new Ajax.Updater(container, '/account/fetchPayment?txtPaymentId=' + id + '&container=' + container, {onComplete:function(){Liberty.Common.updateAccountInfo(container);Liberty.Common.showUpdated(container);},asynchronous:true,evalScripts:true});
                    break;
                default:
                    break;
            }
        },

        updateInviteContainer : function(){
            $('invitationContainer').addClassName('inviteAdjust');
        },

        updateAccountInfo : function(container) {
            if($('preferred-billing') && $('preferred-shipping') && $('preferred-payment'))  {
                var preferredBilling = $('preferred-billing');
                var preferredShipping = $('preferred-shipping');
                var preferredPayment = $('preferred-payment');

                // Multiple containers can have the same className, don't change to
                // else if!
                if(container == preferredBilling.className) {
                    preferredBilling.innerHTML = $(container).innerHTML;
                    Liberty.Common.showUpdated('preferred-billing');
                }
                if(container == preferredShipping.className) {
                    preferredShipping.innerHTML = $(container).innerHTML;
                    Liberty.Common.showUpdated('preferred-shipping');
                }
                if(container == preferredPayment.className) {
                    preferredPayment.innerHTML = $(container).innerHTML;
                    Liberty.Common.showUpdated('preferred-payment');
                }
            }
        },

        cleanHighBytes : function(txtControl) {
            var v = txtControl.value,
                replaced = false;
            for (var i = 0; i < v.length; i++) {
                if (v.charCodeAt(i) > 127 ) {
                    v = v.substring(0,i) + v.substring(i+1);
                    replaced = true;
                }
            }
            if ( replaced ) {
                txtControl.value = v;
            }
        },

        showUpdated : function(container) {
            var div = $(container);
            var img = "<div id='updated-" + container + "' class='updated'>Updated</div>";
            div.insert(img);
            Effect.Fade('updated-' + container, {duration: 2, delay: 4});
        },

        hideModalboxCloseButton : function() {
            $('MB_close').hide();
        },

        /**
         * Validates via AJAX that state and zip combo is valid.
         */
        validateStateZipCombo : function(formObj, stateObjName, zipObjName) {
            var state = $F(formObj.elements[stateObjName]),
                zip = $F(formObj.elements[zipObjName]);

            //only validate if state and zip filled in
            if (state.length == 0 || zip.length == 0) {
                return false;
            }

            var parameters = {
                state: state,
                zip: zip
            };

            var isValid = false;

            new Ajax.Request('/account/validateStateZipCombo', {
                method: 'get',
                asynchronous: false, //block until this AJAX call returns
                parameters: parameters,
                onComplete: function(transport) {
                    if (!transport.request.success()) {
                        alert('An error occurred. Please reload this page and try again.'); //TODO: enhance
                        return;
                    }

                    (transport.responseText).evalScripts(); //handle session timeouts
                    var response = eval( '(' + transport.responseText + ')' );
                    if (typeof response == 'boolean') {
                        isValid = response;
                    }

                    if (!isValid) {
                        alert("That state and zip code don't match. Please check the state and zip code and try it again.");
                    }
                }
            });
            return isValid;
        },

        deviceType : function() {        
            var userAgent = navigator.userAgent,
                returnVal = {};

            if(userAgent.match(/iPhone/i)) {
                returnVal['device'] = 'iPhone';
                returnVal['type'] = 'ios';
            } else if(userAgent.match(/iPod/i)) {
                returnVal['device'] = 'iPod';
                returnVal['type'] = 'ios';
            } else if(userAgent.match(/iPad/i)) {
                returnVal['device'] = 'iPad';
                returnVal['type'] = 'ios';
            } else if(userAgent.match(/Android/i)) {
                returnVal['device'] = 'Android';
                returnVal['type'] = 'android';
            }

            return returnVal;
        }
    },

    Nav : {
        /*Show Hide Nav Menus*/
        // The reason for the delays is that ie spams us with events when we
        // move the mouse around in the menus.  If there are no delays on closing
        // then the menus are unusable on ie.  The delays on opening are to compensate
        // for the close delays and prevent mutliple menus from being displayed at
        // the same time.
        showMenu : function(id){
            el = $(id);
            if (el) {
            if (el.closeDelayTimer) window.clearTimeout(el.closeDelayTimer);
            if (el.getStyle('display') == "none" && !el.openDelayTimer) {
                el.openDelayTimer = window.setTimeout("$('"+id+"').show()", 100);
            }
            }
        },

        hideMenu : function(id){
            el = $(id);
            if (el) {
            if (el.closeDelayTimer) window.clearTimeout(el.closeDelayTimer);
            if (el.openDelayTimer) window.clearTimeout(el.openDelayTimer);
            el.openDelayTimer = null;
            el.closeDelayTimer = window.setTimeout("$('"+id+"').hide()", 100);
        }
        }
    },

    PromoReel : {
        initPromoLinks : function(){
            var quickInviteLink = $('promoQuickInviteLink'),
                reminderLink = $('promoReminderLink');

            if (quickInviteLink) {
                quickInviteLink.observe('click', this.quickInviteLinkHandler);
            }
            if (reminderLink) {
                reminderLink.observe('click', this.reminderLinkHandler);
            }
        },

        quickInviteLinkHandler : function(event){
            event.stop();
            Modalbox.show(
                '/invitation/quickInvite?' + Liberty.PromoReel.inviteQs,
                {
                    title:this.title,
                    width:950,
                    resizeDuration: 0,
                    evalScripts:true,
                    afterLoad: function() {Liberty.Common.postLoad();},
                    afterHide: function() {Liberty.Common.postUnload()}
                }
            );
        },

        reminderLinkHandler : function(event){
            event.stop();
            Modalbox.show(
                this.href,
                {
                    title:this.title,
                    width:950,
                    height: 500,
                    resizeDuration: 0
                }
            );
        }
    },

    Calendar : function () {
        var infoElems = {},
            calendar = $('comingSoonCalendar'),
            slides = $$('#calendar-content .slide'),
            controls = $$('a.carousel-control'),
            infoTemplate = new Template('<img class="calPreview" alt="#{eventName}" src="/images/content/events/#{eventId}/#{eventId}_doormini.jpg" /><header class="productName calPreview">#{eventName}</header><a class="calPreview ruePink" href="/event/promoReel/id/#{eventId}" title="#{eventName}">Preview the Boutique</a><br /><a class="rueBlue calShare" href="/invitation/quickInvite?eventId=#{eventId}&invitedTo=#{invitedTo}">Share</a><a class="rueBlue calRemind" href="/event/signUp/id/#{eventId}">Remind me</a>'),
            activeEvent = null,
            hoverTimeout = null,
            calWidth = null,
            offsetBuffer = 50,
            calendarOpts = {
                visibleSlides : 1,
                circular : false,
                initial : 0,
                duration : 0.5,
                wheel : false
            },
            
            positionInfoElem = function (eventId, pos) {
                var relOffset = pos.left - calendar.scrollLeft;
                //if the hover item is in the right hand column (of 3)
                if (relOffset > (calWidth * .66)) {
                    relOffset -= ((calWidth / 3) + offsetBuffer);
                } else {
                    relOffset += 60;
                }
                if (eventId in infoElems) {
                    infoElems[eventId].setStyle({top : (pos.top - 10) + 'px', left : relOffset + 'px'});
                }
            },
            
            showInfoElem = function (elem) {
                var eventId = elem.readAttribute('data-event');
                if (eventId && activeEvent != eventId) {
                    hideActiveElem();
                    if (eventId in infoElems === false) {
                        var eventName = elem.readAttribute('data-name'),
                            pos = elem.positionedOffset();
                            
                            var html = infoTemplate.evaluate({'eventId' : eventId, 'eventName' : eventName, 'invitedTo' : escape(eventName)});
                            infoElems[eventId] = new Element('div', { 'id': eventId, 'class' : 'calInfoElem', 'style' : 'display: none;' }).update(html);
                            positionInfoElem(eventId, pos);
                            calendar.up().appendChild(infoElems[eventId]);
                    }
                    
                    infoElems[eventId].show();
                    activeEvent = eventId;
                    infoElems[eventId].observe('mousemove', handleInfoElemMove).observe('click', handleInfoElemClick);
                    document.observe('mousemove', handleInfoElemOut);
                }
            },
            
            handleInfoElemOut = function (event) {
                var classes = event.target.className,
                    isDescendant = $(event.target).descendantOf(infoElems[activeEvent]) || classes.match('calInfoElem|calendarLink');
                if (isDescendant) {
                    event.stop();
                } else {
                    hoverTimeout = setTimeout(hideActiveElem, 150);
                }
            },
            
            handleInfoElemMove = function () {
                if (hoverTimeout) { clearTimeout(hoverTimeout); }
            },
            
            handleInfoElemClick = function (event) {
                var href,
                    anchor = Event.findElement(event, 'a');
                if (anchor) {
                    href = anchor.href;
                } else if (event.target.className.indexOf('calPreview') !== -1) {
                    href = '/event/promoReel/id/' + activeEvent;
                }
                if (href) {
                    event.stop();
                    var initScrollY = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
                    Modalbox.show(href, {width: 950, afterLoad : function () { 
                        $('MB_window').addClassName('fixed'); 
                        scrollTo(0, initScrollY); 
                    }});
                }
            },
    
            hideActiveElem = function () {
                if (activeEvent && activeEvent in infoElems) {
                    infoElems[activeEvent].hide().stopObserving('mouseout');
                    document.stopObserving('mousemove');
                    activeEvent = null;
                }
            },
            
            findEventLink = function (event) {
                return Event.findElement(event, 'a.calendarLink');
            },
            
            handleCalendarMouseMove = function (event) {
                if (hoverTimeout) { clearTimeout(hoverTimeout); }
                var elem = findEventLink(event);
                if (elem) {
                    hoverTimeout = setTimeout(function () {
                        showInfoElem(elem);
                    }, 150);
                }
            },
            
            initialize = function () {
                calendar.observe('mousemove', handleCalendarMouseMove.bind(this));
                if (slides.length > 1 && controls) {
                    new Carousel(calendar, slides, controls, calendarOpts);
                }
                calWidth = calendar.getWidth();
            };
            
            if (calendar){
                initialize.apply(this, arguments);
            }
    },
    
    Sidebar : {
        initialize : function () {
            var emailAFriendForm = $('emailAFriendForm');
            if (emailAFriendForm) {
                new Validation(emailAFriendForm, {onsubmit : true});
            }
        }
    },

    Local : {
        zipCodeInputWaterMark : null,
        zipCodeInput : null,
        initialize : function() {
            var localPreferenceForm = $('localPreference'),
                zipCodeForm = $('notifyZipCode');

            this.zipCodeInput = $('txtZipCode');
            this.getInfo();

            if (this.zipCodeInput) {
                this.zipCodeInputWaterMark = new Liberty.Control.InputWaterMark(this.zipCodeInput, this.zipCodeInput.getAttribute('title'));
            }

            if (zipCodeForm) {
                zipCodeForm.observe('submit', this.notifyMe.bindAsEventListener(this));
            }
        },

        /**
         * Updates the user zip code for city notification
         */
        notifyMe : function (event) {

            var notice = $('notice'),
                error = $('error'),
                notifyMeButton = $('notify-me-button'),
                valid = new Validation('notifyZipCode', {onSubmit:false});

            notifyMeButton.setAttribute('disabled', 'disabled');
            notifyMeButton.addClassName('disabled');

            if (notice && notice.visible()) { notice.hide(); }
            if (error && error.visible()) { error.hide(); }

            Validation.addAllThese([
                ['validate-zipcode', 'You must enter a valid zip code.', function(v) {
                    var isValid = false;

                    if ((!Validation.get('IsEmpty').test(v) && /^(\d{5})$/.test(v))) {
                        var parameters = { zip: v };
                        new Ajax.Request('/local/validateZipCode', {
                            method: 'get',
                            asynchronous: false, //block until this AJAX call returns
                            parameters: parameters,
                            onComplete: function(transport) {
                                if (transport.request.success()) {
                                    (transport.responseText).evalScripts(); //handle session timeouts
                                    var response = eval( '(' + transport.responseText + ')' );
                                    if (typeof response.results.isZipCodeValid == 'boolean') {
                                        isValid = response.results.isZipCodeValid;
                                    }
                                }
                            }
                      });
                    }
                    return isValid;
                }]
            ]);

            var result = valid.validate();

            //if all validation passed,send to server
            if(!result){        
                event.stop();
                notifyMeButton.removeAttribute('disabled');
                notifyMeButton.removeClassName('disabled');
            }
        },

        /*
         * Gets the User's local information
         */
        getInfo : function() {
            var localRegionCookie = new Liberty.Cookie('localRegionId'),
                localRegionId = localRegionCookie.get();

            if(localRegionId != null){
                //Set the Value on the Screen
                localRadio = $$("input[type=radio][name='grpLocalRegionId'][value='" + localRegionId + "']");
                if (localRadio.length > 0){
                    localRadio[0].checked = true;
                }
            }
        }
    },

    /*
     * Controls event door filtering on boutique main
     */
    BoutiqueMain : {
        filterActive : false,
        activeFilter : null,
        activeFilterClassName : 'active',
        defaultFullDoorsClassName : 'allCategories',
        filters : null,
        showOnFilter : null,
        hideOnFilter : null,
        activeElementsWrapper : null,
        inactiveElementsWrapper : null,

        /*
         * Finds and caches DOM elements, binds click behavior for categories menu
         * and filters doors if a cookie was previously set
         */
        initilizeFilterLinks : function() {
            this.filters = $('boutiqueCategories');
            if (this.filters) {
                this.hideOnFilter = $$('#halfDoors');
                this.showOnFilter = $$('#miniDoors');
                this.activeElementsWrapper = $('fullDoors');
                this.inactiveElementsWrapper = $('miniDoors');
                this.filters.observe('click', this.handleFilterLinkClick.bindAsEventListener(this));
                this.activeLink = $('allCategories');
                var boutiqueFilter = readCookie('boutiqueFilter');
                if (boutiqueFilter) {
                    var filterElement = this.filters.select('#' + boutiqueFilter);
                    if (filterElement.length > 0) {
                        this.doFilter(filterElement[0]);
                    }
                }
            }
        },

        /*
         * Click event handler for boutique category links
         */
        handleFilterLinkClick : function(event) {
            event.stop();
            var filterElement = Event.findElement(event, 'a')
            if (filterElement) {
                this.doFilter(filterElement);
            }
        },

        /*
         * Puts boutique main into 'filtering mode' view of full/mini doors
         */
        activateFilter : function() {
            this.hideOnFilter.invoke('hide');
            this.showOnFilter.invoke('show');
            this.filterActive  = true;
        },

        /*
         * Puts boutique main into the default view of full/half doors
         */
        deactivateFilter : function() {
            this.hideOnFilter.invoke('show');
            this.showOnFilter.invoke('hide');
            this.activeElementsWrapper.childElements().invoke('hide');
            this.activeElementsWrapper.select('.'+this.defaultFullDoorsClassName).invoke('show');
            this.filterActive = false;
        },

        /*
         * Finds appropriate link, marks as active. Shows full doors with
         * specified category, hides mini doors with specified category.
         * Creates cookie with selected value
         */
        doFilter : function(filter) {
            var filterId = filter.id;
            if (filter != this.activeLink) {
                this.activeLink.removeClassName(this.activeFilterClassName);
                this.activeLink = filter;
                this.activeLink.addClassName(this.activeFilterClassName);
                if (filterId == 'allCategories') {
                    this.deactivateFilter();
                    eraseCookie('boutiqueFilter');
                    return;
                }
                if (this.filterActive === false) {
                    this.activateFilter();
                }
                this.activeElementsWrapper.childElements().invoke('hide');
                this.activeElementsWrapper.select('.' + filterId).invoke('show');
                this.inactiveElementsWrapper.down().childElements().invoke('show');
                this.inactiveElementsWrapper.select('.' + filterId).invoke('hide');
                createCookie('boutiqueFilter',filterId);
            }
        }
    },
    Masthead : {
        catNavs : null,
        siteNav : null,
        myAccount : null,
        userToolsMenu : null,
        activeNav : null,
        activeLink : null,
        hideTimer : null,
        showTimer : null,
        observingMouse : false,
        initialize : function () {
            var self = this;
            
            self.catNavs = $$('.categoryBoutiques'),
            self.siteNav = $('siteNav'),
            self.myAccount = $('myAccount'),
            self.userToolsMenu = $('userToolsMenu'),
            self.activeNav = null,
            self.activeLink = null;
            
            if (self.myAccount) {
                self.myAccount.observe('mouseover', function(event) {
                    self.userToolsMenu.show();
                });
                self.myAccount.observe('mouseout', function(event) {
                    self.userToolsMenu.hide();
                });
            }

            self.siteNav.observe('mouseover', this.handleNavMouseOver.bindAsEventListener(self));
            
            //note - seems like the doc needs another sec to settle position
            setTimeout(function() {
                self.catNavs.each(function(elem) {
                    var catLink = elem.previous('.navButton');
                    if (catLink) {
                        var linkPos = catLink.positionedOffset();
                        elem.style.left = linkPos.left + 'px';
                    }
    
                });
            }, 50);
        },
        
        showFlyout : function (href) {
            var catId = href.id.substring(href.id.lastIndexOf('_')),
                catNavId = 'categoryBoutiques' + catId,
                catNav = $(catNavId),
                self = this;

            if (catNav) {
                if (self.activeNav && self.activeNav.id != catNavId) {
                    self.activeNav.hide();
                    self.activeLink.removeClassName('hover');
                }
                self.activeLink = href;
                self.activeLink.addClassName('hover');
                catNav.show();
                if (typeof catNav.scroller === 'undefined') {
                    catNav.scroller = new Control.ScrollBar(catNav.id + 'Content', catNav.id + 'Track');
                    //need to match heights - done under protest   
                    if (catNav.hasClassName('matchMenuHeights')) {
                        var maxHeight = catNav.down().getHeight(),
                            menus = catNav.select('menu');

                        menus.each(function (menu) {
                            var thisHeight = menu.getHeight();
                            if (thisHeight > maxHeight) {
                                maxHeight = thisHeight;
                            }
                        }).invoke('setStyle', { height: maxHeight + 'px' });
                    }                            
                } else {
                    catNav.scroller.scrollTo('top');
                }

                self.activeNav = catNav;
            }
        },
        
        handleNavMouseOver : function (event) {
            var self = this;
            var elem = Event.findElement(event, 'a.navButton');
            if (elem) {
                if (self.observingMouse === false) {
                    $(document).observe('mousemove', self.handleDocumentMouseMove.bindAsEventListener(self));
                    self.observingMouse = true;
                }
                if (self.showTimer !== null) {
                    clearTimeout(self.showTimer);
                    self.showTimer = null;
                }
                if (self.activeNav) {
                    self.showFlyout(elem);
                } else {
                    self.showTimer = setTimeout(function () {
                        self.showFlyout(elem);
                        self.showTimer = null;
                    }, 250);
                }
            }
        },
        
        hideActiveFlyout : function (event) {
            $(document).stopObserving('mousemove', this.handleDocumentMouseMove.bindAsEventListener(this));
            this.observingMouse = false;
            if (this.activeNav) {
                this.activeNav.hide();
                this.activeLink.removeClassName('hover');
                this.activeNav = null;
                this.activeLink = null;
            }
        },

        handleDocumentMouseMove : function (event) {
            var self = this,
                inMenu = $(event.target).descendantOf(self.siteNav) === true;

            if (inMenu === false) {
                if (self.activeNav && self.hideTimer == null) {
                    self.hideTimer = setTimeout(function () {
                        self.hideActiveFlyout.call(self);
                        self.hideTimer = null;
                    }, 500);
                } else if (self.showTimer != null) {
                    clearTimeout(self.showTimer);
                    self.showTimer = null;
                    $(document).stopObserving('mousemove', self.handleDocumentMouseMove.bindAsEventListener(self));
                    self.observingMouse = false;
                }
            } else {
                if (self.hideTimer != null) {
                    clearTimeout(self.hideTimer);
                    self.hideTimer = null;
                }
            }
        },

        parseMhiCookie : function () {
            var mastHeadInfo = {};
            mastHeadInfoCookie = new Liberty.Cookie('mastHeadInfo');
            mastHeadInfoStr = mastHeadInfoCookie.get();
            if ( mastHeadInfoStr != null ) {
                try {
                    var mastHeadInfoRoot = mastHeadInfoStr.evalJSON(),
                        mastHeadInfo = mastHeadInfoRoot.mhi[0];    
                } catch (e) {}
            }
            return mastHeadInfo;
        },
        
        /**
         * Updates my credits in masthead.
         */
        updateMyCredits : function(newCredits, mhi) {
            if (isNaN(newCredits)) {
                newCredits = 0;
            }
            try {
                var mastHeadInfo = mhi || this.parseMhiCookie();
                    if ( mastHeadInfo.cb != newCredits ) {
                        mastHeadInfo.cb = newCredits;
                        this.storeCookie(Object.toJSON(mastHeadInfoRoot));
                        return true;
                    }
                } catch (e) {
                eraseCookie('mastHeadInfo');
                }
            this.getInfo();
        },

        /**
         * Updates cart quantity in masthead.
         */
        updateCartQty : function(newQty, mhi) {
                try {
                var mastHeadInfo = mhi || this.parseMhiCookie();
                    if ( mastHeadInfo.cc != newQty ) {
                        mastHeadInfo.cc = newQty;
                        this.storeCookie(Object.toJSON(mastHeadInfoRoot));
                        return true;
                    }
                } catch (e) {
                eraseCookie('mastHeadInfo');
                }
            this.getInfo();
        },

        updateShippingWidget : function (mhi) {
            var mastheadInfo = mhi || this.parseMhiCookie();
            if ('fset' in mastheadInfo && 'fseta' in mastheadInfo) {
                var odometerDiv = $('odometer'),
                    odometerContainer = $('odometerContainer'),
                    defaultShippingContainer = $('defaultHeaderShippingMessage');
                
                if (odometerDiv && mastheadInfo.fset != 0) {
                    if (defaultShippingContainer) { defaultShippingContainer.hide(); }
                    if (odometerContainer) { odometerContainer.show(); }
                    [defaultShippingContainer,odometerContainer].invoke('setStyle','visibility:visible;');
                    var daysRemaining = Liberty.Common.daysRemaining(mastheadInfo.fset),
                        doAnimate = mastheadInfo.fseta;
                    if (daysRemaining > 29) {
                        daysRemaining = 30;
                        doAnimate = false;
                    }
                    Liberty.Odometer(daysRemaining, doAnimate);
                    if(mastheadInfo.fseta === true) {                    
                        mastheadInfo.fseta = false;
                        createCookie('mastHeadInfo', Object.toJSON({'mhi' : new Array(mastheadInfo)}));
                    }
                    
                } else {
                    if (defaultShippingContainer) { defaultShippingContainer.show(); }
                    if (odometerContainer) { odometerContainer.hide(); }
                    [defaultShippingContainer,odometerContainer].invoke('setStyle','visibility:visible;');
                }
            }
        },

        getAjax : function() {
            var self = this,
                uid = getCookie('uid');
            if ( uid == null ) {
                window.location.href = '/access/logout';
                return false;
            }
            new Ajax.Request(
                '/access/mastheadInfo/userId/' + uid,
                {
                    method:'get',
                    requestHeaders: {Accept: 'application/json'},
                    onSuccess: function(transport) {
                        self.storeCookie(transport.responseText);
                    }
                }
            );
        },

        storeCookie : function(response) {
            if ( response != null ){
                createCookie('mastHeadInfo',response);
                this.getInfo();
            }
        },

        updateNav : function(isLocalEvent) {
            if(isLocalEvent) {
                var boutiques = $('boutiques'),
                    local = $('local');
                if (boutiques) {
                    boutiques.removeClassName('navEventOn');
                    boutiques.addClassName('navEvent');
                }
                if (local) {
                    local.removeClassName('navLocal');
                    local.addClassName('navLocalOn');
                }
            }
        },

        getInfo : function() {
            var isMobile = ($('isMobile') && $('isMobile').value =='true') ? true : false,
                mastHeadInfoStr = getCookie('mastHeadInfo'),
                mastheadInfo = null;

            if ( mastHeadInfoStr != null && mastHeadInfoStr != '' ) {
                mastheadInfo = mastHeadInfoStr.evalJSON().mhi[0];
            }

            if ( mastheadInfo == null || mastheadInfo.cc == null ) {
                Liberty.Masthead.getAjax();
            } else {
                if(!isMobile){
                    this.updateShippingWidget(mastheadInfo);
                }
            
                this.getServerTimeOffset( mastheadInfo );
                var mhGreeting = $('mh_greeting'),
                    myCredits = $('myCredits'),
                    previewIndicator = $('mh_preview_indicator'),
                    cartCount = Liberty.Masthead.getCartItemQty(mastheadInfo),
                    cartCountDom = $('cartCount'),
                    cart = $('cart'),
                    myBag = $('myBag'),
                    fmtCreditBalance = Liberty.Common.getDisplayCredits((mastheadInfo.cb/100).toFixed(2));

                if (mhGreeting) {
                    var greeting = mastheadInfo.fn;
                    mhGreeting.update(greeting).innerHTML;
                }

                //Set the values to the appropriate divs.
                if (myCredits) { myCredits.update(fmtCreditBalance).innerHTML; }
                if (previewIndicator) { previewIndicator.update((mastheadInfo.ss == mastheadInfo.uid) ? '*' : '').innerHTML; }
                if (cartCountDom) { cartCountDom.update( cartCount ).innerHTML; }
                if (cartCount==0){
                    if (cart) { cart.addClassName('zero shoppingBagInActive'); }
                    if (myBag) { myBag.addClassName('zero'); }
                } else {
                    if (cart) {
                        cart.removeClassName('zero shoppingBagInActive');
                        cart.addClassName('shoppingBagActive');
                    }
                    myBag.removeClassName('zero');
                }

                cartUri = ( cartUri == null )?'/cart':cartUri;

                /*
                * skodam: Removed the condition for NOT mobile;
                *  because the checkout button is removed from the master header in web
                *  and is required only for mobile version
                */
                if(isMobile){
                    var addToBag = $('addToBag');
                    if (addToBag) {
                        if(cartCount == 0){
                            addToBag.removeClassName('accent').addClassName('cancel').setAttribute('href', '#');
                        }else{
                            addToBag.removeClassName('cancel').addClassName('accent').setAttribute('href', '/cart');
                        }
                    }
                }
            }
        },

        getServerTimeOffset : function(mastHeadInfo ) {
            var clientDate = new Date(),
                stOffset = getCookie('stos');
            if ( stOffset != parseInt(stOffset) ) {
                var rllTS = mastHeadInfo.ts,
                    clientTS = clientDate.getTime(),
                    rllDate = new Date();
                rllDate.setTime( rllTS );
                var stOffset = rllDate - clientDate;
                createCookie('stos', stOffset );
            }
            Liberty.ServerTimeOffset = ( parseInt(stOffset) == stOffset ) ? parseInt(stOffset) : 0;
        },

        getCartItemQty : function(mastHeadInfo){
            if (!mastHeadInfo || mastHeadInfo == null) {
                var mastHeadInfoStr = getCookie('mastHeadInfo');
                if ( mastHeadInfoStr == null ) {
                    Liberty.Masthead.getAjax();
                    mastHeadInfoStr = getCookie('mastHeadInfo');
                }
                mastHeadInfo = mastHeadInfoStr.evalJSON().mhi[0];
            }
            var cartCount = parseFloat(mastHeadInfo.cc);
            cartCount = isNaN(cartCount)?0:cartCount;
            return cartCount;
        }
    },

    Signup : {
        signUpForm : null,
        signUpFormValidator : null,
        
        initializeReminderForm : function () {
            this.signUpForm = $('signUpForm');
            if (this.signUpForm) {
                this.signUpForm.observe('submit', this.validateFeedbackForm.bindAsEventListener(this));
                this.signUpFormValidator = new Validation('signUpForm', {onsubmit: false});
            }
        },
        
        validateFeedbackForm : function (event) {
            event.stop();
            Liberty.Common.toggleBttn('setRemindersSubmit');
            var checkedCheckboxes = $$('.chkEmail:checked, .chkSMS:checked'),
                errorMsg = $('signupFormError');
            if (checkedCheckboxes.length === 0 || !this.signUpFormValidator.validate()) {
                if (errorMsg) {
                    errorMsg.show();
                    try {
                        Modalbox.resizeToContent();
                    } catch(e) {};
                }
                Liberty.Common.toggleBttn('setRemindersSubmit');
            } else {
                if (errorMsg) {
                    errorMsg.hide();
                    try {
                        Modalbox.resizeToContent();
                    } catch(e) {};
                }
                new Ajax.Updater('signUpContainer', '/event/processSignUp', {
                    asynchronous:true, 
                    evalScripts:true, 
                    parameters:Form.serialize(this.signUpForm)
                });
            }
        },

        chkAllEmail : function() {
            $$('.chkEmail').each(function(obj) {obj.checked=true});
        },

        chkAllSMS : function(defMobilePhone) {
            $$('.chkSMS').each(function(obj) {obj.checked=true});
            Liberty.Signup.showHideReqMobilePhoneContainer(defMobilePhone);
        },

        showHideReqMobilePhoneContainer : function(defMobilePhone) {
            var hasSms = false;
            $$('.chkSMS').each(function(obj) {if (obj.checked) hasSms=true});
            if (hasSms) {
                //reset to stored value
                $('txtMobilePhone').setValue(defMobilePhone);
                $('reqMobilePhoneContainer').show();
            } else {
                //clear before hiding so value is not submitted
                $('txtMobilePhone').clear();
                $('reqMobilePhoneContainer').hide();
            }
        },

        /**
         * Toggles between the WOM and get on the list forms
         */
        showDivInvitedBy : function() {
            var divReferredBy = $('divBecomeMember');
            if (divReferredBy) {
                divReferredBy.setStyle({
                    display : 'block'
                });
                if ($('MB_window')) Modalbox.resizeToContent();
            }
        },

        showDivBecomeMember : function() {
            var divBecomeMember = $('divBecomeMember');
            if (divBecomeMember) {
                divBecomeMember.setStyle({
                    display : 'block'
                });
                Liberty.Signup.initReferrerSignupForm();
            }
            if ($('MB_window')) Modalbox.resizeToContent();
        },

        initReferrerSignupForm : function() {
            var referrerSignupForm = $('referredForm');
            if (referrerSignupForm) {
                referrerSignupForm.stopObserving();
                window.modalValidatorReferred = new Validation('referredForm', {onSubmit : false});
                referrerSignupForm.observe(
                    'submit',
                    Liberty.Signup.handleReferrerSignupFormSubmit.bindAsEventListener(this,referrerSignupForm)
                );
            }
        },
        handleReferrerSignupFormSubmit : function(event,referrerSignupForm) {
            event.stop();
            Liberty.Common.toggleBttn('referredFormSubmit');
            if (!window.modalValidatorReferred.validate()) {
                Liberty.Common.toggleBttn('referredFormSubmit');
                return false;
            } else {
                new Ajax.Updater(
                    'MB_content',
                    '/access/referrerSignup',
                    {
                        asynchronous : true,
                        evalScripts : true,
                        onComplete : function(request, json){
                            Liberty.Signup.showDivInvitedBy();
                        },
                        parameters : Form.serialize(referrerSignupForm)
                    }
                );
            }
        },
        initAddToWaitListForm : function() {
            var waitingListForm = $('addToWaitList');
            if (waitingListForm) {
                waitingListForm.stopObserving();
                window.modalValidator = new Validation('addToWaitList', {onSubmit : false});
                waitingListForm.observe(
                    'submit',
                    Liberty.Signup.handleAddToWaitListFormSubmit.bindAsEventListener(this,waitingListForm)
                );
            }
        },
        handleAddToWaitListFormSubmit : function(event,waitingListForm) {
            event.stop();
            Liberty.Common.toggleBttn('addToWaitListSubmit');
            if (!window.modalValidator.validate()) {
                Liberty.Common.toggleBttn('addToWaitListSubmit');
                return false;
            } else {
                var loadingBox = $('loading_box2');
                new Ajax.Updater(
                    'MB_content',
                    '/access/addToWaitList',
                    {
                        asynchronous : true,
                        evalScripts : true,
                        onComplete : function(request, json){
                            if (loadingBox) {
                                loadingBox.hide();
                            }
                            Liberty.Signup.showDivBecomeMember();
                        },
                        onLoading : function(request, json){
                            if (loadingBox) {
                                loadingBox.show();
                            }
                        },
                        parameters : Form.serialize(waitingListForm)
                    }
                );
            }
        },
        welcomeModal : function() {
            if ( getCookie('newMember') == 'true' ){
                Modalbox.show(
                    '/common/newMember',
                    {
                        title:'&nbsp;',
                        width:740,
                        slideDownDuration:0,
                        afterLoad : function(){
                  					var modalElement = document.getElementById('rondavu_modal_container');
                  					var modalApp = document.getElementById('rondavu_modal_app');
                  					if(modalApp != null && modalElement != null){
                  						  modalElement.appendChild(modalApp);
                  					}
                  					Modalbox.resizeToContent();
              					}
                     }
                );
                eraseCookie('newMember');
            }
            
        },
        initWaitingListLink : function() {
            var waitingListLink = $('waitingListLink');
            if (waitingListLink) {
                waitingListLink.observe('click',function(event) {
                    event.stop();
                    Modalbox.show(
                        waitingListLink.href,
                        {
                            title     : waitingListLink.title,
                            width     : 913,
                            height    : 475,
                            afterLoad : Liberty.Signup.showDivBecomeMember
                        }
                    );
                    return false;
                });
            }
        }
    },
    
    
    Feedback : {
        feedbackForm : null,
        formValidator : null,
        initialize : function () {
            this.feedbackForm = $('feedbackForm');
            if (this.feedbackForm) {
                this.feedbackForm.observe('submit', this.validateFeedbackForm.bindAsEventListener(this));
                this.formValidator = new Validation('feedbackForm', {onsubmit: false});
            }
        },
        validateFeedbackForm : function (event) {
            Liberty.Common.toggleBttn('feedbackFormSubmit');
            if (!this.formValidator.validate()) {
                event.stop();
                Liberty.Common.toggleBttn('feedbackFormSubmit');
            } else {
                new Ajax.Updater('feedbackFormContainer', '/common/processFeedback', {
                    asynchronous : true, 
                    evalScripts  : false, 
                    parameters   : Form.serialize(this.feedbackForm)
                });
            }
        }
    },

    Cookie : function(name) {
        this.name = name;
        this.get = function() {
            return getCookie(this.name);
        };
        this.set = function(value, days) {
            createCookie(this.name, value, days);
        };
        this.erase = function() {
            this.set("", -1);
        }
    },

    Cookies   : {},

    Factories : {
        Cookie : function(name, value) {
            if (value != null) {
                var cookie = new Liberty.Cookie(name);
                cookie.set(value);
                return cookie;
            }
            return new Liberty.Cookie(name);
        }
    },

    /**
     * QuickBuy messaging API.
     *
     * clear()
     *   Removes all messages and hides the container.
     *
     * list()
     *   Returns the set of messages currently being displayed.
     *
     * permanent(message[, id])
     *   Sets a permanent message and returns the CSS Id of the message.
     *
     * remove(id)
     *   Removes a message with a given CSS Id, and hides the message container if it's empty.
     *
     * transient(message[, id, timeout])
     *   Sets a temporary message and returns the CSS Id of the message.  If timeout is not specified,
     *   the message will expire after 5 seconds.
     */
    Message : {
        genericError : 'An unexpected error has occurred, please try again.',
        /**
         * Returns a randomized CSS Id for messages.
         *
         * @return string
         */
        _id : function() {
            return 'msg'+Math.floor(Math.random() * 8192);
        },
        /**
         * Adds a message to the message container and displays the container if it's hidden.
         *
         * @param string message
         * @param string id
         * @param string type
         */
        _message : function(message, id, type) {
            var div = $('errorMessages');
            div.innerHTML += '<div id="'+id+'" class="error errorMessage '+type+'">'+message+'</div>';
            if (Liberty.Common.isHidden(div)) {
                Liberty.Common.show(div);
            }
        },
        /**
         * Removes all messages from the container.
         */
        clear : function() {
            Liberty.Message.list().each(function(x) {
                Liberty.Message.remove(x.id);
            });
        },
        /**
         * Returns the set of messages currently being displayed.
         *
         * @return object
         */
        list : function() {
            return $$('.errorMessage');
        },
        /**
         * Sets a permanent message and returns the CSS Id of the message.
         *
         * @param string message
         * @param string id = null
         * @return string
         */
        permanent : function(message, id) {
            var id = id || Liberty.Message._id();
            if ($(id)) {
                Liberty.Message.remove(id);
            }
            Liberty.Message._message(message, id, 'permanent');
            return id;
        },
      /**
       * Removes a message with a given CSS Id, and hides the message container if it's empty.
       *
       * @param string id
       */
      remove : function(id) {
          if ($(id)) {
              $(id).remove();
              if (Liberty.Message.list().length == 0) {
                  Liberty.Common.hide($('errorMessages'));
              }
          }
      },
      /**
       * Sets a temporary message and returns the CSS Id of the message.  If timeout (in milliseconds)
       * is not specified, the message will expire after 5 seconds.
       *
       * @param string message
       * @param string id = null
       * @param string timeout = null
       * @return string
       */
      'transient' : function(message, id, timeout) {
          var id = id || Liberty.Message._id();
          Liberty.Message._message(message, id, 'transient');
          setTimeout('Liberty.Message.remove("'+id+'")', timeout || 5000);
          return id;
      }
    },

    Messages  : {},

    URIs      : {},

    simpleTip : function(tipElement,contentElement,contentTitle,event,offsets){
        if (tipElement && contentElement) {
            var viewport = document.viewport.getDimensions(),
                eventX = (typeof event != 'undefined' && event != null) ? Event.pointerX(event) : 0,
                eventY = (typeof event != 'undefined' && event != null) ? Event.pointerY(event) : 0,
                existingTip = $('simpleTip'),
                title = contentTitle || '',
                tipWidth = contentElement.getWidth() + 20,
                tipHeight = contentElement.getHeight(),
                tipLeft = typeof offsets != 'undefined' && 'x' in offsets ? eventX + offsets.x : 0,
                tipTop = typeof offsets != 'undefined' && 'y' in offsets ? eventY + offsets.y : 0,
                tipTemplate = new Template('<div id="simpleTip" class="prototip highest" style="z-index: 99999; width: #{tipWidth}px; visibility: visible; height: #{tipHeight}px; left: #{tipLeft}px; top: #{tipTop}px; position:absolute;"><div class="tooltip" style=""><div class="toolbar" style="width: #{toolBarWidth}px;"><div class="title"><a href="javascript:;" onclick="$(\'simpleTip\').hide();" class="close"></a>#{tipTitle}<div style="clear: both;"></div></div></div><div class="content" id="simpleTipContent">#{tipContent}<div style="clear: both;"></div></div></div></div>');

                if (tipWidth + tipLeft > viewport.width) {
                    tipLeft = tipLeft - (tipWidth + tipLeft - viewport.width) - 20;
                }

                if (tipLeft < 20) {
                    tipLeft = 20;
                }

                if (tipTop < 20) {
                    tipTop = 20;
                }

                var tipHtml = tipTemplate.evaluate({
                    'tipWidth' : tipWidth,
                    'tipHeight' : tipHeight,
                    'tipLeft' : tipLeft,
                    'tipTop' : tipTop,
                    'toolBarWidth' : tipWidth,
                    'tipTitle' : title,
                    'tipContent' : contentElement.innerHTML
                });
                if (existingTip) {
                    existingTip.replace(tipHtml);
                } else{
                    $(document.body).insert(tipHtml);
                }
        }
    },
    PayPal : {
        defaultErrorText : 'We are experiencing problems processing this order through PayPal, please try again.',
        requestInProgress : false,
        initPayPalButton : function() {
            var self = this;
            $$('.paypalCheckout').each(function(a){
                a.observe('click', self.payPalButtonHandler);
            })
        },
        payPalButtonHandler : function(event) {
            event.stop();
            var self = Liberty.PayPal;
            if (self.requestInProgress === false) {
                self.requestInProgress = true;
                var elem = Event.findElement(event, 'a'),
                    url = elem.href,
                    loadingModal = $('loadingModalPaypal');

                if (!loadingModal) {
                    loadingModal = '/common/loadingModalPaypal';
                }

                Modalbox.show( loadingModal
                               , { width:376
                                   , overlayClose: false
                                   , beforeLoad: function () {$('MB_header').hide();}
                                   , onUpdate: function() { Liberty.Common.hideModalboxCloseButton() }
                                 }
                             );

                new Ajax.Request(url,
                {
                  method:'get',
                  onSuccess: function(transport){
                      var response = transport.responseText || self.defaultErrorText;
                      if(-1 != response.indexOf('<form')) {
                          document.body.insert({'bottom' : response});
                          $('paypalInitForm').submit();
                      } else {
                          self.showPayPalError.call(self,response);
                      }
                  },
                  onFailure: function(){
                      self.showPayPalError.call(self);
                  }
                });
            }
        },
        showPayPalError : function(message) {
            if(-1 == window.location.href.indexOf('/checkout')) {
                window.location.href = '/cart';
            } else {
                var errorTxt = typeof message == 'undefined' ? this.defaultErrorText : message;
                Modalbox.hide();
                this.requestInProgress = false;
                $('error').update(errorTxt).show();
            }
        }
    },
    AccountModals : {
        initializeEditAccount : function() {
            var editAccountForm = $('updateUser');
            if (editAccountForm) {
                editAccountForm.observe('submit', this.validateAccountForm.bindAsEventListener(this));
                this.validForm = new Validation('updateUser', {onsubmit : false});
            }
            this.addAccountValidators();
        },
        addAccountValidators : function () {
            Validation.addAllThese([
                ['validate-password', 'Your password cannot be less than 6 <br/>or more than 12 characters in length.', {
                    maxLength : 12,
                    minLength : 6
                }],
                ['validate-mobile-AreaCode', 'Your number must be exactly 3 digits.', function(v) {
                    if (Validation.get('IsEmpty').test(v)) {
                        return true;
                    } else {
                        return v.length >= 3
                    }
                }],
                ['validate-mobile-Prefix', 'Your number must be exactly 3 digits.', function(v) {
                    if (Validation.get('IsEmpty').test(v)) {
                        return true;
                    } else {
                        return v.length >= 3
                    }
                }],
                ['validate-mobile-LineNumber', 'Your number must be exactly 4 digits.', function(v) {
                    if (Validation.get('IsEmpty').test(v)) {
                        return true;
                    } else {
                        return v.length >= 4
                    }
                }],
                ['validate-zipCode', 'Your Zip Code must be at least 5 digits.', function(v) {
                    if (Validation.get('IsEmpty').test(v)) {
                        return true;
                    } else {
                        return v.length >= 5
                    }
                }],
                ['validate-password-confirm', 'Your confirmation password does not match <br/>your first password, please try again.', {
                    equalToField : 'txtPassword'
                }],
                ['validate-email-confirm', 'The email addresses entered do not match.', {
                    equalToField : 'txtEmail'
                }]
            ]);
        },
        validateAccountForm : function() {
            Liberty.Common.toggleBttn('userFormSubmit');
            Liberty.Common.startLoading();
            var result = this.validForm.validate();
            //if all validation passed, erase mastHeadInfo cookie and allow form to submit
            if(result){
                eraseCookie('mastHeadInfo');
                this.validForm = null;
            } else {
                Liberty.Common.stopLoading();
                Liberty.Common.toggleBttn('userFormSubmit');
            }
        },
        initializeAddressForm : function(addressType, newAddress) {
            var addressForm = $('addressForm');
            if (addressForm) {
                addressForm.observe('submit', this.validateAddressForm.bindAsEventListener(this, addressForm, addressType, newAddress));
                this.validForm = new Validation('addressForm', {onSubmit : true});
                this.addAccountValidators();
            }
        },
        validateAddressForm : function(event, addressForm, addressType, newAddress) {
            Liberty.Common.toggleBttn('addressFormSubmit');
            Liberty.Common.startLoading();
            if (!this.validForm.validate() || !Liberty.Common.validateStateZipCombo(addressForm, addressType + 'State', addressType + 'ZIP')) {
                event.stop();
                Liberty.Common.stopLoading();
                Liberty.Common.toggleBttn('addressFormSubmit');
            } else if (newAddress === false) {
                event.stop();
                this.validForm = null;
                new Ajax.Updater(
                    'responseDiv',
                    '/account/updateAddress',
                    {
                        asynchronous:true,
                        evalScripts:true,
                        parameters:Form.serialize(addressForm)
                    }
                );
            }
        },
        initializeCreditCardForm : function(newPayment) {
            var creditCardForm = $('paymentForm');
            if (creditCardForm) {
                creditCardForm.observe('submit', this.validateCreditCardForm.bindAsEventListener(this, creditCardForm, newPayment));
                this.validForm = new Validation('paymentForm', {onSubmit : true});
            }
        },
        validateCreditCardForm : function(event, creditCardForm, newPayment) {
            Liberty.Common.toggleBttn('paymentFormSubmit');
            Liberty.Common.startLoading();
            if (!this.validForm.validate()) {
                event.stop();
                Liberty.Common.stopLoading();
                Liberty.Common.toggleBttn('paymentFormSubmit');
            } else if (newPayment === false) {
                event.stop();
                this.validForm = null;
                new Ajax.Updater(
                    'responseDiv',
                    '/account/updatePaymentInfo',
                    {
                        asynchronous:true,
                        evalScripts:true,
                        parameters:Form.serialize(creditCardForm)
                    }
                );
            }
        }
    }
});


// quick function to determine ie version (if any), borrowed largely from jQuery
(function() {
    var userAgent = navigator.userAgent.toLowerCase(),
        browser = {
            ie: /msie/.test(userAgent) && !/opera/.test(userAgent),
            mozilla: /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent),
            opera: /opera/.test(userAgent),
            safari: /webkit/.test(userAgent),
            version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1]
        };

    browser.ie6 = (browser.ie === true && browser.version == '6.0') ? true : false;
    Liberty.Browser = browser;
})();

/* Observer and Observable are different. Observer is a broker for events, Observable is
 * a set of methods grafted onto other classes that enables the receiving class to
 * interact with other objects in a loosely coupled manner
 */

Liberty.Observer = {
    listeners: {},
    bind : function(eventName, handler, scope){
        var definition = {
            eventName: eventName,
            handler: handler,
            scope: (scope || window)
        };
        if (eventName in this.listeners){
            this.listeners[eventName].push(definition);
        }else{
            this.listeners[eventName] = [ definition ];
        }
    },
    trigger : function(eventName){
        var i = 0,
            args = arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [],
            listeners = this.listeners;
        if (eventName in listeners){
            var listener = listeners[eventName],
                i = listener.length;

            while(i--){
                var that = listener[i];
                if(typeof that.handler == 'function'){
                    that.handler.apply(that.scope, args);
                }
            }
        }
    },
    clear : function(eventName){
        if(typeof eventName != 'undefined' && eventName in this.listeners){
            this.listeners[eventName].length = 0;
        }else{
            this.listeners = {};
        }
    },
    clearGroup : function(group){
        var re = new RegExp("^"+group),
            listener;
        for(listener in this.listeners){
            if(re.test(group)){
                this.listeners[listener].length = 0;
            }
        }
    }
};

Liberty.Common.Observable = Class.create((function(){
    function initialize(){
        this.eventHash = {};
    }

    function addListener(key, func){
        if (!this.eventHash[key]) {
          this.eventHash[key] = [];
        }
        this.eventHash[key].push(func);
    }

    function hasListener(key){
        return !!this.eventHash[key];
    }

    function removeListener(type, listener){
        if(!this.hasListener(type)) {
            return false;
        }
        if (!listener) {
            this.eventHash[type] = [];
        }
        for (var i = 0, len = this.eventHash[type].length; i < len; i++) {
            if (this.eventHash[type][type][i] == listener) {
                this.eventHash[type][type].splice(i, 1);
            }
        }

    }

    function dispatchEvent(type, arg){
        if(!this.hasListener(type)) {
            return false;
        }
        try {
            this.eventHash[type].any(function(f){
              var retval = f(arg);
              return (retval == false ? true : false);
            });
        } catch (e) {}
    }

    function purgeListeners(){
        this.eventHash = {};
    }

    return {
        initialize     : initialize,
        addListener    : addListener,
        on             : addListener,
        hasListener    : hasListener,
        dispatchEvent  : dispatchEvent,
        fire           : dispatchEvent,
        fireEvent      : dispatchEvent,
        removeListener : removeListener,
        un             : removeListener
    }
})());

Ajax.Responders.register({
    onCreate : Liberty.Common.startLoading,
    onComplete : Liberty.Common.stopLoading
});

/* cart-related JavaScript; needs to be "common" due to modal cart in masthead */
var cartJs = {
    shippingZip: null,
    modalCartItemForms : null,
    qtyControls : null,
    removeItemLinks : null,
    exitActions : null,
    editActions : null,
    defaultShipping : 1034,
    gfcShipping : 1046,
    
    initialize : function (opts) {
        var options = Object.extend({ shippingAlert : false}, opts || {}),
            shExplainTipText = $('shExplainTipText'),
            shExplainTip = $('shExplain'),
            returnsTipText = $('returns'),
            returnsTip = $('returnsLink'),
            fadeShipAlert = $('flatShippingRateAlert'),
            flatRateNotChosen = $('flatRateNotChosenMessage'),
            shippingMessages = $('shippingMessagesRow');

        this.exitActions = $$('.cartExitAction');
        this.editActions = $$('.cartEditAction');

        if (options.shippingAlert === true && fadeShipAlert) {
            new Effect.Fade(fadeShipAlert, {duration: 2, delay: 3});

            if (options.shippingMethod != cartJs.defaultShipping && flatRateNotChosen && shippingMessages) {
                flatRateNotChosen.show();
                new Effect.Appear(shippingMessages, {duration: 2, delay: 0});
            }
        }
        
        if (shExplainTipText && shExplainTip) {
            new Tip(shExplainTip, shExplainTipText.innerHTML, {
                title : 'About Additional Shipping &amp; Handling', 
                showOn: 'click', 
                viewport: true, 
                offset: {x:-520, y:0}, 
                hideOn: {element: '.close', event: 'click'}, 
                closeButton: true});
        }
        if (returnsTipText) {
            new Tip(returnsTip, returnsTipText.innerHTML, {
                title : 'Returns', 
                showOn: 'click', 
                offset: {x:0, y:-100}, 
                hideOn: {element: '.close', event: 'click'}, 
                closeButton: true});
        }

        if (this.exitActions.length > 0) {
            this.exitActions.invoke('observe', 'click', this.protectExitActions.bindAsEventListener(this));
        }

        cartJs.initCartItemForms();
        cartJs.initShippingMethodsZipForm();
        Liberty.PayPal.initPayPalButton();
    },
    
    protectExitActions : function (event) {
        event.stop();
        var link = Event.element(event),
            href = link.href;
        this.disableExitAction(link);
        this.disableCartActions();
        document.location.href = href;
    },
    
    disableExitAction : function (elem) {
        if (typeof elem.href != 'undefined') {
            elem.removeAttribute('href');
            elem.addClassName('disabled');
        } else if (elem.nodeName === 'select' || elem.nodeName === 'input') {
            elem.disable();
        }
    },
    
    disableCartActions : function () {
        this.editActions.invoke('addClassName', 'disabledContent');
        this.exitActions.each(this.disableExitAction);
    },
    
    findCartItemElements : function() {
        cartJs.modalCartItemForms = $$('.modalCartItemForms');
        cartJs.qtyControls = $$('.quantityCtrl');
        cartJs.removeItemLinks = $$('.removeItemLink');
    },
    resetCartItemElements : function() {
        cartJs.removeItemLinks.invoke('stopObserving');
        cartJs.modalCartItemForms.invoke('stopObserving');
        cartJs.qtyControls.invoke('stopObserving');
        cartJs.modalCartItemForms = cartJs.qtyControls = cartJs.removeItemLinks = null;
    },
    initCartItemForms : function() {
        cartJs.findCartItemElements();
        if (cartJs.modalCartItemForms.length > 0) {
            cartJs.modalCartItemForms.invoke('observe', 'submit', cartJs.handleCartItemFormSubmit);
        }
        if (cartJs.qtyControls.length > 0) {
            cartJs.qtyControls.invoke('observe', 'change', cartJs.handleQtyControlChange);
        }
        if (cartJs.removeItemLinks.length > 0) {
            cartJs.removeItemLinks.invoke('observe', 'click', cartJs.handleRemoveItemLinkClick);
        }
    },
    initShippingMethodsZipForm : function () {
            var zipForm = $('shipMethodAjax');
            if (zipForm) {
                zipForm.observe('submit', this.handleShippingMethodsZipFormSubmit.bindAsEventListener(this, zipForm));
                this.validZipForm = new Validation(zipForm, {onSubmit : true});
                Validation.addAllThese([
                    ['validate-shipzipcode', 'You must enter a valid zip code.', function(v) {
                        return (!Validation.get('IsEmpty').test(v) && /^(\d{5})$/.test(v));
                    }]
                ]);
            }
    },
    handleShippingMethodsZipFormSubmit : function (event, zipForm) {
        event.stop();
        if (this.validZipForm.validate()) {
            new Ajax.Updater(
                'shippingContainer', 
                '/cart/findShippingMethods', 
                {asynchronous:false, evalScripts:true, parameters:Form.serialize(zipForm)}
            );
        }
    },
    handleRemoveItemLinkClick : function(event) {
        event.stop();
        var link = Event.element(event);
        if (link.hasClassName('disabledContent') === false) {
            cartJs.disableCartActions();
            link.style.visibility = 'hidden';
            var linkIndex = link.id.replace('removeItemLink',''),
                itemForm = $('item_form_' + linkIndex);
            $('item_form_' + linkIndex).quantity.value = '0';
            $('quantitySpinner' + linkIndex).show();
            window['cart_cd' + linkIndex] = null;
            if (itemForm.hasClassName('modalCartItemForms')) {
                cartJs.resetCartItemElements();
                cartJs.handleCartItemFormSubmit(itemForm);
            } else {
                itemForm.submit();
            }
        }
    },
    handleQtyControlChange : function(event) {
        event.stop();
        var qtySelector = Event.element(event),
            itemForm = $(qtySelector.form),
            itemIndex = qtySelector.id.replace('qtySelector','');
        if (qtySelector.hasClassName('disabledContent') === false) {
            cartJs.disableCartActions();
            qtySelector.disable();
            qtySelector.form.quantity.value = $F(qtySelector);
            $('quantitySpinner' + itemIndex).show();
            if (itemForm.hasClassName('modalCartItemForms')) {
                cartJs.resetCartItemElements();
                cartJs.handleCartItemFormSubmit(itemForm);
            } else {
                itemForm.submit();
            }
        }
    },
    handleCartItemFormSubmit : function(itemForm) {
        new Ajax.Updater(
            'MB_content',
            '/cart/updateCart', {
                asynchronous : true,
                evalScripts : true,
                parameters : Form.serialize(itemForm)
            }
        );
    },

    shippingChangeHandler: function() {
        $('shippingTemplateContainer').show();
        $('shippingContainer').hide();
        loadingBoxId = 'loading_box';
        // $('shippingContainer').innerHTML = $('shippingTemplateContainer').innerHTML;
        var tempArr = document.getElementsByName('shippingZip'); //need to get Elements by name since template has same control
        for (var i = 0; i < tempArr.length; i++) {
            tempArr[i].value = this.shippingZip;
        }
        $('shippingSelector').show();
    },

    findShippingMethodsCallback: function(shippingMethods, shippingZip) {
        //no need to do anything; callback for debug only
    },

    shippingMethodClickHandler: function(control) {
        if (control.form.onsubmit()) {
            control.form.submit();
        }
    },

    shippingMethodChangeHandler: function(control,zip, firstHide) {

        if($('selectedShippingMethod')) {
            $('selectedShippingMethod').disable();
            $('shippingMethodsLoadingIndicator').show();
        }

        if (firstHide == undefined){
            firstHide = false;
        }

        new Ajax.Updater('response',
                     '/cart/updateTaxAndShipping?shippingZip=' + zip + '&shippingMethod=' + control + '&disableFirstHide=' + firstHide,
                     {onComplete: function() {
                         if ($('shippingMethodsLoadingIndicator')) $('shippingMethodsLoadingIndicator').hide();
                         if ($('selectedShippingMethod')) $('selectedShippingMethod').enable();
                      },
                      asynchronous: true,
                      evalScripts: true});
    },

    rebuildShippingMethods: function(zip, selectedShippingMethod) {

        if($('selectedShippingMethod')) {
              $('selectedShippingMethod').disable();
              $('shippingMethodsLoadingIndicator').show();
        }
        new Ajax.Updater('shippingMethodDropDown',
                         '/checkout/updateShipping?shippingZIP=' + zip + "&selectedShippingMethod=" + selectedShippingMethod,
                         {onComplete: function(){
                          if ( $('shippingMethodsLoadingIndicator') ) {
                            $('shippingMethodsLoadingIndicator').hide();
                          }
                          if ( $('selectedShippingMethod') ) {
                                     $('selectedShippingMethod').enable();
                          }
                          },
                          asynchronous: true,
                          evalScripts: true});
    },

    /*Cart...Hide special messages if user clicks on change shipping */
    chkMsgs : function(){
        if($('flatShippingRateAlert')!=null) {
            $('flatShippingRateAlert').hide();
        }
    },

    updateTaxAndShippingCallback: function(cart, disableFirstHide) {
        // Hide any previous shipping messages
        try {
            if (!disableFirstHide) {
                $('flatRateNotChosenMessage').hide();
                $('flatRateExpiredError').hide();
                $('shippingMessagesRow').hide();
            } else {
                disableFirstHide=false;
            }
        }
        // Modal throws errors because it can't find disableFirstHide
        // This just makes sure this doesn't hurt things.
        catch(err){
          var disableFirstHide = false;
        }

        $('orderSubtotalContainer').innerHTML = Liberty.Common.getDisplayPrice(cart.orderSubtotal);
        $('taxContainer').innerHTML = Liberty.Common.getDisplayPrice(cart.tax);
        new Effect.Highlight('taxContainer', {duration: 4});
        $('shippingCostContainer').innerHTML = Liberty.Common.getShippingDisplayPrice(cart.totalShippingRate);
        new Effect.Highlight('shippingCostContainer', {duration: 4});

        // If a user is flate rate eligible they can still get a shipping code of "1034" (cartJs.defaultShipping)
        // which is standard. It means that even though the user is eligible one or many
        // products in the cart can't be consolidated. In this case we don't want to message
        // the user.
        if(cart.freeShipUpgradeEligible
              && cart.shippingMethod != cartJs.defaultShipping
              && cart.baseShippingRate != 0) {
            $('flatRateNotChosenMessage').show();
            new Effect.Appear('shippingMessagesRow', {duration: 2, delay: 0});
        } else {
          // If disableFirstHide isn't selected we need to hide error message.
          $('flatRateNotChosenMessage').hide();
        }

        var hasAddlShippingCost = false;
        if (parseFloat(cart.addlShippingRate) > 0) {
            hasAddlShippingCost = true;
            $('addlShippingCostRow').show();
            $('addlShippingCostContainer').innerHTML = Liberty.Common.getDisplayPrice(cart.addlShippingRate);
        }
        else {
            $('addlShippingCostRow').hide();
            $('addlShippingCostContainer').innerHTML = 'N/A'; //div is hidden, but set to 'N/A' for completeness
        }

        //additional shipping note adds height to page; resize modal if in modal mode
        if ($('MB_window')) {
            Modalbox.resizeToContent();
        }

        $('creditsAppliedContainer').innerHTML = Liberty.Common.getDisplayPrice(cart.creditsApplied);
        $('orderTotalContainer').innerHTML = Liberty.Common.getDisplayPrice(cart.orderTotal);
        new Effect.Highlight('orderTotalContainer', {duration: 4});

        if($('shippingNameContainer') && 'shippingName' in cart) {
            $('shippingNameContainer').innerHTML = cart.shippingName;
        }

        $('shippingAsteriskContainer').innerHTML = (hasAddlShippingCost ? '*' : '');

        if($('checkoutCart')) {
            $('estimatedArrivalValue').update(cart.shippingEtaFormatted);
            new Effect.Highlight('estimatedArrivalValue', {duration: 4});


            // Update individual shipment ETAs
            for(var shipmentNode in cart.shipments) {
                if($('shipmentEta_'+shipmentNode)) {
                    $('shipmentEta_'+shipmentNode).update(cart.shipments[shipmentNode].shippingEta);
                    new Effect.Highlight('shipmentEta_'+shipmentNode, {duration: 4});
                }
            }

            if ($('selectedShippingMethod').value == 1029) {
                $('nextDayMsg').style.display = 'block';
                new Effect.Highlight('nextDayMsg', {duration: 4});
            } else {
                $('nextDayMsg').style.display = 'none';
            }
        }

        var hasUpgradeShipMethod = false;
        
        //selectedShippingMethod is on checkout, not cart
        var selectedShippingMethod = $('selectedShippingMethod');
        if (selectedShippingMethod) {
            for ( var smLcv = 0; smLcv < selectedShippingMethod.options.length; smLcv++ ) {
                if ( $('selectedShippingMethod').options[smLcv].value == cartJs.gfcShipping ) {
                    hasUpgradeShipMethod = true;
                    break;
                }
            }
        } else {
            try {
                for ( var smLcv = 0; smLcv < cartJs.shippingMethods.length; smLcv++ ) {
                    if (+cartJs.shippingMethods[smLcv]['shipMethodID'] == cartJs.gfcShipping) {
                        hasUpgradeShipMethod = true;
                        break;
                    }
                }
            } catch (e) {};
        }

        if ( $('shipUpgradeMessage') != null ) {
            $('shipUpgradeMessage').style.display = ((cart.shippingMethod=='1046' && hasUpgradeShipMethod || !hasUpgradeShipMethod) ? 'none' : 'block');
        }

        if ( $('shippingLabel') != null ) {
            $('shippingLabel').style.display = ((cart.shippingMethod=="1046" && hasUpgradeShipMethod)?'none':'inline');
        }

        this.shippingZip = cart.taxZipCode;

        if($('shippingSelector')) {
            $('shippingSelector').hide();
        }

    }

}

// limiter for the invitation message textarea
var count = "210";   //Example: var count = "175";
function limiter(){
    var tex = $('message').value,
        len = tex.length;
    if(len > count){
        tex = tex.substring(0,count);
        $('message').value=tex;
        return false;
    }

    var newCount = count-len;
    if (newCount > 0) {
        $('limit').innerHTML = "(" + newCount + " characters left)";
        $('limit').style.color = '#989B97';
    } else {
        $('limit').innerHTML = 'maximum reached!';
        $('limit').style.color = '#EF164B';
    }
}

/************************************************************/

function createCookie(name,value,days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days*24*60*60*1000));
        var expires = '; expires='+date.toGMTString();
    } else {
      var expires = '';
    }
    var domain = ( cookieDomain!=null && cookieDomain.length>0 )?('; domain=' + cookieDomain):'';
    document.cookie = name + '=' + escape(value)+expires+'; path=/' + domain;
}

function getCookie(name) {
    var dc = document.cookie,
        prefix = name + '=',
        begin = dc.indexOf('; ' + prefix);
    if (begin == -1) {
        begin = dc.indexOf(prefix);
        if (begin != 0) {
            return null;
        }
    } else {
        begin += 2;
    }
    var end = document.cookie.indexOf(';', begin);
    if (end == -1) {
        end = dc.length;
    }
    return unescape(dc.substring(begin + prefix.length, end));
}

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1,c.length);
        }
        if (c.indexOf(nameEQ) == 0) {
            return c.substring(nameEQ.length,c.length);
        }
    }
    return null;
}

function eraseCookie(name) {
    createCookie(name,'',-1);
}


function sessionTimeout(timeoutMsg){
  if (Modalbox.active) {
    if (typeof Product != 'undefined') {
        Product = null;
    }
    Modalbox.show("<p>" + timeoutMsg + "</p>");
  }
  (function() {
    var href = window.top.location.href;
    href = href.replace(/#[^?]+/, "");
    href = href.replace(/#$/, "");
    var q = href.parseQuery();
    q['expired'] = true;
    var url = href.split("?")[0];
    window.top.location.href = (url + '?' + Object.toQueryString(q));
  }).delay(3);
}


/**
 * The following is an algorithm to determine if credit card numbers are
 * valid.  Basically, we add values to validate according to the mod10 rules,
 * and if validate is a factor of 10, then the credit card is valid.  The
 * rules are as follows:
 *
 * Each digit in the credit card number has an index.  Starting from the back,
 * digits with an odd numbered index are doubled and each digit in the
 * resulting value is added to validate.  digits with even numbered indexes
 * are added to validate.  When the process is complete, validate should be a
 * factor of 10 if the credit card number is valid.
 */

/* deep copy of object's data - excludes functions and dom elements */
Liberty.Common.copy = function(destination,source) {
    if (Object.prototype.toString.call(destination) === '[object Array]') {
        var out = source || [], i = 0, len = destination.length;
        for ( ; i < len; i++ ) {
            out[i] = arguments.callee(destination[i]);
        }
        return out;
    }
    if (typeof destination === 'object') {
        var out = source || {}, i;
        for ( i in destination ) {
            if(destination[i] != null && typeof destination[i]['nodeType']=='undefined' && typeof destination[i] !== 'function'){
              out[i] = arguments.callee(destination[i]);
            }
        }
        return out;
    }
    return destination;
};

Liberty.Common.mixin = function(source,destination){
    for(var prop in source){
        if(prop !== undefined && source.hasOwnProperty(prop)){
            destination[prop] = source[prop];
        }
    }
    return destination;
};

Liberty.Common.clone = function(baseObject/*,concreteObj,deep*/){
    var inheriting = arguments.length > 1,
        concreteObject = {};

    function F() {}
    F.prototype = baseObject;
    var newObject = new F;

    if(inheriting){
        concreteObject = arguments[1] || false;
        var copy = arguments[2] || false;
        newObject = copy===true
            ? Liberty.Common.copy(concreteObject,newObject)
            : Liberty.Common.mixin(concreteObject,newObject);
    }
    if(typeof baseObject.init == "function"){
        baseObject.init.call(newObject,concreteObject);
    }
    if(inheriting && typeof newObject.initialize == "function"){
        newObject.initialize.call(newObject,concreteObject);
    }
    return newObject;
};

/******************************************************************************
 * Utility for bind events for one-time use (ex. closing an open select box)
 * Can be called with 3,4 or 5 arguments
 * Called with 3 or 4, the fn argument (a function) is called and the one time event is removed
 * If called with 4, the 4th method is used as the scope (no checking done...TODO)
 * If called with 5, the 3rd argument is a test function, the 4th is a callback function and
 *     an optional 5th argument is a scope to apply to the 3rd and 4th functions.
 *     If the test function returns true, the 4th method is called and the bound function is removed.
 *     If the test function returns false, bound function is not cleared
 ******************************************************************************/
Liberty.Common.once = (function(){
    var boundFn = {};

    function bind(elem,type,fn){
      var uniqueId = new Date().getTime(),
          origArgs = arguments;

          boundFn[uniqueId] = {
              'elem' : elem,
              'type' : type,
              'args' : arguments,
              'fn' : function(){
                  var args = origArgs,
                      nArgs = args.length,
                      callback = args[3];
                  if(nArgs > 4){
                      if(fn.apply(args[4],arguments)===true){
                          callback.apply(args[4],arguments);
                          Event.stopObserving(elem, type, boundFn[uniqueId]['fn']);
                          delete boundFn[uniqueId];
                      }
                  }else{
                      var scp = nArgs > 3 ? args[3] : this;
                      fn.apply(scp,arguments);
                      Event.stopObserving(elem, type, boundFn[uniqueId]['fn']);
                      delete boundFn[uniqueId];
                  }
              }
          };
        Event.observe(elem, type, boundFn[uniqueId]['fn']);
        return uniqueId;
    };

    function call(uniqueId){
        if(boundFn[uniqueId]){
            boundFn[uniqueId]['fn']();
        }
    };

    function callAll(){
        for(var bound in boundFn){
            if(boundFn.hasOwnProperty(bound)){
                boundFn[bound]['fn']();
            }
        }
    };

    function unbind(uniqueId){
        if(boundFn[uniqueId]){
            Event.stopObserving(boundFn[uniqueId]['elem'], boundFn[uniqueId]['type'], boundFn[uniqueId]['fn']);
            delete boundFn[uniqueId];
        }
    };

    function clear(){
        for(bound in boundFn){
            Event.stopObserving(boundFn[bound]['elem'], boundFn[bound]['type'], boundFn[bound]['fn']);
        }
        boundFn = {};
    }

    return {
        'bind': bind,
        'unbind' : unbind,
        'clear' : clear,
        'call' : call,
        'callAll' : callAll
    }

})();

/* START ODOMETER CODE */
Liberty.Odometer = function (dLeft, doAnimate) {
    
    var tens = $('odometerTens'),
        singles = $('odometerSingles'),
        odometer = $('odometer'),
        defaultDuration = 1,
        
        initialize = function (daysLeft, doAnimate) {
            var tileHeight = tens.getHeight(),
                daysLeft = daysLeft.length == 1 ? '0' + daysLeft : daysLeft,
                firstDigit = daysLeft.substring(0,1),
                secondDigit = daysLeft.substring(1,2),
                tensOffset = tileHeight * firstDigit,
                singlesOffset = tileHeight * secondDigit;
    
            jump(tens, -tensOffset);
            jump(singles, -singlesOffset);
            setTimeout(function(){odometer.setStyle('visibility:visible');},10);
            if (doAnimate === true) {
                setTimeout(function () {
                    if (secondDigit == 0) {
                        roll(tens, -tensOffset, -tensOffset + tileHeight, defaultDuration * 1.5);
                        jump(singles, -(tileHeight * 10));
                        setTimeout(function () {
                            roll(singles, -(tileHeight * 10), -(tileHeight * 9));
                        }, (defaultDuration * 1000) * .5);
                    } else if (daysLeft != '01') {
                        roll(singles, -singlesOffset, -singlesOffset + tileHeight);
                    } else {
                        jump(singles, -tileHeight);
                    }
                }, 500);
            }
        },
        
        jump = function (elem, to) {
            roll(elem, 0, to, 0);
        },
        
        roll = function (elem, from, to, dur) {
            var q = elem.id || elem.identify(),
                effectDuration = typeof dur != 'undefined' ? dur : defaultDuration,
                effectOptions = {transition: Effect.Transitions.sinoidal, duration: effectDuration, queue: { position: 'end', scope: q }};
            
            if (effectDuration === 0) {
                effectOptions.fps = 1;
            }
            
            new Effect.Tween(elem, from, to,  effectOptions, function (val) {
                this.style.backgroundPosition = '0px ' + val + 'px';
            });
        };
    
    try {
		    if (tens && singles) {
            daysLeft = (!isNaN(dLeft) && dLeft && dLeft < 99) ? dLeft : 1;
            if (doAnimate === true) { daysLeft++; }
		        initialize.call(this, new String(daysLeft), doAnimate);
		    }
    } catch (e) {}    
};

