﻿var _tmplCache = {}
parseTemplate = function(str, data) {
    /// <summary>
    /// Client side template parser that uses &lt;#= #&gt; and &lt;# code #&gt; expressions.
    /// and # # code blocks for template expansion.
    /// NOTE: chokes on single quotes in the document in some situations
    ///       use &amp;rsquo; for literals in text and avoid any single quote
    ///       attribute delimiters.
    /// </summary>    
    /// <param name="str" type="string">The text of the template to expand</param>    
    /// <param name="data" type="var">
    /// Any data that is to be merged. Pass an object and
    /// that object's properties are visible as variables.
    /// </param>    
    /// <returns type="string" />  
    var err = "";
    try {
        var func = _tmplCache[str];
        if (!func) {
            var strFunc =
            "var p=[],print=function(){p.push.apply(p,arguments);};" +
                        "with(obj){p.push('" +

            str.replace(/[\r\t\n]/g, " ")
               .replace(/'(?=[^#]*#>)/g, "\t")
               .split("'").join("\\'")
               .split("\t").join("'")
               .replace(/<#=(.+?)#>/g, "',$1,'")
               .split("<#").join("');")
               .split("#>").join("p.push('")
               + "');}return p.join('');";

            //            alert(strFunc);
            func = new Function("obj", strFunc);
            _tmplCache[str] = func;
        }
        return func(data);
    } catch (e) { err = e.message; }
    return "< # ERROR: " + err + " # >";
}

var finderUtils = {
    ParseCSSProperty: function(selector, cssProperty) {
        return parseInt(($(selector).css(cssProperty).replace(/px/, "")));
    }
};

var sockfinderCommon = {
    FilterStatus: {
        Selected: 1,
        Unselectable: 2,
        Selectable: 3
    },
    SetupIconClicks: function(finderIcons, allowDeselect, context) {
        if (typeof finderIcons != "undefined") //serialized to page from code-behind
        {
            for (var i in finderIcons) {
                var fIcon = finderIcons[i];
                if (fIcon.FilterStatus == this.FilterStatus.Selectable)
                    $("#" + fIcon.IconImageClientId).click(function() { context.SelectableIconClicked(this.id); });

                if (allowDeselect) {
                    if (fIcon.FilterStatus == this.FilterStatus.Selected)
                        $("#" + fIcon.IconImageClientId).click(function() { context.SelectedIconClicked(this.id); });
                }
            }
        }
    },
    CreateFilterObjectForIconClicked: function(id, iconsArray) {
        var fIcon = this.GetFilterIconFromPageArray(id, iconsArray);

        var filterObject = new Object();
        filterObject.FilterStatus = "Selected";
        filterObject.FilterType = fIcon.FilterType;
        filterObject.SourceId = fIcon.SourceId;
        filterObject.FilterText = fIcon.IconHoverText;

        return filterObject;
    },
    GetFilterIconFromPageArray: function(fIconId, iconsArray) {
        for (var i in iconsArray) {
            if (iconsArray[i].IconImageClientId == fIconId)
                return iconsArray[i];
        }
    },
    RemoveSelectedFilterFromFiltersArray: function(filterType, sourceId, context) {
        var updatedFilters = [];
        for (var i in context.FilterObjectsToSend) {
            var fo = context.FilterObjectsToSend[i]
            if (fo.FilterType != filterType && fo.SourceId != sourceId)
                updatedFilters.push(fo);
        }
        context.FilterObjectsToSend = updatedFilters;
    },
    GetFilterObjectFromArray: function(allfilterObjects, filterType, sourceId) {
        for (var i in allfilterObjects) {
            var fo = allfilterObjects[i]
            if (fo.FilterType == filterType && fo.SourceId == sourceId)
                return fo;
        }
    },
    UpdateFinderIcons: function(filterObjectsReturned, iconsArray, context) {
        for (var i in iconsArray) {
            var fIcon = iconsArray[i];
            var filterObject = sockfinderCommon.GetFilterObjectFromArray(filterObjectsReturned, fIcon.FilterType, fIcon.SourceId);
            if (filterObject != null)
                sockfinderCommon.UpdateFinderIcon(fIcon, filterObject.FilterStatus, context);
        }
    },
    UpdateFinderIcon: function(fIcon, filterStatus, context) {
        var fImage = $("#" + fIcon.IconImageClientId);

        //take out any onmouseover attributes. event will be handled via jquery events
        fImage.removeAttr("onmouseover").removeAttr("onmousedown").removeAttr("onmouseout");

        if (filterStatus == sockfinderCommon.FilterStatus.Selected) {
            fImage.attr("src", fIcon.SelectedImagePath)
                  .css("cursor", "")
                  .unbind();

            if (context.AllowDeselect) {
                fImage.click(function() { context.SelectedIconClicked(this.id); });
                this.SetMouseOversForIconImage(fImage, fIcon, true);
            }
        }
        else if (filterStatus == sockfinderCommon.FilterStatus.Selectable) {
            fImage.attr("src", fIcon.SelectableImagePath)
                  .css("cursor", "")
                  .unbind()
                  .click(function() { context.SelectableIconClicked(this.id); });

            this.SetMouseOversForIconImage(fImage, fIcon, false);
        }
        else if (filterStatus == sockfinderCommon.FilterStatus.Unselectable) {
            fImage.attr("src", fIcon.UnSelectableImagePath)
                  .css("cursor", "default")
                  .unbind();
        }

        //in case a mouseout was removed while label was displayed
        $("#" + fIcon.HoverLabelClientId).hide();
    },
    SetMouseOversForIconImage: function(jqueryEle, fIcon, isSelected) {
        var hasHoverText = $("#" + fIcon.HoverLabelClientId).text().length > 0;

        jqueryEle.mouseover(function() { sockfinderCommon.SwapFinderImage(this, fIcon.HoverImagePath, fIcon.HoverLabelClientId, hasHoverText); });

        var mouseDownAndOut = null;
        if (isSelected)
            mouseDownAndOut = function() { sockfinderCommon.SwapFinderImage(this, fIcon.SelectedImagePath, fIcon.HoverLabelClientId, false); };
        else
            mouseDownAndOut = function() { sockfinderCommon.SwapFinderImage(this, fIcon.SelectableImagePath, fIcon.HoverLabelClientId, false); };

        jqueryEle.mouseout(mouseDownAndOut);
        jqueryEle.mousedown(mouseDownAndOut);
    },
    SetDefaultStateForIcons: function(iconsArray, context) {
        for (var i in iconsArray) {
            var fIcon = iconsArray[i];
            sockfinderCommon.UpdateFinderIcon(fIcon, fIcon.FilterStatus, context);
        }
    },
    SwapFinderImage: function(imgEle, imageUrl, textEle, showtext) {
        sockfinderCommon.ShowHideHoverText(imgEle, textEle, showtext);
        imgEle.src = imageUrl;
    },
    ShowHideHoverText: function(imageEle, textEle, showtext) {
        var hoverLabel = $("#" + textEle);
        var icon = $(imageEle);

        if (showtext) {
            //center the label above the icon            
            var labelOffset = 0;
            var labelWidth = hoverLabel.width();
            var iconWidth = icon.width();

            if (labelWidth < iconWidth) {
                labelOffset = (iconWidth - labelWidth) / 2;
                labelOffset -= 4; //adjust for padding
            }
            else if (labelWidth > iconWidth) {
                labelOffset = (labelWidth - iconWidth) / 2;
                labelOffset *= -1; // need to make margin negative
            }
            else
                labelOffset -= 4;

            hoverLabel.css("margin-left", labelOffset + "px");
            hoverLabel.css("display", "block");
        }
        else
            hoverLabel.css("display", "none");
    }
};


//specifically SockFinder in Header
var sockFinderControl = {
    IsVisible: false,
    SFHeight: "",
    ucfinderIcons: new Array(),
    FilterObjectsToSend: new Array(),
    IsIE6: false,
    AllowDeselect: true,
    FinderSlideSpeed: 1500,

    Initialize: function() {
        var me = this;
        $(SockFinderControlGlobals.UIElements.CloseLink).click(function() { me.HideSockFinder(); });
        $(SockFinderControlGlobals.FunctionalElements.BtnReset).click(function() { me.ResetSockFinder(); });

        this.IsIE6 = (jQuery.browser.msie && jQuery.browser.version < 7);

        this.SFHeight = finderUtils.ParseCSSProperty(SockFinderControlGlobals.UIElements.SockFinderDiv, "height");

        sockfinderCommon.SetDefaultStateForIcons(ucfinderIcons, this);
        this.SetupIconClicks();
    },
    ShowSockFinder: function() {
        this.SetupContentAreaSizes();

        $(SockFinderControlGlobals.UIElements.SockFinderParentDiv).slideDown(500);
        $(SockFinderControlGlobals.UIElements.SockFinderDiv).slideDown(this.FinderSlideSpeed);
    },
    SetupContentAreaSizes: function() {
        //if top or left hasn't been explicitly set, the control will position itself over the global UIElements.PageContentContainer set in markup 
        var contentLocation = $(SockFinderControlGlobals.UIElements.PageContentContainer).offset();

        var top = (SockFinderControlGlobals.Positioning.Top > 0)
                  ? SockFinderControlGlobals.Positioning.Top
                  : contentLocation.top + finderUtils.ParseCSSProperty(SockFinderControlGlobals.UIElements.PageContentContainer, "padding-top");

        var left = (SockFinderControlGlobals.Positioning.Left > 0)
                   ? SockFinderControlGlobals.Positioning.Left
                   : contentLocation.left;

        $(SockFinderControlGlobals.UIElements.SockFinderParentDiv).css("top", top);
        $(SockFinderControlGlobals.UIElements.SockFinderDiv).css("top", top);
        if (this.IsIE6) {
            $(SockFinderControlGlobals.UIElements.SockFinderParentDiv).css("left", left);
            $(SockFinderControlGlobals.UIElements.SockFinderDiv).css("left", left);
        }

        //below code is to make sure the sockfinder will take up the entire content area
        var contentAreaContainerHeight = $(SockFinderControlGlobals.UIElements.PageContentContainer).height() + finderUtils.ParseCSSProperty(SockFinderControlGlobals.UIElements.PageContentContainer, "padding-bottom");

        //normally this control will position itself on the top of the PageContentContainer specified.  However, when TOP is specified, we need to offset the height to ensure canvas still extends only to bottom of content.
        if (SockFinderControlGlobals.Positioning.Top > 0)
            contentAreaContainerHeight -= top;

        var adjustedHeight = 0;
        if (contentAreaContainerHeight <= this.SFHeight)
            adjustedHeight = this.SFHeight - finderUtils.ParseCSSProperty(SockFinderControlGlobals.UIElements.SockFinderDiv, "padding-bottom");
        else {
            adjustedHeight = contentAreaContainerHeight;
            if (contentAreaContainerHeight > 2000) //when the page is longer, reduce the slide speed
                this.FinderSlideSpeed = 2000;
        }
        //this is needed for only bringing down the background canvas
        $(SockFinderControlGlobals.UIElements.SockFinderParentDiv).height(adjustedHeight);
        //below needed to bring sockfinder brown to bottom of content                
        $(SockFinderControlGlobals.UIElements.SockFinderDiv).height(adjustedHeight);

        if (SockFinderControlGlobals.Positioning.Top > 0) //home page
            $(SockFinderControlGlobals.UIElements.BottomSection).height(adjustedHeight - SockFinderControlGlobals.Positioning.Top - 10); //10 for padding
        else
            $(SockFinderControlGlobals.UIElements.BottomSection).height(adjustedHeight - 180); //180 for top section,titles,padding
    },
    HideSockFinder: function(callback) {
        if (typeof callback == "undefined") {
            $(SockFinderControlGlobals.UIElements.SockFinderParentDiv).slideUp();
            $(SockFinderControlGlobals.UIElements.SockFinderDiv).slideUp();
        }
        else {
            $(SockFinderControlGlobals.UIElements.SockFinderDiv).slideUp();
            $(SockFinderControlGlobals.UIElements.SockFinderParentDiv).slideUp("fast", callback);
        }
    },
    //set the find buttons onClientClick property to this if the sockfinder needs to slide back up before it posts back
    HideSockFinderForPost: function(searchType) {
        var callBackToFirePost = null;
        if (searchType == "textSearch")
            callBackToFirePost = function() { __doPostBack(SockFinderControlGlobals.FunctionalElements.BtnSearchByTextUniqueId, '') };
        else if (searchType == "filterSearch")
            callBackToFirePost = function() { __doPostBack(SockFinderControlGlobals.FunctionalElements.BtnSearchByFiltersUniqueId, '') };

        this.HideSockFinder(callBackToFirePost);

        return false;
    },
    SetupIconClicks: function() {
        if (typeof ucfinderIcons != "undefined") //serialized to page from code-behind
            sockfinderCommon.SetupIconClicks(ucfinderIcons, this.AllowDeselect, this);
    },
    CopyFiltersIntoHiddenFieldForServerSideAccess: function() {
        var serializedFilters = Sys.Serialization.JavaScriptSerializer.serialize(this.FilterObjectsToSend);
        $(SockFinderControlGlobals.FunctionalElements.HiddenFieldSelectedFilters).val(serializedFilters);
    },
    SelectableIconClicked: function(id) {
        var filterObject = sockfinderCommon.CreateFilterObjectForIconClicked(id, ucfinderIcons);

        //do the check below in icons are clicked multiple times before they are updated (FB4484)
        var filterObjAlreadyInArray = sockfinderCommon.GetFilterObjectFromArray(this.FilterObjectsToSend, filterObject.FilterType, filterObject.SourceId);

        if (filterObjAlreadyInArray == null)
            this.FilterObjectsToSend.push(filterObject);

        //filters needed server-side for redirection
        this.CopyFiltersIntoHiddenFieldForServerSideAccess();

        var me = sockFinderControl;
        var successCallBack = function(result) { me.OnSuccessFiltersReturnedCallback(result, me); };
        Wigwam.UI.Web.FrontEnd.Services.SockFinder.GetSockFinderFilters(this.FilterObjectsToSend, successCallBack);
    },
    SelectedIconClicked: function(id) {
        var filterObject = sockfinderCommon.CreateFilterObjectForIconClicked(id, ucfinderIcons);

        sockfinderCommon.RemoveSelectedFilterFromFiltersArray(filterObject.FilterType, filterObject.SourceId, this);
        this.CopyFiltersIntoHiddenFieldForServerSideAccess();

        var me = this;
        var successCallBack = function(result) { me.OnSuccessFiltersReturnedCallback(result, me); };
        Wigwam.UI.Web.FrontEnd.Services.SockFinder.GetSockFinderFilters(this.FilterObjectsToSend, successCallBack);
    },
    OnSuccessFiltersReturnedCallback: function(filterObjectsReturned, me) {
        sockfinderCommon.UpdateFinderIcons(filterObjectsReturned, ucfinderIcons, me);
    },
    ResetSockFinder: function() {
        this.FilterObjectsToSend = new Array();
        sockfinderCommon.SetDefaultStateForIcons(ucfinderIcons, this);
        this.SetupIconClicks();
    }
};

//specifically for findRetailer in header
var findRetailerControl = {
    SelectedCountry: "",
    Address: "",
    Distance: "",
    Category: null,
    FindRetailerCore: null,
    IsBottomVisible: true,
    ContentAreaOrigCSS: "mainContent",
    ContentAreaOrigHeight: "",
    TopHeight: 0,
    ContentAreaAdjustableHeightCSS: "mainContentAdjustableHeight",
    ContentAreaContainerTotalHeight: 0, //adjusted for padding           
    VisibleHeight: 0,
    IsIE6: false,
    FinderSlideSpeed: 1500,

    Initialize: function() {
        $(FindRetailerGlobals.CountryDropDown).change(function() {
            var showState = $(FindRetailerGlobals.CountryDropDown).val() == "US";
            findRetailerControl.ShowHideStateDropDown(showState);
            findRetailerControl.Validation.ShowHideStateValidatorMsg(false);
        });

        this.IsIE6 = (jQuery.browser.msie && jQuery.browser.version < 7);
        this.TopHeight = finderUtils.ParseCSSProperty(FindRetailerGlobals.TopSection, "height");
        this.ContentAreaOrigHeight = $(FindRetailerGlobals.PageContentContainer).css("height");

        $(FindRetailerGlobals.FinderContainer).keydown(findRetailerControl.HandleEnterPressed);
        $(FindRetailerGlobals.SearchButton).click(function() { findRetailerControl.PerformSearch(); });
        $(FindRetailerGlobals.SearchButtonImage);
        $(FindRetailerGlobals.CloseButton).click(function() { findRetailerControl.CloseFindRetailer() });
        $(FindRetailerGlobals.RetailerTypeResults).click(function() { findRetailerControl.ShowRetailerFilters() });
        $(FindRetailerGlobals.EtailerTypeResults).click(function() { findRetailerControl.ShowEtailerFilters() });

        this.FindRetailerCore = new FindRetailerCore();
        this.FindRetailerCore.MapContainer = FindRetailerGlobals.MapContainer;
        this.FindRetailerCore.ResultsContainer = FindRetailerGlobals.ResultsContainer;
        this.FindRetailerCore.EtailerResultsContainer = FindRetailerGlobals.EtailerResultsContainer;
        this.FindRetailerCore.NoResultsContainer = FindRetailerGlobals.NoResultsContainer;
        this.FindRetailerCore.ResultTemplateURL = FindRetailerGlobals.ResultTemplateURL;
        this.FindRetailerCore.EtailerResultTemplateURL = FindRetailerGlobals.EtailerResultTemplateURL;
        this.FindRetailerCore.ThemedRetailerResultIconUrl = FindRetailerGlobals.ThemedRetailerResultIconUrl;
        this.FindRetailerCore.ThemedRetailerMapIconUrl = FindRetailerGlobals.ThemedRetailerMapIconUrl;
        this.FindRetailerCore.Initialize();
    },
    ShowFindRetailer: function() {
        this.SetupContentAreaSizes();
        $(FindRetailerGlobals.FindRetailerCanvas).slideDown(500);
        $(FindRetailerGlobals.FinderContainer).slideDown(this.FinderSlideSpeed);
    },
    CloseFindRetailer: function() {
        //see comment in SetupCanvasControlAndPageContainerHeights() for why we muck with these classes
        $(FindRetailerGlobals.PageContentContainer).removeClass(this.ContentAreaAdjustableHeightCSS).addClass(this.ContentAreaOrigCSS);
        $(FindRetailerGlobals.PageContentContainer).css("height", this.ContentAreaOrigHeight);

        $(FindRetailerGlobals.FindRetailerCanvas).slideUp();
        $(FindRetailerGlobals.FinderContainer).slideUp();
    },
    ShowRetailerFilters: function() {
        $(FindRetailerGlobals.FormCountry).show();
        $(FindRetailerGlobals.FormCity).show();
        $(FindRetailerGlobals.FormZip).show();
        $(FindRetailerGlobals.FormDistance).show();
        $(FindRetailerGlobals.CategoryStepNumber).html("4.");
        $(FindRetailerGlobals.SubmitStepNumber).html("6.");
        $(FindRetailerGlobals.TopSection).css("height", "400px");
        var imageUrl = $(FindRetailerGlobals.SearchButtonImage).attr("src");
        imageUrl = imageUrl.replace("btnPurchase2.gif", "btnFindRetailer.gif");
        $(FindRetailerGlobals.SearchButtonImage).attr("src", imageUrl);
        findRetailerControl.Validation.ResetForm();

    },
    ShowEtailerFilters: function() {
        $(FindRetailerGlobals.FormCountry).hide();
        $(FindRetailerGlobals.FormCity).hide();
        $(FindRetailerGlobals.FormZip).hide();
        $(FindRetailerGlobals.FormDistance).hide();
        $(FindRetailerGlobals.CategoryStepNumber).html("2.");
        $(FindRetailerGlobals.SubmitStepNumber).html("3.");
        $(FindRetailerGlobals.TopSection).css("height", "200px");
        var imageUrl = $(FindRetailerGlobals.SearchButtonImage).attr("src");
        imageUrl = imageUrl.replace("btnFindRetailer.gif", "btnPurchase2.gif");
        $(FindRetailerGlobals.SearchButtonImage).attr("src", imageUrl);
        findRetailerControl.Validation.ResetForm();
    },
    HandleEnterPressed: function(sender) {
        if (sender.keyCode == 13) {
            sender.preventDefault();
            findRetailerControl.PerformSearch();
        }
    },
    PerformSearch: function() {
        if ($("input[@name='resulttype']:checked").val() == '0') {
            if (this.ValidateAndConstuctAddress()) //this.AreFieldsValid(zip, distance)
            {

                this.IsBottomVisible = true;
                //for request extend BG to bottom.  to make it appear as so we hide bottom elements
                $(FindRetailerGlobals.HiddenOnLoad.BottomSectionTitle).fadeIn();
                $(FindRetailerGlobals.HiddenOnLoad.ResultsBorder).fadeIn();
                $(FindRetailerGlobals.HiddenOnLoad.BottomThickBorder).fadeIn();
                $(FindRetailerGlobals.EtailerResultsContainer).hide();
                $(FindRetailerGlobals.BottomMapAndResults).show();
                this.ShowSearchedForLabel();
                this.FindRetailerCore.GeocodeAddressAndDoSearch(this.SelectedCountry, this.Address, this.Distance, this.Category, this.AddressNotFoundCallback);

                this.VisibleHeight = finderUtils.ParseCSSProperty(FindRetailerGlobals.TopSection, "height");
                if (this.IsBottomVisible)
                    this.VisibleHeight += finderUtils.ParseCSSProperty(FindRetailerGlobals.BottomSection, "height");

                this.SetupCanvasControlAndPageContainerHeights();

                $(FindRetailerGlobals.BottomSection).slideDown();
                pageTracker._trackEvent('Global Retailer Search', 'Local Search', this.Address + ' | ' + this.SelectedCountry + ' | ' + this.Distance + ' | ' + this.GetDropDownSelectedText($(FindRetailerGlobals.CategoryDropDown)));

            }
        }
        else {

            $(FindRetailerGlobals.BottomSection).show();
            //for request extend BG to bottom.  to make it appear as so we hide bottom elements
            $(FindRetailerGlobals.HiddenOnLoad.BottomSectionTitle).fadeIn();
            $(FindRetailerGlobals.HiddenOnLoad.ResultsBorder).fadeIn();
            $(FindRetailerGlobals.HiddenOnLoad.BottomThickBorder).fadeIn();
            $(FindRetailerGlobals.BottomMapAndResults).hide();
            $(FindRetailerGlobals.EtailerResultsContainer).show();
            //create closures for callbacks to reference this instance of FindRetailerCore
            this.FindRetailerCore.DisplayEtailerResults(this.Category);
            pageTracker._trackEvent('Global Retailer Search', 'Online Retailer Search', this.GetDropDownSelectedText($(FindRetailerGlobals.CategoryDropDown)));
            $("#UCEtailerResults").find("a").click(function() {
                pageTracker._trackEvent('Global Retailer Search', 'Online Retailer Click', $(this).html());
            });
        }

    },
    SetupContentAreaSizes: function() {
        //if top or left hasn't been explicitly set, the control will position itself over the global UIElements.PageContentContainer set in markup 
        var contentLocation = $(FindRetailerGlobals.PageContentContainer).offset();

        var top = (FindRetailerGlobals.Positioning.Top > 0)
                  ? FindRetailerGlobals.Positioning.Top
                  : contentLocation.top + finderUtils.ParseCSSProperty(FindRetailerGlobals.PageContentContainer, "padding-top");

        var left = (FindRetailerGlobals.Positioning.Left > 0)
                   ? FindRetailerGlobals.Positioning.Left
                   : contentLocation.left;

        $(FindRetailerGlobals.FindRetailerCanvas).css("top", top);
        $(FindRetailerGlobals.FinderContainer).css("top", top);
        if (this.IsIE6) {
            $(FindRetailerGlobals.FindRetailerCanvas).css("left", left);
            $(FindRetailerGlobals.FinderContainer).css("left", left);
        }

        //below code is to make sure the control will take up the entire content area
        this.ContentAreaContainerTotalHeight = $(FindRetailerGlobals.PageContentContainer).height() + finderUtils.ParseCSSProperty(FindRetailerGlobals.PageContentContainer, "padding-bottom");

        this.VisibleHeight = finderUtils.ParseCSSProperty(FindRetailerGlobals.TopSection, "height");
        if (this.IsBottomVisible)
            this.VisibleHeight += finderUtils.ParseCSSProperty(FindRetailerGlobals.BottomSection, "height");

        //normally this control will position itself on the top of the PageContentContainer specified.  However, when TOP is specified, we need to offset the height to ensure canvas still extends only to bottom of content.
        if (FindRetailerGlobals.Positioning.Top > 0)
            this.ContentAreaContainerTotalHeight -= top;

        this.SetupCanvasControlAndPageContainerHeights();
    },
    SetupCanvasControlAndPageContainerHeights: function() {
        if (this.ContentAreaContainerTotalHeight <= this.VisibleHeight) //will need to stretch page
        {
            //since the mainContent class has an auto !important,  no way to remove it so that it doesn't screw with resizing.  therefore, removing the class and adding one we can work with
            $(FindRetailerGlobals.PageContentContainer).removeClass(this.ContentAreaOrigCSS).addClass(this.ContentAreaAdjustableHeightCSS);

            if (FindRetailerGlobals.Positioning.Top > 0) //home page
            {
                $(FindRetailerGlobals.PageContentContainer).height(this.VisibleHeight + FindRetailerGlobals.Positioning.Top);
                $(FindRetailerGlobals.FindRetailerCanvas).height(this.VisibleHeight);
            }
            else {
                $(FindRetailerGlobals.PageContentContainer).height(this.VisibleHeight + 10);
                $(FindRetailerGlobals.FindRetailerCanvas).height(this.VisibleHeight + 10);
            }
        }
        else {
            $(FindRetailerGlobals.FindRetailerCanvas).height(this.ContentAreaContainerTotalHeight);
            $(FindRetailerGlobals.BottomSection).height(this.ContentAreaContainerTotalHeight - this.TopHeight - 10); // -10 for some padding

            if (this.ContentAreaContainerTotalHeight)
                this.FinderSlideSpeed = 2000;
        }
    },
    ShowSearchedForLabel: function() {
        var searchDescription = "You searched for <b>{Category}</b> socks near <b>{Address}</b> within <b>{Miles}</b> miles";

        var categorytext = this.GetDropDownSelectedText($(FindRetailerGlobals.CategoryDropDown));

        searchDescription = searchDescription.replace(/{Category}/, categorytext)
                                             .replace(/{Address}/, this.Address)
                                             .replace(/{Miles}/, this.Distance);

        $(FindRetailerGlobals.SearchDescription).html(searchDescription);
        $(FindRetailerGlobals.SearchDescription).fadeIn("normal");

    },
    GetDropDownSelectedText: function(jqueryDropDown) {
        var domDDL = jqueryDropDown[0]; //jqueryObj [0] is the wrapped DOM object
        var selectedText = domDDL.options[domDDL.selectedIndex].text;
        return selectedText;
    },
    //enforce city/state OR zip but not both    
    ValidateAndConstuctAddress: function() {
        this.SelectedCountry = "";
        this.Address = "";
        this.Category = null;

        var stateNotValid = false;
        var distanceNotValid = false;
        var cityAndZipNotValid = false;

        this.SelectedCountry = $(FindRetailerGlobals.CountryDropDown).val();
        var city = $(FindRetailerGlobals.CityTextBox).val();
        var emptyCityText = $find(FindRetailerGlobals.WaterMarkExtenders.City).get_WatermarkText();
        var zip = $(FindRetailerGlobals.ZipCodeTextBox).val();
        var emptyZipText = $find(FindRetailerGlobals.WaterMarkExtenders.Zip).get_WatermarkText();
        var state = $(FindRetailerGlobals.StateDropDown).val();

        if (city != emptyCityText) //indicates city was entered
        {
            this.Address = city;
            if (this.SelectedCountry == "US") //only if country is US need to validate state
            {
                if (state == "0") //then state not selected
                    stateNotValid = true;
                else
                    this.Address += ", " + state;
            }
            //                    this.Address += ", " + country;                    
            this.Address += ", " + this.GetDropDownSelectedText($(FindRetailerGlobals.CountryDropDown));
        }
        if (this.Address == "") {
            if (zip != emptyZipText)
                this.Address += zip;
        }
        if (this.Address == "") {
            cityAndZipNotValid = true;
        }

        this.Distance = $(FindRetailerGlobals.DistanceDropDown).val();
        distanceNotValid = (this.Distance == "0");

        var categoryId = $(FindRetailerGlobals.CategoryDropDown).val();

        if (categoryId != "0")
            this.Category = categoryId;

        this.Validation.ShowHideStateValidatorMsg(stateNotValid);
        this.Validation.ShowHideDistanceValidatorMsg(distanceNotValid);
        this.Validation.ShowHideCityAndZipValidatorMsg(cityAndZipNotValid);

        if (stateNotValid || distanceNotValid || cityAndZipNotValid) {
            return false;
        }
        else
            return true;
    },
    ShowHideStateDropDown: function(show) {
        if (show)
            $(FindRetailerGlobals.StateDropDown).fadeIn();
        else
            $(FindRetailerGlobals.StateDropDown).fadeOut();
    },
    AddressNotFoundCallback: function(errorType) {
        $(FindRetailerGlobals.ResultsContainer).hide();

        if (errorType == "zipNotInCountry")
            $(FindRetailerGlobals.NoResultsContainer).text(FindRetailerGlobals.ZipNotFoundInCountryMessage);
        else
            $(FindRetailerGlobals.NoResultsContainer).text(FindRetailerGlobals.AddressNotFoundMessage);

        $(FindRetailerGlobals.NoResultsContainer).fadeIn("normal");
    },
    Validation: {
        ShowHideStateValidatorMsg: function(show) {
            this.ShowHideFields($(FindRetailerGlobals.Validators.StateValidator), show);
        },
        ShowHideDistanceValidatorMsg: function(show) {
            this.ShowHideFields($(FindRetailerGlobals.Validators.DistanceValidator), show);
        },
        ShowHideCityAndZipValidatorMsg: function(show) {
            this.ShowHideFields($(FindRetailerGlobals.Validators.CityAndZipValidator), show);
        },
        ShowHideFields: function(jqueryObj, show) {
            if (show)
                jqueryObj.slideDown("fast");
            else
                jqueryObj.slideUp("fast");
        },
        ResetForm: function() {
            this.ShowHideStateValidatorMsg(false);
            this.ShowHideDistanceValidatorMsg(false);
            this.ShowHideCityAndZipValidatorMsg(false);
            $(FindRetailerGlobals.ResultsContainer).hide();
            $(FindRetailerGlobals.BottomSection).hide();
        }
    }
};



//this component is shared by both sockfinders.  each creates it's own instance to use
function FindRetailerCore() {
    GeoCoder = null;
    Map = null;
    Point = null;
    IE6Point = null;
    ResultTemplateString = "";
    EtailerResultTemplateString = "";
    ProductCategoryIdFilter = null;

    //these should be set prior to Initialize being called
    MapContainer = "";
    ResultsContainer = "";
    EtailerResultsContainer = "";
    NoResultsContainer = "";
    ResultTemplateURL = "";
    EtailerResultTemplateURL = "";
    ThemedRetailerResultIconUrl = "";
    ThemedRetailerMapIconUrl = "";
    IsUsedForProdDetailsFinder = false;

    this.Initialize = function() {
        if (this.MapContainer == "" || this.ResultsContainer == "" || this.NoResultsContainer == "" || this.ResultTemplateURL == "" || this.ThemedRetailerResultIconUrl == "") {
            alert("Find Retailer value not defined - A necessary property has not been assigned prior to calling Initialize");
            return;
        }

        //check whether we'll be able to search.  may want to set a flag here that we can check on the search (or disable the search button) to prevent ugly behavior        
        if (GBrowserIsCompatible()) {
            try { this.GeoCoder = new GClientGeocoder(); }
            catch (err) { }
        }

        //prefetch the retailer html template
        var me = this;
        $.get(this.ResultTemplateURL, function(template) {
            me.ResultTemplateString = template;
        });

        //prefetch the etailer html template
        var me = this;
        $.get(this.EtailerResultTemplateURL, function(template) {
            me.EtailerResultTemplateString = template;
        });
    };
    this.GeocodeAddressAndDoSearch = function(countryCode, address, distance, productCategoryIdFilter, addressNotFoundCallback) {
        this.ProductCategoryIdFilter = productCategoryIdFilter;

        //create a closure for the callback        
        var me = this;

        this.GeoCoder.getLocations(address, function(result) {
            if (!result || result.Status.code != G_GEO_SUCCESS) {
                //for IE6.. seems to fail on first call to google but works on retry(?). (note:Also fails on GeoCoder.getLocations when not in failback)
                me.GeoCoder.getLocations(address, function(result) {
                    if (result.Status.code == G_GEO_SUCCESS) {
                        me.ValidateReturnedAddressIsInSelectedCountry(result, countryCode, distance, addressNotFoundCallback);
                    }
                    else
                        addressNotFoundCallback();
                });
            }
            else {
                if (result.length === 0 || result.Placemark == null)
                    addressNotFoundCallback();
                else {
                    me.ValidateReturnedAddressIsInSelectedCountry(result, countryCode, distance, addressNotFoundCallback);
                }
            }
        });
    };
    this.ValidateReturnedAddressIsInSelectedCountry = function(getAddressResult, countryCode, distance, addressNotFoundCallback) {
        if (getAddressResult.length === 0 || getAddressResult.Placemark == null)
            addressNotFoundCallback();
        else {
            var returnedCountry = getAddressResult.Placemark[0].AddressDetails.Country.CountryNameCode;

            var addessValid = false;
            if (countryCode == null) {
                addessValid = (returnedCountry == "US" || returnedCountry == "CA" || returnedCountry == "GB" || returnedCountry == "BM" || returnedCountry == "IE");
            } else {
                addessValid = (returnedCountry == countryCode);
            }
            if (!addessValid) {
                addressNotFoundCallback('zipNotInCountry');
            } else {
                this.IE6Point = getAddressResult.Placemark[0].Point;
                this.DisplayMap(distance, this.GetZoomLevelForDistance(distance));
            }
        }
    };
    this.DisplayMap = function(distance, zoomLevel) {
        if (GBrowserIsCompatible()) {
            if (this.Map == null) {
                var mapContainerId = $(this.MapContainer).attr("id");
                this.Map = new GMap2(document.getElementById(mapContainerId));
                this.Map.addControl(new GSmallMapControl());
            }

            var lat;
            var lng;

            if (this.Point != null) {
                this.Map.setCenter(this.Point, zoomLevel);
                lat = this.Point.lat();
                lng = this.Point.lng();
            }
            else if (this.IE6Point != null) {
                this.Map.setCenter(new GLatLng(this.IE6Point.coordinates[1], this.IE6Point.coordinates[0]), zoomLevel);
                lat = this.IE6Point.coordinates[1];
                lng = this.IE6Point.coordinates[0];
            }
            else
                alert('error in core.DisplayMap');

            //create closures for callbacks to reference this instance of FindRetailerCore
            var me = this;
            var successCallBack = function(result) { me.OnSuccessfulFindRetailersCallback(result, me); };
            var failedCallBack = function(result) { me.OnFailedFindRetailersCallback(result, me); };
            Wigwam.UI.Web.FrontEnd.Services.FindRetailers.FindRetailersByCoordinates(lat, lng, distance, this.ProductCategoryIdFilter, successCallBack, failedCallBack);
        }
    };
    this.OnSuccessfulFindRetailersCallback = function(result, me) {
        $(me.MapContainer).show();
        var retailerResults = eval(result); //deserialize
       
        me.RenderMapOverlays(retailerResults);
        me.RenderHTMLResults(retailerResults);
    };
    this.OnFailedFindRetailersCallback = function(result) {
        alert('error getting results:' + result.get_message());
    };
    this.DisplayEtailerResults = function(productCategoryIdFilter) {
        //create closures for callbacks to reference this instance of FindRetailerCore
        var me = this;
        var successCallBack = function(result) { me.OnSuccessfulFindEtailersCallback(result, me); };
        var failedCallBack = function(result) { me.OnFailedFindEtailersCallback(result, me); };
        Wigwam.UI.Web.FrontEnd.Services.FindRetailers.FindEtailers(productCategoryIdFilter, successCallBack, failedCallBack);
    };
    this.OnSuccessfulFindEtailersCallback = function(result, me) {
       
        var etailerResults = eval(result); //deserialize

        me.RenderHTMLResults(etailerResults, true);
    };
    this.OnFailedFindEtailersCallback = function(result) {
        alert('error getting results:' + result.get_message());
    };
    this.RenderHTMLResults = function(retailers, isEtailer) {
        $(this.ResultsContainer).html("");

        //if this called for small findRetailer on prodDetails page then isEtailer will be undefined
        if (typeof (isEtailer) == 'undefined')
            isEtailer = false;

        if (!this.IsUsedForProdDetailsFinder)
            $(this.EtailerResultsContainer).html("");            
        
        if (retailers.length == 0) {
            $(this.ResultsContainer).hide();

            $(this.NoResultsContainer).html("Sorry. Your search returned no results.<br />Please try again.");
            $(this.NoResultsContainer).fadeIn("normal");
        }
        else if (isEtailer) {
            $(this.NoResultsContainer).hide();
            $(this.EtailerResultsContainer).fadeIn("normal");
            for (var i = 0; i < retailers.length; i++) {
                retailers[i].IconUrl = this.ThemedRetailerResultIconUrl.replace(/{ImgIndex}/, i + 1);
            }

            var result = parseTemplate(this.EtailerResultTemplateString, { retailers: retailers });
            $(this.EtailerResultsContainer).append(result);
        }
        else {
            $(this.NoResultsContainer).hide();
            $(this.ResultsContainer).fadeIn("normal");

            for (var i = 0; i < retailers.length; i++) {
                retailers[i].IconUrl = this.ThemedRetailerResultIconUrl.replace(/{ImgIndex}/, i + 1);
            }

            var result = parseTemplate(this.ResultTemplateString, { retailers: retailers });
            $(this.ResultsContainer).append(result);
        }
    };
    this.RenderMapOverlays = function(retailers) {
        this.Map.clearOverlays();

        // Create our the marker icon (this is used when making the marker to overlay)
        var themedIcon = new GIcon(G_DEFAULT_ICON);
        themedIcon.iconSize = new GSize(26, 43)

        for (var i = 0; i < retailers.length; i++) {
            themedIcon.image = this.ThemedRetailerMapIconUrl.replace(/{ImgIndex}/, i + 1);
            // Set up our GMarkerOptions object
            markerOptions = { icon: themedIcon };

            var point = new GLatLng(retailers[i].Latitude, retailers[i].Longitude);
            this.Map.addOverlay(new GMarker(point, markerOptions));
        }
    };
    this.GetZoomLevelForDistance = function(distance) {
        var zoomLevel;
        switch (distance) {
            case "10":
                zoomLevel = 10;
                break;
            case "25":
                zoomLevel = 9;
                break;
            case "50":
                zoomLevel = 8;
                break;
            case "100":
                zoomLevel = 7;
                break;
        }
        return zoomLevel;
    };
};







