//==================================================================================
//  Geek Squad Map
//  
//  This JavaScript class contains all properties and functions necessary to present
//  and interact with a Google Map on www.geeksquad.com.  
//  
//  While this is written specifically for this need, the properties and functions 
//  within are constructed such that any site that displays a map, a list of 
//  relevant locations, and information windows for each location match could use
//  this class with little modification.
//
//==================================================================================

var GSM = {

    map : null,
    centerpt : null,
    centermkr : null,
    currentmkr : null,
    geocoder : null,
    tgtLpos : null,
    akamaiVals : null,
    locmarkers : [],
    locitems : [],
    defaultZoom : 9,
    minZoomLvl : 6,
    maxZoomLvl : 20,
    zoomCtrlHt : 93,
    dmaxradius : 100,
    dservicemax : 25,
    lwCurrentTop : 0,
    lwItemHt : 83,
    lwItemsPP : 5,
    visibleLocCt : 0,
    currentPage : 1,
    scrollDuration : 1200,
    infoCookieId : "CT_Akamai",
    locDefaultAddr : "New York NY",
    basePath : "/apps/locator/",
    dataProviderPage : "data.aspx",
    locZipId : "hidLocZipID",
    locMapHostId : "hidLocHost",
    locAddrId : "hidLocAddrId",
    locCityId : "hidLocCityId",
    locStateId : "hidLocStateId",
    mapLoadId : "mapLoading",
    mapBodyId : "mapBody",
    locMapZoomCtrlId : "mapZoomCtrl",
    locMapId : "map",
    locListId : "mapinfo",
    locMsgAreaId : "mapMsgPanel",
    locMapInfoAreaId : "mapLeftCol",
    locMapInfoHeadId : "mapinfoheadmsg",
    locMapSvcMsgId : "mapsvcmsg",
    mapOptMsgId : "mapOptMsg",
    pageMsgIds : ["mapPgrTop","mapPgrBtm"],
    hidePgrOnEdge : true,
    pagerLTop : "mapPgrLtTop",
    pagerLBtm : "mapPgrLtBtm",
    pagerRTop : "mapPgrRtTop",
    pagerRBtm : "mapPgrRtBtm",
    filterIds : ["mapfilter_smb","mapfilter_pc","mapfilter_ht","mapfilter_car","mapfilter_apple", "mapfilter_marine", "mapfilter_isr"],
    filterBoxes : [],
    partnerOffIds : ["mapfilter_ht","mapfilter_car","mapfilter_apple"],
    svcLabels : { },
    
    // .NET form controls have a client id that is assigned at 
    // run time.  This function is used to store those ids as
    // GSM variables.
    locatorTagAssign : function() {
        GSM.basePath = document.getElementById(GSM.locMapHostId).value + GSM.basePath;
        window.onunload = function(){GUnload();};
        GSSlider.createSlider();
        GSM.findLocation();
    },
    
    mapInit : function(mlat,mlng) {
        if (GBrowserIsCompatible()) {        
            if(GSM.map == null) {
	            GSM.map = new GMap2(document.getElementById(GSM.locMapId));             
                GSM.map.addControl(new ExtMapTypeControl({showTraffic: false}));
                GEvent.addListener(GSM.map, 'zoomend', function(oldZoomLevel, newZoomLevel) { GSM.handleMapZoom(oldZoomLevel, newZoomLevel); GSSlider.zoomEnd(oldZoomLevel, newZoomLevel); });
	        }
    	    
	        GSM.clearElementContent(document.getElementById(GSM.locListId));
	        GSM.clearMapMarkers();
	        GSM.centerpt = new GLatLng(mlat,mlng);
	        GSM.map.setCenter(GSM.centerpt, GSM.defaultZoom);
	        var redIcon = GSM.getMarkerIcon("red");
	        var newCenterMkr = new GMarker(GSM.centerpt, redIcon);
	        GSM.map.addOverlay(newCenterMkr); 
	        GSM.centermkr = newCenterMkr;
	        
	        document.getElementById(GSM.locMapInfoAreaId).style.visibility = "visible";
        }  
    },
    
    findLocation : function() {
        GSM.toggleLoading(true);
    
        var mheader = document.getElementById(GSM.locMsgAreaId);
        var mzip = document.getElementById(document.getElementById(GSM.locZipId).value).value;
        var maddr = document.getElementById(document.getElementById(GSM.locAddrId).value).value;
        var mcity = document.getElementById(document.getElementById(GSM.locCityId).value).value;
        var mstate = document.getElementById(document.getElementById(GSM.locStateId).value).value;
        var address = "";
        
        var tmpZip = getCookie("gsZipcode");
        var tmpAddr = getCookie("gsAddress");
        var tmpCity = getCookie("gsCity");
        var tmpState = getCookie("gsState");
        
        if(maddr == null || maddr.length == 0) {maddr = tmpAddr;}
        if(mcity == null || mcity.length == 0) {mcity = tmpCity;}
        if(mstate == null || mstate.length == 0 || (mstate == "NONE" && tmpState != "NONE")) {mstate = tmpState;}
        
        if(mzip != null && mzip.length > 0 && mzip != "Enter ZIP code") { address = mzip; }
        else if(maddr != null || mcity != null || mstate != null) {
            if(maddr != null && maddr.length > 0){ address = maddr; }
            if(mcity != null && mcity.length > 0){ address += (address.length > 0 ? " " : "") + mcity; }
            if(mstate != null && mstate.length > 0 && mstate != "NONE"){ address += " " + mstate; }
        }
        
        if(address == null || address.length == 0)
        {
            address = GSM.determineAltAddress();
        }
           
        GSM.getGeocode(address);
    },
    
    determineAltAddress : function() {
            var result = "";
            var akZip = GSM.getAkamaiValue("zip");
            if(akZip != null) { result = akZip.substring(0,5); }
            else { result = GSM.locDefaultAddr; }
            
            return result;
    },
    
    getGeocode : function(address) {
        if(address != null && address.length > 0) {
            GSM.geocoder = new GClientGeocoder();
            GSM.geocoder.getLatLng(address,
            function(point) {

                if(!point){ 
                    GSM.handleErrorMessage("The address you have provided cannot be found.  Please try again.", true, GSM.mapOptMsgId);
                    var altAddress = GSM.determineAltAddress();
                    GSM.getGeocode(altAddress);
                }  
                else {
                    GSM.centerpt = point;
                    GSM.mapInit(point.y,point.x);
                    GSM.getStoreLocs(address,point.x,point.y);
                    GSM.map.setCenter(point, GSM.defaultZoom);
                    GSM.geocoder.getLocations(address, GSM.addAddressToMap);
                    
                    GSM.toggleLoading(false);
                }
            });
        }
    },
    
    handleErrorMessage : function(msg, limitMap, altId) {
        var infoArea = document.getElementById(GSM.locListId);
        if(altId != null) { GSM.addElementText(document.getElementById(altId),msg); }
        else { GSM.addElementText(infoArea,msg); }
        GSM.toggleListControls(limitMap);
        GSM.toggleLoading(false);
    },
    
    toggleListControls : function(isError) {
        if(isError == true){
            // Need to toggle in home service when no map or matches
            GSM.reportInHomeSvc(null);
            document.getElementById(GSM.locMapInfoAreaId).style.visibility = "visible";
        }
        document.getElementById(GSM.locMapZoomCtrlId).style.visibility = ( GSM.map == null ? "hidden" : "visible" );
        GSM.setPagingInfo();
    },
    
    processAkamaiCookie : function() {
    
        if(GSM.akamaiVals == null){
            var tmpAkamai = getCookie(GSM.infoCookieId);
            if(tmpAkamai != null && tmpAkamai.length > 0) {
            
                var akVals = tmpAkamai.split(",");
                GSM.akamaiVals = akVals;
            }
        }
    },
    
    getAkamaiValue : function(_key) {
        
        var result = null;
        if(GSM.akamaiVals == null) { GSM.processAkamaiCookie() }
        
        if(GSM.akamaiVals != null) {
        
            result = GSM.getValByKey(GSM.akamaiVals, _key);    
        }
        
        return result;
    },  
    
    getValByKey : function (vals,_key) {
    
        var result = null;
        
        for(i=0; i < vals.length; i++) {
            var cDE = vals[i].split("=");
            var cKey = cDE[0];
            var cVal = cDE[1];
            if(_key == cKey) { result = cVal; break; }
        }
        
        return result;
    },  
    
    toggleLoading : function(showLoading){
        
        document.getElementById(GSM.mapLoadId).style.height = ( showLoading == true ? "14px" : "0" );
        document.getElementById(GSM.mapLoadId).style.visibility = ( showLoading == true ? "visible" : "hidden" );
        document.getElementById(GSM.mapBodyId).style.visibility = ( showLoading == true ? "hidden" : "visible" ); 
    },
    
    addElementText : function(el,elText) {
	var newText = document.createTextNode(elText);
        el.appendChild(newText);
    },
    
    clearElementContent : function(el) {
        if(el != null && el.hasChildNodes()) {
            var pNode = el.parentNode;
            var copyNode = el.cloneNode(false);
            pNode.insertBefore(copyNode,el);
            pNode.removeChild(el);
        }
    },
    
    handleMapZoom : function(oldZoomLevel, newZoomLevel){
        if(newZoomLevel < GSM.minZoomLvl) { GSM.map.zoomIn(); }     // increases zoom level
        if(newZoomLevel > GSM.maxZoomLvl) { GSM.map.zoomOut(); }    // decreases zoom level
        resetInfoWindows();
    },
    
    clearMapMarkers : function() {
        if(GSM.map && GSM.centermkr) { GSM.map.removeOverlay(GSM.centermkr); }
        for(var i=0; i<GSM.locmarkers.length; i++) { GSM.map.removeOverlay(GSM.locmarkers[i]); }
        GSM.locmarkers = [];
    },
    
    getMarkerIcon : function(color) {    
        var icon = new GIcon();
        icon.image = GSM.basePath + "img/mm_20_" + color + ".png";
        icon.shadow = GSM.basePath + "img/mm_20_shadow.png";
        icon.iconSize = new GSize(12, 20);
        icon.shadowSize = new GSize(22, 20);
        icon.iconAnchor = new GPoint(6, 20);
        icon.infoWindowAnchor = new GPoint(5, 1);
        return icon;
    },
    
    getStoreLocs : function(address, ptx, pty) {

        var partnerCookie = getCookie("gsPartnerID");
        
        if(partnerCookie == null || partnerCookie.length == 0) { partnerCookie = ""; }
        else { GSM.handleIncomingPartner(); }
        
        GDownloadUrl(GSM.basePath + GSM.dataProviderPage + "?dist=" + GSM.dmaxradius + "&lat=" + pty + "&lng=" + ptx + "&maxcap=" + GSM.dservicemax + "&store_type=" + partnerCookie, 
            function(data, responseCode) {
                
                var xml = GXml.parse(data);  
                var mlen = 0;
                
                if(xml.documentElement){
                    GSM.loadSvcLabels();  // ought to come from the xml doc
                    var markers = xml.documentElement.getElementsByTagName("marker");
                    var ritags = xml.documentElement.getElementsByTagName("requestinfo");
                    mlen = markers.length;
                    GSM.reportInHomeSvc(ritags[0]);
                }
                
                if(mlen == 0) { GSM.toggleLoading(false); GSM.handleErrorMessage("Sorry, there were no locations near " + address, false, null) }
                else {
                    var infoArea = document.getElementById(GSM.locListId);
                     GSM.toggleListControls(false);
                    
                    for (var i = 0; i < mlen; i++) {
                    
                        GSM.processMarkerNode(markers[i],i,address,infoArea);
                    }
                    
                    GSM.fillLocationListArea(); 
                }
             });
    },
    
    loadSvcLabels: function() {
        GSM.svcLabels = {
            smb: "Small Business",
            pc: "Computer Services",
            ht: "Home Theater Services",
            car: "Car Electronics",
            apple: "Apple/Mac",
            marine: "Marine Services",
            isr: "In-Store Reservations"
        };
    },

    
    // Iterate through the collection of loc objects and display those that are marked visible
    fillLocationListArea : function() {
    
        var infohead = document.getElementById(GSM.locMapInfoHeadId);
        var infoArea = document.getElementById(GSM.locListId);
        var itemsAdded = 0;

        $(GSM.locMapInfoHeadId).empty();
	       
        var tempHtml = "";
        var firstset = GSM.locitems.length < 5 ? GSM.locitems.length : 5;
        
        var pageNo = 1;
        var colCt = 0;
        
        for(var i=0; i<GSM.locitems.length; i++) {
            var li = GSM.locitems[i];
            if(li.visible == true) {
                if(colCt == 5) { colCt = 1; pageNo ++; }
                else { colCt ++; }
                itemsAdded ++;
                li.listPos = itemsAdded;
                li.partOfPage = pageNo;
               
                tempHtml += li.innerContent; 
            } 
        }

        $(GSM.locListId).empty();
        infoArea.innerHTML = tempHtml;
        
        $(GSM.locListId).setHTML(tempHtml) ;
        
        GSM.visibleLocCt = itemsAdded;
        GSM.currentPage = 1;
        infohead.innerHTML =  itemsAdded + " location" + ( itemsAdded > 1 || itemsAdded == 0 ? "s" : "") + " in your area";
        GSM.setPagingInfo();
    },
    
    buildLocNode : function(li) {
    
        var mainDiv = document.createElement("div");
        mainDiv.className = "mapInfoItem";
        mainDiv.setAttribute("id",li.idRef);
        
        var img1 = document.createElement("img");
        img1.setAttribute("src",GSM.basePath + "img/mm_20_" + li.color + ".png");
        img1.onclick = new Function(li.showJS);
        img1.className = "locPinImg";
        
        var img2 = document.createElement("img");
        img2.setAttribute("src",GSM.basePath + "img/loc_" + li.storecode + "_med.gif");
        img2.className = "locImage";
        
        var bTag = document.createElement("b");
        var aTag = document.createElement("a");
        aTag.setAttribute("href",li.showJS);
        aTag.appendChild(document.createTextNode(li.stype));
        bTag.appendChild(aTag);
        
        mainDiv.appendChild(img1);
        mainDiv.appendChild(img2);
        mainDiv.appendChild(bTag);
        mainDiv.appendChild(document.createElement("br"));
        mainDiv.appendChild(document.createTextNode(li.addr1));
        mainDiv.appendChild(document.createElement("br"));
        mainDiv.appendChild(document.createTextNode(li.city + ", " + li.state + "  " + li.zip));
        mainDiv.appendChild(document.createElement("br"));
        
        var bTag2 = document.createElement("b");
        bTag2.appendChild(document.createTextNode("Phone"));
        mainDiv.appendChild(bTag2);
        
        mainDiv.appendChild(document.createTextNode(" " + li.phone));
        mainDiv.appendChild(document.createElement("br"));
        mainDiv.appendChild(document.createTextNode("~" + Math.round(li.dist*Math.pow(10,1))/Math.pow(10,1) + " miles" + "  "));
         
        var aTag2 = document.createElement("a");
        aTag2.setAttribute("href","javascript:linkTracking('directions','left_nav');flexWin('http://maps.google.com/maps?saddr=" + GSM.centerpt.lat() + "," + GSM.centerpt.lng() + "(" + encodeURI(li.address) + ")&daddr=" + li.point.lat() + "," + li.point.lng() + "(" + encodeURI(li.stype + "-" + li.loc) + ")','yes',1100,750,'resizable','all',100,100,0);");
        aTag2.className = "arrowTextLink";
        aTag2.appendChild(document.createTextNode("Directions"));
        
        mainDiv.appendChild(aTag2);
                   
        return mainDiv;
    },
    
    // Turn off defined filter checkboxes for users coming from partner sites
    handleIncomingPartner : function() {
        // All boxes are defaulted to be unchecked.  Check them all first.
        for(var a=0; a<GSM.filterIds.length; a++) {
            var acbx = document.getElementById(GSM.filterIds[a]);
            if(acbx != null) { acbx.checked = true; }
        }
    
        // Now uncheck those that should be.
        for(var b=0; b<GSM.partnerOffIds.length; b++) {
            var bcbx = document.getElementById(GSM.partnerOffIds[b]);
            if(bcbx != null) { bcbx.checked = false; }
        }  
    },
    
    // Read the svc attribute from the xml result and use it to toggle 
    //service availability image & copy
    reportInHomeSvc : function(infoNode){
        var ihSvc;
        var msgarea = document.getElementById(GSM.locMapSvcMsgId);
        
        if(infoNode != null) {
            ihSvc = infoNode.getAttribute("svc");
        }
        
        if(ihSvc == "True"){ msgarea.style.background = "url('/apps/locator/img/inhome-is-avail.gif') no-repeat"; }
        else{ msgarea.style.background = "url('/apps/locator/img/inhome-isnot-avail.gif') no-repeat"; }
    },
    
    // Provided the xml node that represents a location, read its attributes to build a 
    // GLocListItem object and add it to the GSM's locmarkers collection
    processMarkerNode : function(cmarker,i,address,infoArea){
    
        var point = new GLatLng(parseFloat(cmarker.getAttribute("lat")), parseFloat(cmarker.getAttribute("lng")));    
        var stype = cmarker.getAttribute("type");
        var loc = cmarker.getAttribute("location");
        var laddr1 = cmarker.getAttribute("address1");
        var laddr2 = cmarker.getAttribute("address2");
        var lcity = cmarker.getAttribute("city");
        var lstate = cmarker.getAttribute("state");
        var lzip = cmarker.getAttribute("zip");
        var lphone = cmarker.getAttribute("phone");
        var dist = cmarker.getAttribute("distance");
        var svclist = cmarker.getAttribute("svcs");
        var appleFlag = cmarker.getAttribute("apple_flag");
        
        if(lphone == "0") { lphone = ""; }
        
        var idRef = "mapLocItem" + i;
        var hbxAddress = stype + "_" + laddr1 + "_" + lcity + "_" + lstate;
        
        var infoContent = laddr1 + "<br/>"; 
            infoContent += lcity + ", " + lstate + "&nbsp;&nbsp;" + lzip + "<br/>"; 
            infoContent += "<b>Phone</b>&nbsp;" + lphone + "<br/>"; 
            infoContent += "~" + Math.round(dist*Math.pow(10,1))/Math.pow(10,1) + " miles" + "&nbsp;&nbsp;";  
        
        var newLoc = new GSLocListItem(idRef,infoContent,address,point,stype,loc,i,svclist,true,appleFlag,hbxAddress);
        newLoc.addr1 = laddr1;
        newLoc.addr2 = laddr2;
        newLoc.city = lcity;
        newLoc.state = lstate;
        newLoc.zip = lzip;
        newLoc.phone = lphone;
        newLoc.dist = dist;
        
        GSM.locitems[i] = newLoc;
        
        var icon = GSM.getMarkerIcon(newLoc.color);
        var mkr = GSM.createMarker(point,icon,newLoc.infoWindowContent,idRef,hbxAddress,i);
        GSM.map.addOverlay(mkr);
        GSM.locmarkers[i] = mkr;
    },
    
    buildLinkTracking : function(op, lid, lpos) {
        return "linkTracking('" + op + lid + "','" + lpos + "')";
    },
    
    // Build the link to connect the loc address to google maps
    buildDirectionLink : function(address,point,stype,loc,lpos,appendLID) {
        
        return "<a href=\"javascript:" + GSM.buildLinkTracking("directions", appendLID, lpos) + ";flexWin('http://maps.google.com/maps?saddr=" + GSM.centerpt.lat() + "," + GSM.centerpt.lng() + "(" + encodeURI(address) + ")&daddr=" + point.lat() + "," + point.lng() + "(" + encodeURI(stype + "-" + loc) + ")','yes',1100,750,'resizable','all',100,100,0);\">Directions</a>"; 
    },
    
    buildReservationsLink : function(lpos, lid) {
        return "<a href=\"javascript:" + GSM.buildLinkTracking("reservations", lid, lpos) + ";flexWin('http://reservations.geeksquad.com','yes',1100,750,'resizable','all',100,100,0);\">Reservations</a>"; 
    },
        
    // Find the marker matching the idx and fire its click event
    showMarker : function(idx) {
        var newmarker = GSM.locmarkers[idx];
        GSM.tgtLpos = "left_nav";
        GEvent.trigger(newmarker, "click"); 
    },
    
    // Create a new google map marker
    createMarker : function(point, icon, iwContent, idRef, hbxAddress, i) {  
        var newmarker = new GMarker(point,icon);  
        newmarker.hbxAddr = hbxAddress;
        
        // the following is used to set up custom info windows 
        GEvent.addListener(newmarker, "click", function() {

		    if(newmarker.GSIWInstance) {
		        newmarker.closeGSIW();
		        GSM.currentmkr  = null;
	        } else {
	            
	            GSM.currentmkr = newmarker;
	            
	            if(GSM.tgtLpos != null && GSM.tgtLpos != "") {
	                linkTracking(hbxAddress,GSM.tgtLpos);
	                GSM.tgtLpos = null;
	            }
	            else {
	                linkTracking(hbxAddress,"map_marker");
	            }
	            newmarker.openGSIW("<div class=\"mapInfoWindow\">"+ iwContent + "</div>");
	        }
	        
	        var tgtEl = document.getElementById(idRef);
	        if(tgtEl && GSM.currentPage != GSM.locitems[i].partOfPage) {
	            //  Need to get a new Fx.Scroll object because the list can dynamically change in size.
	            var scroller = new Fx.Scroll(GSM.locListId, { wait: false, duration: GSM.scrollDuration, transition: Fx.Transitions.Quad.easeInOut });
	            scroller.toElement(tgtEl);
	            
	            GSM.currentPage = GSM.locitems[i].partOfPage;
	            GSM.setPagingInfo();
	            
	            scroller = null;
	        }    
	    });
        
        return newmarker;
    },
    
    addAddressToMap : function(response) { 
        if (!response || response.Status.code != 200) { /*TODO:  Anything to record on failed address lookups?*/ } 
    },
    
    //  Handle click of the service type filter checkboxes 
    handleMapChecks : function(theTag, service, lpos) {
        var checkState;
        theTag.checked == true ? checkState = "_true" : checkState = "_false";   
        linkTracking(service + checkState, lpos);
        GSM.resetScroll();
        GSM.toggleVisibilityByService(theTag,service);
    },
    
    toggleVisibilityByService : function(theTag,service) {
    
        if(GSM.currentmkr != null && GSM.currentmkr.GSIWInstance) { GSM.currentmkr.closeGSIW(); }
        
        //Get the collection of filter checkboxes - need to know if they are checked
        if(GSM.filterBoxes.length == 0) { 
            for(var f=0; f<GSM.filterIds.length; f++){ GSM.filterBoxes[f] = document.getElementById(GSM.filterIds[f]); }
        }
        
        // Get the collection of filter checkboxes who are currently checked
        var checkedSvcs = new Array();
        for(var g=0; g<GSM.filterBoxes.length; g++) {
            if(GSM.filterBoxes[g].checked == true){ checkedSvcs[checkedSvcs.length] = GSM.filterBoxes[g]; }
        }
        
        // Reset by hiding every location until they meet all reqs.
        for(var e=0; e<GSM.locitems.length; e++) { GSM.locitems[e].visible = false; GSM.locmarkers[e].hide(); }
        
        if(checkedSvcs.length == 0) {
            // Show 'em all because no filters are set
            for(var e=0; e<GSM.locitems.length; e++) { GSM.locitems[e].visible = true; GSM.locmarkers[e].show(); }
        }
        else {
        
            // For each checked box, iterate through the locitems.  
            // If they offer a service, set their visibility to true.  If not, set it to false.
            var svcLn = checkedSvcs.length;
            
            for(var z=0; z<GSM.locitems.length; z++) {
                var ci = GSM.locitems[z];
                var matchCt = 0;

                if(ci.svcs.length < svcLn) {
                    //  You know this location doesn't offer at least one of the services.  Doesn't matter which, so...
                    ci.visible = false; GSM.locmarkers[ci.i].hide(); }
                else
                {
                    // Go through the checked services and make sure each is represented in this ci.svcs array
                    for(var h=0; h<svcLn; h++) {
                    
                        
                        var cSvcVal = checkedSvcs[h].getAttribute("servicetype");
                         
                        // Make sure this ci has this service
                        for(var k=0; k<ci.svcs.length; k++){ 
                            if(cSvcVal == ci.svcs[k]) { 
                                matchCt ++; 
                            } 
                        }
                    }  
                }
                
                if(matchCt == svcLn) { 
                    ci.visible = true; 
                    GSM.locmarkers[ci.i].show(); 
                }
                else { ci.visible = false; GSM.locmarkers[ci.i].hide(); }
            }   
        }
        
        GSM.fillLocationListArea();
    },
    
    resetScroll : function() {
        GSM.lwCurrentTop = 0;
        var scroller = new Fx.Scroll(GSM.locListId, { wait: false, duration: GSM.scrollDuration, transition: Fx.Transitions.Quad.easeInOut });
        scroller.scrollTo(0,0);
    },
    
    locWinScroll : function(dir) {

        //  Need to get a new Fx.Scroll object because the list can dynamically change in size.
        var scroller = new Fx.Scroll(GSM.locListId, { wait: false, duration: GSM.scrollDuration, transition: Fx.Transitions.Quad.easeInOut });
       
        if(dir == "down") {
            GSM.lwCurrentTop += 415;
            scroller.scrollTo(0,GSM.lwCurrentTop);
            GSM.currentPage = GSM.currentPage + 1;
        } 
        else {
            
            GSM.lwCurrentTop -= 415;
            
            if(GSM.lwCurrentTop < 0) 
            { 
                GSM.lwCurrentTop = 0;
            } 
	        
	        scroller.scrollTo(0,GSM.lwCurrentTop);
	        GSM.currentPage = GSM.currentPage - 1;
        }
        
        scroller = null;
        
        GSM.setPagingInfo();
    },
    
    setPagingInfo : function() {
        
        var totalPgs = Math.ceil(GSM.visibleLocCt/GSM.lwItemsPP);
        
        if(GSM.currentPage < 1) { GSM.currentPage = 1; }
        if(GSM.currentPage > totalPgs) { GSM.currentPage = totalPgs; }
        
        var msg = "Page " + GSM.currentPage + " of " + totalPgs;
        window.status = msg;
        
        for(var i=0; i<GSM.pageMsgIds.length; i++){ 
            var msgTag = document.getElementById(GSM.pageMsgIds[i]); 
            
            msgTag.innerHTML = "";
            msgTag.innerHTML = msg;
        }
        
        if(GSM.hidePgrOnEdge == true) {
            var ltTop = document.getElementById(GSM.pagerLTop);
            var ltBtm = document.getElementById(GSM.pagerLBtm);
            var rtTop = document.getElementById(GSM.pagerRTop);
            var rtBtm = document.getElementById(GSM.pagerRBtm);
        
            ltTop.style.visibility = GSM.currentPage <= 1 ? "hidden" : "visible";
            ltBtm.style.visibility = GSM.currentPage <= 1 ? "hidden" : "visible";
            rtTop.style.visibility = GSM.currentPage == totalPgs ? "hidden" : "visible";
            rtBtm.style.visibility = GSM.currentPage == totalPgs ? "hidden" : "visible";
        }
    }   
};

//===================================================================================================================
// Represents the zoom slider that is part of the map zoom/pan control
// functions that supply appropriate zoom level and y positions (getZoomLevelForY and getYPosForZoom)
// are intended to properly handle zoom and click positioning for a specific sized slider image with
// a specific number of tick marks.  

var GSSlider =
{
    handleId : "mapZoomHandle",
    sliderId : "mapZoomSlider",
    slider : null,
    isIE : false,
    zoomSlider : null,
    isSliding : false,
    
    createSlider : function() {
        
        var container = document.getElementById(GSSlider.sliderId);
        var zoomHandle = null;
        var agent = navigator.userAgent.toLowerCase(); 
        if ((agent.indexOf("msie") > -1) && (agent.indexOf("opera") < 1)){GSSlider.isIE = true} else {GSSlider.isIE = false}
        
        /*
        if (GSSlider.isIE) {
          var loader = "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/apps/locator/img/ticker.png', sizingMethod='scale');";
          container.innerHTML = '<div style="height:95px; width:23px; ' + loader + '" ></div>';
        } 
        else {
          container.innerHTML = '<img src="/apps/locator/img/ticker.png"  width=23 height=95 >';
        }
        */
        
        if (GSSlider.isIE) {
          var loader = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/apps/locator/img/zoom-controller.png', sizingMethod='scale');";
          zoomHandle = document.createElement("div"); 
          zoomHandle.setAttribute("id", GSSlider.handleId);
          zoomHandle.style.height="9px";
          zoomHandle.style.width="23px";
          zoomHandle.style.filter=loader;
        } 
        else {
          zoomHandle = document.createElement("img"); 
          zoomHandle.setAttribute("id", GSSlider.handleId);
          zoomHandle.src = "/apps/locator/img/zoom-controller.png";
          zoomHandle.height = "9";
          zoomHandle.width = "23";
        }
        container.appendChild(zoomHandle);
        
        GSSlider.zoomSlider = new GDraggableObject(zoomHandle, {container:container});
        
        GEvent.addListener(GSSlider.zoomSlider, "drag", function() {GSSlider.whileDrag()});
        GEvent.addListener(GSSlider.zoomSlider, "dragend", function() {GSSlider.dragEnd()});
    },
 
    sliderClick : function(evt, theTag) {   
        
        if(GSSlider.isSliding == false) {
            var e = (window.event) ? window.event : evt;
            var y;

            if(GSSlider.isIE){ y = e.offsetY; }
            else { y = e.layerY; }
            
            var z = GSSlider.getZoomLevelForY(y);
            GSM.map.setZoom(z);
        }
    },
    
    whileDrag : function() {
        GSSlider.isSliding = true;
    },
    
    dragEnd : function() {
        
        var y = GSSlider.zoomSlider.top;
        var z = GSSlider.getZoomLevelForY(y);
	    GSM.map.setZoom(z);
    },
    
    zoomEnd : function(oldZoomLevel, newZoomLevel) {
        if(newZoomLevel >= GSM.minZoomLvl && newZoomLevel <= GSM.maxZoomLvl) {
            var y = GSSlider.getYPosForZoom(newZoomLevel);
            GSSlider.assignYPosition(y);
        } 
        
        setTimeout("GSSlider.isSliding = false;",1000); 
    },
    
    assignYPosition : function(y) {
        var handleTag = document.getElementById(GSSlider.handleId);
		handleTag.style.top = y + "px";
		GSSlider.zoomSlider.top = y;
    },
    
    getZoomLevelForY : function(y) {
        if (y>=0 && y<=1)  { return 20; }
        if (y>1 && y<=2)   { return 19; }
        if (y>2 && y<=3)   { return 18; }
        if (y>3 && y<=10)  { return 17; }
        if (y>10 && y<=18) { return 16; }
        if (y>18 && y<=27) { return 15; }
        if (y>27 && y<=37) { return 14; }
        if (y>37 && y<=46) { return 13; }
        if (y>46 && y<=55) { return 12; }
        if (y>55 && y<=63) { return 11; }
        if (y>63 && y<=72) { return 10; }
        if (y>72 && y<=82) { return 9; }
        if (y>82 && y<=90) { return 8; }
        if (y>90 && y<=91) { return 7; }
        if (y>91 && y<=93) { return 6; }
        
        return 0
    },
    
    getYPosForZoom : function(z) {
        var result = 0;
        
        switch(z)
        {
            case(20): { result = 1; break; }
            case(19): { result = 2; break; }
            case(18): { result = 3; break; }
            case(17): { result = 4; break; }
            case(16): { result = 11; break; }
            case(15): { result = 19; break; }
            case(14): { result = 28; break; }
            case(13): { result = 38; break; }
            case(12): { result = 47; break; }
            case(11): { result = 56; break; }
            case(10): { result = 64; break; }
            case(9):  { result = 73; break; }
            case(8):  { result = 83; break; }
            case(7):  { result = 91; break; }
            case(6):  { result = 93; break; }
        }
        
        return result;
    }
};

//===================================================================================================================
// Location List Item

function GSLocListItem(_idRef,_infoContent,_address,_point,_stype,_loc,_i,_svcs,_visible,_appleFlag,_hbxAddress) {
    
    this.idRef = _idRef;
    this.infoContent = _infoContent
    this.address = _address;
    this.hbxAddress = _hbxAddress;
    this.point = _point;
    this.stype = _stype;
    this.loc = _loc;
    this.i = _i;
    this.visible = _visible;
    this.svcs = new Array();
    this.listPos = 0;
    this.partOfPage = 0;
    this.appleFlag = _appleFlag;
    this.storecode = null;
    this.showJS = null;
    this.storeImgCSS = null;
    this.addr1 = null;
    this.addr2 = null;
    this.city = null;
    this.state = null;
    this.zip = null;
    this.phone = null;
    this.dist = null;
    
    if(_svcs != null && _svcs.length > 0) {
        var svcList = _svcs.split(","); 
        for(var i=0; i<svcList.length; i++){
            var cDE = svcList[i].split("=");
            if(cDE[1] == "Y"){ this.svcs[this.svcs.length] = cDE[0]; }
        }
    }
    
    this.storeImgCSS = "mapIWStore";
    
    switch(this.stype){
        case("Best Buy"): { this.storecode = "bestbuy"; this.color = "blue"; break; }
        case("Best Buy Mobile"): { this.storecode = "bestbuymobile"; this.color = "blue"; break; }
        case("Geek Squad"): { this.storecode = "geek"; this.color = "orange"; break; }
        case("Fedex Kinkos"): { this.storecode = "fedexk"; this.color = "grey"; this.storeImgCSS = "mapIWStoreWide"; break; }
        default : { this.storecode = "bestbuy"; this.color = "blue"; break; }
    }
    
    var optAppImg = "";
    var optAppIWImg = "";
    
    if(this.appleFlag == "y" || this.appleFlag == "Y") {
        var appMsg = "Apple Authorized Service Provider";
        
        optAppImg = "<img src=\"" + GSM.basePath + "img/st-apple-auth.gif" + "\" class=\"locImageOptional\" title=\"" + appMsg + "\" alt=\"" + appMsg + "\" />";
        optAppIWImg = "<img src=\"" + GSM.basePath + "img/st-apple-auth.gif" + "\" class=\"mapIWSvcImg\" title=\"" + appMsg + "\" alt=\"" + appMsg + "\" />"; 
    }
    
    this.svcsContent = "<div class=\"mapIWSvcImgCtr\">";
    
    this.svcsContent += optAppIWImg;
    
    for(var j=0; j<this.svcs.length; j++) {
        var svcKey = this.svcs[j];
        var svcText = "";
        if (GSM.svcLabels[svcKey])
            svcText = GSM.svcLabels[svcKey];
        var svcTitle = "title=\"" + svcText + "\" alt=\"" + svcText + "\" ";
        var imgPath = GSM.basePath + "img/st-" + svcKey + "-info.gif";
        this.svcsContent += "<img src=\"" + imgPath + "\" class=\"mapIWSvcImg\" " + svcTitle + " />";
    }

    this.svcsContent += "</div>";
    
    this.showJS = "javascript:GSM.showMarker(" + this.i + ");";
    
    var hasInStoreReservations = false;
    for (var i=0; i<this.svcs.length; i++)
        if (this.svcs[i] == "isr")
            hasInStoreReservations = true;
    
    this.innerContent = "<div class=\"mapInfoItem\" id=\"" + this.idRef + "\">";
    this.innerContent += "<img src=\"" + GSM.basePath + "img/mm_20_" + this.color + ".png" + "\" class=\"locPinImg\" onclick=\"" + this.showJS + "\" />";
    this.innerContent += optAppImg;
    this.innerContent += "<img src=\"" + GSM.basePath + "img/loc_" + this.storecode + "_med.gif" + "\" class=\"locImage\" />";
    this.innerContent += "<b><a href=\"" + this.showJS + "\">" + this.stype + "</a></b><br/>";
    this.innerContent += this.infoContent;
    this.innerContent += "<span class=\"links\">";
    this.innerContent += GSM.buildDirectionLink(this.address,this.point,this.stype,this.loc,'left_nav','_' + this.hbxAddress);
    if (hasInStoreReservations)
        this.innerContent += " | " + GSM.buildReservationsLink('left_nav', '_' + this.hbxAddress);
    this.innerContent += "</span></div>"; 

    this.infoWindowContent = "<img src=\"" + GSM.basePath + "img/close.gif" + "\" class=\"mapIWClose\" onclick=\"javascript:linkTracking('close_icon','map_marker');resetInfoWindows();\" />";
    this.infoWindowContnet += "<img src=\"" + GSM.basePath + "img/loc_" + this.storecode + "_med.gif" + "\" class=\"" + this.storeImgCSS + "\" />";
    this.infoWindowContent += "<div class=\"mapIWMain\"><b>" + this.stype + "</b><br/>" + this.infoContent;
    this.infoWindowContent += "<span class=\"links\">" + GSM.buildDirectionLink(this.address,this.point,this.stype,this.loc,'map_marker','');
    if (hasInStoreReservations)
        this.infoWindowContent += " | " + GSM.buildReservationsLink('map_marker', '');
    this.infoWindowContent += "</span></div>";
    this.infoWindowContent += "<div class=\"mapIWSvc\"><b>Services Available</b><br/></div>";
    this.infoWindowContent += this.svcsContent;
}

//===================================================================================================================
//Functions to support custom info windows
var winCt;

function resetInfoWindows(){
    winCt = 0;
    for(var i=0; i<GSM.locmarkers.length; i++) {
        var cmkr = GSM.locmarkers[i];
        if(cmkr.GSIWInstance) {
		    cmkr.closeGSIW();
	    }
    }
}

function GSIW(marker,html,width){
	this.html_ = html;
	this.width_ = ( width ? width + 'px' : 'auto');
	this.marker_ = marker;
}

GSIW.prototype = new GOverlay();

GSIW.prototype.initialize = function(map) {
	this.map_ = map;
	var ctr = document.createElement("div");
	ctr.style.display='none';
	map.getPane(G_MAP_FLOAT_PANE).appendChild(ctr);
	this.ctr_ = ctr;

	var shadow = document.createElement("div");
	shadow.style.display='none';
	map.getPane(G_MAP_FLOAT_SHADOW_PANE).appendChild(shadow);
	this.shadow_ = shadow;
}

GSIW.prototype.remove = function() {
	this.ctr_.parentNode.removeChild(this.ctr_);
	this.shadow_.parentNode.removeChild(this.shadow_);
}

GSIW.prototype.copy = function() {
	return new GSIW(this.marker_,this.html_,this.width_);
}

GSIW.prototype.redraw = function(force) {
	if (!force || winCt > 0) return;
          
    winCt ++;
	var content = document.createElement("span");
	content.innerHTML = this.html_;
	content.style.border='0';
	content.style.display='inline';

	if(!this.width_ || this.width_=='auto' || this.width_ <= 0) {
		content.style.minWidth = '10px';
		content.style.maxWidth = '500px';
		content.style.width = 'auto';
	} 
	else {
		content.style.width= width + 'px';
	}

	content.style.visibility='hidden';

	this.map_.getContainer().appendChild(content);

	var contentWidth = 276;
	var contentHeight = 208; 
	
	content.parentNode.removeChild(content);
	content.style.visibility='visible';
	content.style.width=contentWidth+'px';
	content.style.height=contentHeight+'px';
	content.style.position='absolute';
	content.style.left='5px';
	content.style.top='7px';
	content.style.background='transparent';

	var wrapper = document.createElement("div");
    var img = document.createElement("img");
    img.src = GSM.basePath + "img/speech-bubble.png";
    img.className = "mapIWHelpPng";
    wrapper.appendChild(img);
	wrapper.appendChild(content);

	var pixelLocation = this.map_.fromLatLngToDivPixel(this.marker_.getPoint());

	this.ctr_.style.position='absolute';
	this.ctr_.style.left = (pixelLocation.x-10) + "px";
	this.ctr_.style.top = (pixelLocation.y - contentHeight - this.marker_.getIcon().iconSize.height) +  10 + "px";
	this.ctr_.style.border = '0';
	this.ctr_.style.margin = '0';
	this.ctr_.style.padding = '0';
	this.ctr_.style.display = 'block';
	this.ctr_.appendChild(wrapper);

	this.shadow_.style.position='absolute';
	this.shadow_.style.left = (pixelLocation.x-20) + "px";
	this.shadow_.style.top = (pixelLocation.y - this.marker_.getIcon().iconSize.height - 140) + 10 +"px";
	this.shadow_.style.border = '0';
	this.shadow_.style.margin = '0';
	this.shadow_.style.padding = '0';
	this.shadow_.style.display = 'block';
	
	var img = document.createElement('img');
	img.src = 'img/speech-bubble-shdw.png';
	img.className = "mapIWHelpPng";
	this.shadow_.appendChild(img);
}

GMarker.prototype.GSIWInstance = null;

GMarker.prototype.openGSIW = function(content,width) {
	resetInfoWindows();
	if(this.GSIWInstance == null) {
		GSM.map.setCenter(this.getPoint());
		this.GSIWInstance = new GSIW(this,content,width);
		GSM.map.addOverlay(this.GSIWInstance);
	}
}

GMarker.prototype.closeGSIW = function() {
	if(this.GSIWInstance != null) {
		GSM.map.removeOverlay(this.GSIWInstance);
		this.GSIWInstance = null;
	}
}
//===================================================================================================================