// CONFIGURATION FOR THE MAP
var mapCONFIG = {
    gIcon: [],
    gIconImages: [],
    initialize: function(){
        // set up pulte icons for the 3 sites + marker
        var mapIcon = new GIcon();
        mapIcon.shadow = "/img/locators/gIcon-shadow.png";
        mapIcon.iconSize = new GSize(22, 28);
        mapIcon.shadowSize = new GSize(37, 28);
        mapIcon.iconAnchor = new GPoint(10, 28);
        mapIcon.infoWindowAnchor = new GPoint(1, 3);
        mapIcon.printShadow = "/img/locators/gIcon-shadow.gif";
        // default icon
        this.gIcon['default'] = new GIcon(mapIcon);
        this.gIcon['default'].image = "/img/locators/gIcon-default.png";
        this.gIcon['default'].printImage = "/img/locators/gIcon-default.gif";
        this.gIcon['default'].mozPrintImage = "/img/locators/gIcon-default.gif";
        // category id: 1 = automotive
        this.gIcon['cat_1'] = new GIcon(mapIcon);
        this.gIcon['cat_1'].image = "/img/locators/gIcon-auto.png";
        this.gIcon['cat_1'].printImage = "/img/locators/gIcon-auto.gif";
        this.gIcon['cat_1'].mozPrintImage = "/img/locators/gIcon-auto.gif";
        // category id: 2 = Transit
        this.gIcon['cat_2'] = new GIcon(mapIcon);
        this.gIcon['cat_2'].image = "/img/locators/gIcon-transit.png";
        this.gIcon['cat_2'].printImage = "/img/locators/gIcon-transit.gif";
        this.gIcon['cat_2'].mozPrintImage = "/img/locators/gIcon-transit.gif";
        // category id: 3 = Convenience Store
        this.gIcon['cat_3'] = new GIcon(mapIcon);
        this.gIcon['cat_3'].image = "/img/locators/gIcon-store.png";
        this.gIcon['cat_3'].printImage = "/img/locators/gIcon-store.gif";
        this.gIcon['cat_3'].mozPrintImage = "/img/locators/gIcon-store.gif";
        // category id: 4 = Gas Station
        this.gIcon['cat_4'] = new GIcon(mapIcon);
        this.gIcon['cat_4'].image = "/img/locators/gIcon-gas.png";
        this.gIcon['cat_4'].printImage = "/img/locators/gIcon-gas.gif";
        this.gIcon['cat_4'].mozPrintImage = "/img/locators/gIcon-gas.gif";
        // category id: 5 = Restaurants/Fast Food
        this.gIcon['cat_5'] = new GIcon(mapIcon);
        this.gIcon['cat_5'].image = "/img/locators/gIcon-restaurant.png";
        this.gIcon['cat_5'].printImage = "/img/locators/gIcon-restaurant.gif";
        this.gIcon['cat_5'].mozPrintImage = "/img/locators/gIcon-restaurant.gif";
        // category id: 6 = Financial Services
        this.gIcon['cat_6'] = new GIcon(mapIcon);
        this.gIcon['cat_6'].image = "/img/locators/gIcon-finance.png";
        this.gIcon['cat_6'].printImage = "/img/locators/gIcon-finance.gif";
        this.gIcon['cat_6'].mozPrintImage = "/img/locators/gIcon-finance.gif";
        // category id: 7 = Drugstore/Pharmacy
        this.gIcon['cat_7'] = new GIcon(mapIcon);
        this.gIcon['cat_7'].image = "/img/locators/gIcon-drug.png";
        this.gIcon['cat_7'].printImage = "/img/locators/gIcon-drug.gif";
        this.gIcon['cat_7'].mozPrintImage = "/img/locators/gIcon-drug.gif";
        // category id: 8 = Medical Services
        this.gIcon['cat_8'] = new GIcon(mapIcon);
        this.gIcon['cat_8'].image = "/img/locators/gIcon-medical.png";
        this.gIcon['cat_8'].printImage = "/img/locators/gIcon-medical.gif";
        this.gIcon['cat_8'].mozPrintImage = "/img/locators/gIcon-medical.gif";
        // category id: 9 = Supermarket/Grocery
        this.gIcon['cat_9'] = new GIcon(mapIcon);
        this.gIcon['cat_9'].image = "/img/locators/gIcon-grocery.png";
        this.gIcon['cat_9'].printImage = "/img/locators/gIcon-grocery.gif";
        this.gIcon['cat_9'].mozPrintImage = "/img/locators/gIcon-grocery.gif";
        // category id: 10 = Personal &amp; Beauty
        this.gIcon['cat_10'] = new GIcon(mapIcon);
        this.gIcon['cat_10'].image = "/img/locators/gIcon-personal.png";
        this.gIcon['cat_10'].printImage = "/img/locators/gIcon-personal.gif";
        this.gIcon['cat_10'].mozPrintImage = "/img/locators/gIcon-personal.gif";
        // category id: 11 = Specialty Retail
        this.gIcon['cat_11'] = new GIcon(mapIcon);
        this.gIcon['cat_11'].image = "/img/locators/gIcon-speciality.png";
        this.gIcon['cat_11'].printImage = "/img/locators/gIcon-speciality.gif";
        this.gIcon['cat_11'].mozPrintImage = "/img/locators/gIcon-speciality.gif";
        // category id: 12 = Vending
        this.gIcon['cat_12'] = new GIcon(mapIcon);
        this.gIcon['cat_12'].image = "/img/locators/gIcon-vending.png";
        this.gIcon['cat_12'].printImage = "/img/locators/gIcon-vending.gif";
        this.gIcon['cat_12'].mozPrintImage = "/img/locators/gIcon-vending.gif";
        // category id: 13 = Entertainment
        this.gIcon['cat_13'] = new GIcon(mapIcon);
        this.gIcon['cat_13'].image = "/img/locators/gIcon-entertainment.png";
        this.gIcon['cat_13'].printImage = "/img/locators/gIcon-entertainment.gif";
        this.gIcon['cat_13'].mozPrintImage = "/img/locators/gIcon-entertainment.gif";
        // category id: 14 = Travel
        this.gIcon['cat_14'] = new GIcon(mapIcon);
        this.gIcon['cat_14'].image = "/img/locators/gIcon-travel.png";
        this.gIcon['cat_14'].printImage = "/img/locators/gIcon-travel.gif";
        this.gIcon['cat_14'].mozPrintImage = "/img/locators/gIcon-travel.gif";
        // category id: 15 = Other
        this.gIcon['cat_15'] = new GIcon(mapIcon);
        this.gIcon['cat_15'].image = "/img/locators/gIcon-other.png";
        this.gIcon['cat_15'].printImage = "/img/locators/gIcon-other.gif";
        this.gIcon['cat_15'].mozPrintImage = "/img/locators/gIcon-other.gif";
        // center icon
        this.gIcon['home'] = new GIcon(mapIcon);
        this.gIcon['home'].image = "/img/locators/gIcon-home.png";
        this.gIcon['home'].printImage = "/img/locators/gIcon-home.gif";
        this.gIcon['home'].mozPrintImage = "/img/locators/gIcon-home.gif";
        // on images
        this.gIconImages['default'] = {imageOn: "/img/locators/googleIcon-flagOn.png", imageOff: "/img/locators/googleIcon-flag.png"};
        this.gIconImages['home'] = {imageOn: "/img/locators/googleIcon-flagOn.png", imageOff: "/img/locators/googleIcon-flag.png"};
    }
};

mapCONFIG.initialize();
// end of map configuration ----------------------------------------

if (!VISA) { VISA = {}; }

VISA.payWave = (function() {
	
	// adapted from jQuery.toggleVal, http://kuzemchak.net/
	jQuery.fn.defaultVal = function() {
		return this.each(function() {
			$(this).focus(function() {
				$(this).removeClass("default");
				if ($(this).val() == this.defaultValue) {
					$(this).val("");
				} else {
					this.select();
				}
			}).blur(function() {
				if($(this).val() == "") {
					$(this).addClass("default");
					$(this).val(this.defaultValue);
				}
			});
		});
	}
	
	
	/* utility functions */
	
	if (typeof console == 'undefined') {
		console = {
			log: function(msg) { /* alert("log: " + msg); */ },
			warn: function(msg) { /* alert("warn: " + msg); */ }
		};
	}
	
	// template is a jQuery DOM reference
	// obj is a JS object
	// returns new jQ node
	function templatize(obj, $template) {
		$template = $($template); // make sure it is a jQ object
		$template = $template.clone();
		var html = $template.html();
		$.each(obj, function(key, val) {
            // translate category
            if (key == 'category_id') {
                val = category_translations[val]
            }
           // val = val.toString().replace("&", "&amp;");
            html = html.replace(new RegExp("{" + key + "}", "g"), val);
		});
		html = html.replace(/\{[^\}]+\}/g, ""); // remove unmatched items
		return $template.html(html);
	}
	
	// object to show and hide the progress meter, and block out the form elements, while network calls are made
	var progress = {
		count: 0,
		show: function(text) {
			$("#progress").show();
            $("#find").hide();
            this.count++;
        },
		hide: function(text) {
			if (--this.count <= 0) {
				this.count = 0;
				$("#progress").hide();
                $("#find").show();
            }
        }
	}

    var progressCat = {
        count: 0,
		show: function(text) {
            $("progress-category").height($('#filter-categories').height()-10);
            $("#progress-category").show();
            this.count++;
        },
		hide: function(text) {
			if (--this.count <= 0) {
				this.count = 0;
				$("#progress-category").hide();
            }
        }
    }


    /* paywave code */
	var map;
    var map_mgr;
    var geocoder;
    var all_drawn = false;
    var center_point;
	var origin_marker;
	var current_location;
    var geo_result;
    var existing_markers = [];
    var stores = [];
	var categories = {}; // populated with an Array from the server, but stored as a Hash for easy access
    var maxResultsCnt = 25;
    var catTimer;
    var selected_category = [];
    var pageTotal = 0;

    function error(message) {
		var $error = $("#addresses .error");
		if ($error.length < 1) {
			$error = $("<div>").addClass("error").prependTo("#addresses");
		}
		// make sure error will be seen
		if ($("#map").width() > 400) { toggle_map_width(); }
		$error.html(message).show();
	}
	
	
	
	
	
	
	function resize_contents() {

        var height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
		var width = $("#map").width(); // doesn't change, needed for map size method
        var merchantHeight = 0;
        if($("#featured_merchants").length > 0){
            merchantHeight = $("#featured_merchants").get(0).offsetHeight; 
        }

        var sub = getAbsoluteTop($("#results").get(0)) + merchantHeight - 5;
		height = Math.max(height - sub, 270); // must be at least 270
		height = Math.min(height, 500); // cap the height at 600
		// sometimes on IE the map is not fully initialized and this will fail
		// we can safely ignore this exception
        
        try {
			$("#map").css('width', width + "px");
            $("#map").css('height', height + "px");
            map.checkResize();
		} catch(e) {
			// ignore
		}
		$(".resizable").stop().height(height);
		$("#addresses").height(height-20);
        if(serviceType == "payWave") {
            $("#filter-categories").height(height-20);
        }
    }
	
	function toggle_map_width(event) {
		var height = $("#map").height();
		var width = $("#map").width();
		var full = $("#results").width();
		var new_width = width < full ? full : 400;
		
		if (width < full) {
			$("#expander").addClass("open").removeClass("hover");
			$("#list").hide();
		}
		if (map) {
            $("#map").css('width', new_width + "px");
            $("#map").css('height', height + "px");
            map.checkResize();
        }
		$("#map").width(new_width);
		$("#expander").css({left: new_width-18});
		if (width >= full) {
			$("#expander").removeClass("open hover");
			$("#list").show();
		}
	}
	
	// application intro animation and initialization
	// these are nested to avoid conflicting animations: they are sequential
	$(document).ready(function() {
        if($("#serviceType").length > 0){
            //$("#serviceType").val(serviceType);
            $("#serviceType").change(function() {
                if($(this).val() != ""){
                    location.href=$(this).val();
                }
            });
        }
        // we are animating multiple items, so this event gets fired multiple times
		// but it only responds once
		$(document).one("init", function() {
			// add a resize handler to the window set initial results size
			if(serviceType == "payWave") {
                maxResultsCnt = 100;
                // set up tabs function
                VISA.ui.tabs('#list', fixTabBorder);
            }

            $("#expander").click(toggle_map_width);
            // load the map API and run initial search
			init_gmap();
			// start the merchant list rotation
            if($("#featured_merchants").length > 0)
                rotate_merchant_list();

            $(window).resize(resize_contents).resize();
        });
		
		// set the starting location based on a cookie, or on the server-passed location
		// and set location field to get a default values when empty
		var loc = $.cookie("paywave-location") || edgescape_location;
		$("#location").val(loc).defaultVal();

        // if the page has category, then listen to the change event
        if($("#categories").length > 0){
            // set up categories based on Array from the server
            category_array.categories.sort(function(a,b) {
                // "Other" should always appear at the bottom
                if (a.name == "Other") { return 1; }
                else if (b.name == "Other") { return -1; }
                return category_translations[a.id].localeCompare(category_translations[b.id]);
            });

            $.each(category_array.categories, function(i, cat) {
                // map pin images based on category color
                cat.pin = "/img/locators/map_" + cat.color + ".gif";
                cat.hover = "/img/locators/hover_" + cat.color + ".gif";
                var className ='';
                if(i%2 == 0){
                    className =' class="odd"';
                }
                cat.$listing = $('<div' + className +'>').append('<input type="checkbox" name="category" value="' + cat.name + '" class="cat" />').append('<span>' + category_translations[cat.id] + '</span>').appendTo("#categories");
                //cat.$listing = $("<option>").val(cat.name).text(category_translations[cat.id]).appendTo("#categories");
                categories[cat.name] = cat;
            });

            // if user check all, uncheck the rest
            $('#cat-all').click(function(){
                if($("#cat-all").is(':checked')){
                    $('#categories .cat').filter(':not(:first)').attr("checked", "");
                }
            });

            // udpate the onchange event to onclick
            $("#submit-filter").click(function() {
                $('#result-tab-link a').click();
                filter_stores();
                $(this).trigger("categoryChanged"); // trigger custom analytics event
            });

            //set up print locator map function
            var printLink = null;
	    try {
		printLink = parent.document.getElementById('print-locator');
		}
	    catch (err) {
		// no action, just proceed
		}
            if(printLink){
                $(printLink).click(function(event){
                    printLocator();
                    event.preventDefault();
                });
            }            
        }

        // animate the visible items sequentially
        if($("#featured_merchants").length > 0){
            $("#featured_merchants tr").not(":first").fadeOut("fast");
            $("#featured_merchants").css("overflow", "hidden").animate({ height: 70, borderTopWidth: 0}, "fast", function() {
                $("#criteria, #results, .disclaimer").slideDown("fast", function() {
                    $(document).trigger("init");
                });
            });
        } else {
             $("#criteria, #results, .disclaimer").slideDown("fast", function() {
                    $(document).trigger("init");
                });
        }
        
		init_analytics();
	});

    function fixTabBorder() {
        if($('#cat-tab-link').hasClass("selected")){
            $('#results').addClass("borderOn");
        } else {
            $('#results').removeClass("borderOn");
        }
        if($('#addresses').hasClass('selected')){
            // add alt color on address area (we are doing it here is because payweve has category filter that will just hide stores
            $("#addresses .address:not(:hidden)").each(function(i){
                if(i%2 == 0){
                    $(this).removeClass("odd");
                } else {
                    $(this).addClass("odd");
                }
            });
        }
    };

    // handle disable and enable category checkbox
    function disableCategories (disableFlag) {
        if(disableFlag) {
            $.each(categories, function(name, cat) {
                cat.$listing
                    .find('input').attr("disabled", "disabled");
            });
        } else {
            $.each(categories, function(name, cat) {
                cat.$listing
                    .find('input').attr("disabled", ((cat.count && cat.count > 0) ? "" : "disabled"));
            });
        }
    };

    function init_gmap() {
        if (GBrowserIsCompatible()) {
            map = new GMap2($("#map").get(0));
            map.setCenter(new GLatLng(37.4419, -122.1419), 13);
            var customUI = map.getDefaultUI();
            customUI.controls.largemapcontrol3d  = true;
            customUI.controls.maptypecontrol  = false;
            customUI.controls.menumaptypecontrol = false;
            map.setUI(customUI);
            map_mgr = new MarkerManager(map);
            // set up geocoder
            geocoder = new GClientGeocoder();
            var countryCode = locale.split("_");
            if(countryCode.length > 1) {
                geocoder.setBaseCountryCode(countryCode[1]);
            } else {
                geocoder.setBaseCountryCode('US');
            }    
            // set the isclicked to be false
            GEvent.addListener(map, 'extinfowindowbeforeclose', function(){
                var openedWin = map.getExtInfoWindow();
                openedWin.marker_.isClicked = false;
            });

            // set up change event handler on find button field, and trigger it once
            $("#find").click(function() {
                var entered_location = $("#location").val();
                // test to make sure it is alphanumeric
                var alphaRegex = /^([A-Za-z0-9,\.\s])*$/;

                if(alphaRegex.test(entered_location)){
                    if (entered_location == current_location) {
                        map.setCenter(center_point);
                    } else {
                        progress.show("before geocode/search"); // hidden at end of 'search' handler
                        getGeoLocation(entered_location);
                    }
                };
            }).click();

            // if ie browser, trap the enter key to submit the form
            if($.browser.msie){
                $("#location").keypress(function(e){
                    var code = (e.keyCode ? e.keyCode : e.which);
                    if(code == 13){
                        $("#find").click();
                    }
                });
            }

            // also find if Enter is pressed in the Near field
            // this is NOT necessary on IE, which submits on return even through there is no form wrapper
            if ($.browser.msie) { return; }
            $("#location").keypress(function(event) {
                if (event.keyCode == 13) {
                    $(this).blur();
                    $("#find").trigger("click");
                }
            });



        }
    }

	// search geo location
    function getGeoLocation (address){
        geo_result = null;
        if(geocoder) {
            geocoder.getLatLng(address, function (point) {
                if(!point){
                    error($("#location").val() + " can't be found");
			        $("#location").val(current_location);
			        progress.hide("search failure");
                } else {
                    geo_result = point;
                    map.setCenter(geo_result);
                    search(address);
                }
                
            });
        }
    }

    function init_analytics() {
		// add some default parameters to all analytics calls from this page
		VISA.Analytics.addParameters({
			application:     "paywave",
			filter_category: function() { var categories = ''; $.each(selected_category, function(i, cat){if(categories != "") categories += ",";categories += cat;}); return categories; },
			map_location:    function() { return current_location; },
			map_coordinates: function() { return (center_point ? center_point.lat() + "," + center_point.lng() : ""); },
			map_size:        function() { return $("#map").width() + "," + $("#map").height(); }
		});
		
		// set up some custom analytics regions of the page
		$("#map, #list").addClass("analytics");
		
		// create some custom event handlers for analytics
        if($("#categories").length > 0){
            $("#submit-filter").bind("categoryChanged", VISA.Analytics.event);
        }
		$("#find").bind("locationChanged", VISA.Analytics.event);
		
		// bind and trigger an initial event beacon
		$("#map").bind("applicationLoaded", VISA.Analytics.event).trigger("applicationLoaded");
	}
	
	// filter the local dataset based on new map coordinates
	function search(address) {
		if (!geo_result) {
			error(address + " can't be found");
			$("#location").val(current_location);
			progress.hide("search failure");
			return;
		}
		var params = {
			type: "findStores",
			location: escape(address),
			lat: geo_result.lat(),
			long: geo_result.lng(),
            locale: locale,
            serviceType: serviceType,
            maxResults: maxResultsCnt
        };
		$.getJSON("/locators/paywave", params, function(json) {
            current_location = address;
			center_point = geo_result;
			all_drawn = false;

			map.setCenter(center_point, 7);
			$("#addresses").empty();
			$("#find").trigger("locationChanged"); // trigger custom analytics event

            if($("#categories").length > 0){
                // re-zero the category counts
                $("#categories input").attr("disabled", "disabled");
                $.each(categories, function(name, cat) { cat.count = 0; });

                $('#result-tab-link a').click();
            }
            
			stores = $.map(json.stores, function(json) {
                if($("#categories").length > 0){
                    var cat = categories[json.category];
				    if (cat) { cat.count += 1; }
                }
				return new Store(json);
			});
			stores.sort(function(a, b) { return a.distance - b.distance; });

            if($("#categories").length > 0){
                // update category with new counts
                $.each(categories, function(name, cat) {

                    cat.$listing
                        .find('span').text(category_translations[cat.id] + " (" + cat.count + ")")
                        .end()
                        .find('input').attr("disabled", ((cat.count && cat.count > 0) ? "" : "disabled"));
                });
                $("#categories input:first").attr("disabled", "");
            }
            
            // reset markers
            if(origin_marker){
                map.removeOverlay(origin_marker);
            }
            if(existing_markers.length > 0) {
                map_mgr.clearMarkers();
                map_mgr.refresh();
                existing_markers = [];
            }

            create_origin_marker(json.stores.length);
			if (!json.stores.length) {
				error(error_no_results);
			} else {
				$.cookie("paywave-location", address, { path: '/', expires: 100 });
				filter_stores();
			}
            if(origin_marker != null){
                map.addOverlay(origin_marker);
                // auto-open the panel when we first arrive on the page
                GEvent.trigger(origin_marker, "click");
            }
			progress.hide("search success"); // shown before geocoding starts, in init_map
		});
	}
	
	function create_origin_marker(store_count) {

		var $origin_panel = templatize({location: current_location}, "#templates .origin");
		
		if (store_count >= 100) {
			$origin_panel.find(".location_details").html(origin_msg_many_results + " ");
		} else if (store_count == 0) {
			$origin_panel.find(".location_details").addClass("error").html(origin_msg_no_results + " ");
			$origin_panel.find("p.details").html(origin_details_no_results);
		}

        origin_marker = create_marker(center_point, $origin_panel.html(), 'home');
    }

    function create_marker(point, html, iconType, address){
        
        var marker;
        marker = new GMarker( point, mapCONFIG.gIcon[iconType]);
        marker.GeoPoint = point;
        marker.isClicked = false;
        marker.hideFlag = false;
        //marker.imageOff = mapCONFIG.gIconImages[iconType].imageOff
        GEvent.addListener(marker, 'click', function(){
            marker.isClicked = true;
            if(typeof address != "undefined"){
               $("#addresses .active").removeClass("active");
               $(address).addClass("active");
               var offset = $(address).get(0).offsetTop + 1; // sometimes is -1?
               $("#addresses").stop().scrollTo({ left: 0, top: offset }, 500);
            }
            // close any open tool tip
            map.closeTooltipWindow();
            marker.openExtInfoWindow(
                map,
                "g_win",
                "<div class='contents'>" + html + "</div>",
                {beakOffset: 10}
            );
            window.setTimeout(function(){map.setCenter(point);}, 200); 
          });

        GEvent.addListener(marker, 'mouseover', function(){
            if(!marker.isClicked) {
                //marker.setImage(mapCONFIG.gIconImages[iconType].imageOn);
                marker.openTooltipWindow(
                    map,
                    "g_tip",
                    "<div class='contents'>" + html + "</div>",
                    {beakOffset: 10}
                );
            }
        });
        GEvent.addListener(marker, 'mouseout', function(){
            if(!marker.isClicked){
                //marker.setImage(mapCONFIG.gIconImages[iconType].imageOff);
                map.closeTooltipWindow();
            }
        });
        return marker;
    }
    
    function filter_stores() {
        progress.show("filter stores");
        // close any opened info window
        map.closeExtInfoWindow();
        $("#addresses .error").hide();
		var filtered_stores = stores;

        if($("#categories").length > 0){
            selected_category = [];
            $('#categories .cat').each(function(i, cat){
               
               if($(cat).is(':checked')) {
                selected_category.push($(cat).val());
               }
            });
            // user select something
            if(selected_category.length > 0){
                if(selected_category[0] == ""){
                    // if user select all, don't filter category   
                } else {
                    filtered_stores = $.grep(stores, function(store) {
                        var selectedCat = false;
                        $.each(selected_category, function(i, cat){
                            if(store.category == cat) {
                                selectedCat = true;
                            }
                        });
                        return selectedCat;
                    });
                }
            }

        } 
        //console.log("filtered_stores.length = " + filtered_stores.length);
		if (filtered_stores.length == 0) {
			// should only be possible on IE6, since other browsers disable the options with no matches
			error(error_no_results);
		}

        pageTotal = filtered_stores.length;
        
        $("#addresses").scrollTo({ left: 0, top: 0 }, 0);
		
		$.each(stores, function(i, store) {
            if (!store.isDrawn()) { store.draw(); }
			if ($.inArray(store, filtered_stores) > -1) { store.show();
            }
			else { store.hide(); }
        });

        if(!all_drawn){
            if(existing_markers.length > 0){
                map_mgr.addMarkers(existing_markers, 0);
            }
            all_drawn = true;
        }
        
        map_mgr.refresh();
        zoomToMarkers(10, 10, filtered_stores);

        /*
        if($("#categories").length > 0){
            $("#categories").attr("disabled", "");
        }
        */

        // add alt color on address area (we are doing it here is because payweve has category filter that will just hide stores
        $("#addresses .address:not(:hidden)").each(function(i){
            if(i%2 == 0){
                $(this).removeClass("odd");
            } else {
                $(this).addClass("odd");
            }
        });
        
        progress.hide("filter/draw stores");
	}
	
	// zoom to the first 20 markers
    function zoomToMarkers (slopPercentage, heightOffsetPct, filtered_stores) {
        if(!filtered_stores || !filtered_stores.length || filtered_stores.length < 1) return;

        var count = 0;
        var thePoint, x, y, minX, maxX, minY, maxY, span;

        $.each(filtered_stores, function(i, store){

                thePoint = store.GeoPoint;
                x = thePoint.lat()*1.0000000000000000; y = thePoint.lng()*1.0000000000000000;
                if (count == 0)
                {
                    minX = x; maxX = x; minY = y; maxY = y;
                }
                else
                {
                    if (x < minX) minX = x;
                    if (x > maxX) maxX = x;
                    if (y < minY) minY = y;
                    if (y > maxY) maxY = y;
                }
                count++;
                if(count > 24) return false;

        });

        if (count == 1)
            map.setCenter(new GLatLng(x,y), map.getZoom());
        else if (count > 1)
        {
            var center = new GLatLng((minX + maxX) / 2, (minY + maxY) / 2);
            span = new GSize(Math.abs(maxX - minX), Math.abs(maxY - minY));
            var slopWid = 0;
            var slopHgt = 0;
            var deltaHgt = 0;

            if (typeof slopPercentage != "undefined")
            {
                slopWid = span.width * slopPercentage / 200;
                slopHgt = span.height * slopPercentage / 200;
                span.width  *= 1 + slopPercentage / 100;
                span.height *= 1 + slopPercentage / 100;
            }

            if (typeof heightOffsetPct != "undefined")
            {
                deltaHgt = span.height * heightOffsetPct / 100;
                center = new GLatLng(center.lat() + deltaHgt, center.lng());
            }
            // needs slop
            var bounds = new GLatLngBounds(new GLatLng(minX-slopHgt, minY-slopWid), new GLatLng(maxX+slopHgt, maxY+slopWid)); // sw, ne
            var zoom = map.getBoundsZoomLevel(bounds);
            map.setCenter(center, zoom);
        }
    }
    
    function rotate_merchant_list() {
		// if there is only 1 row of logos, do not rotate
		if ($("#featured_merchants tr").length < 2){
			return false;
		}

		var logo_list = [];
		var interval = 3000;
		var fadeRate = 3000;
		var rowSize = 5;
		
		// rotates the merchants from the master list, when a element is hidden
		function swap_merchants() {
			var i = 0;
			var $row = $(this).find("tr").empty();
			while (i++ < rowSize) {
				var $logo = logo_list.shift();
				logo_list.push($logo);
				$row.append($logo);
			}
		}
		
		// get all of the table cells (randomize in the JSP code)
		$("#featured_merchants td").each(function() { logo_list.push($(this)); });
		// remove the excess rows and create two sets between which to rotate
		$("#featured_merchants tr").not(":first").remove();
		// duplicate the containing divs: trs do not fade in/out on IE
		var $row1 = $("#featured_merchants .logos");
		// should be able to clone, but jQ 1.2 has a problem on IE (leaves the clone, takes the original?)
		var $row2 = $("<div class='logos'>").insertAfter($row1).hide().html($row1.html());
		$(".logos").css("position", "absolute");        
        swap_merchants.call($row1);
		swap_merchants.call($row2);
		
		// swap the two rows on an repeating timeout (could use an interval instead)
		var rows = [ $row1, $row2 ];
		function fade_swap() {
			rows.push(rows.shift()); // swap order in array
			rows[0].fadeOut(fadeRate, swap_merchants);
			interval = (interval < 30000 ? interval += 100 : 30000); // slowly show down the rotation to every 30 seconds
			rows[1].fadeIn(fadeRate, function() { setTimeout(fade_swap, interval); });
		}
		setTimeout(fade_swap, 7000); // longer initial interval, to allow other page items to load
	}
	
	
	/*** start Store prototype ***/
	
	function Store(json) {
		$.extend(this, json);
		if (this.address2 == "" || this.address2 == "null") { delete this.address2; }
		try {
			this.GeoPoint = new GLatLng(this.latitude, this.longitude);
            this.distance = center_point.distanceFrom(this.GeoPoint, 3959);
            if (distance_unit == 'km') {
                this.distance = (this.distance * 1.609344);
            }

            if (this.distance.toFixed) { // pad with 2 degrees of precision
				this.distance = this.distance.toFixed(2);
			}
		} catch(e) {
			console.log("failed to set the distance"); // IE is sometimes failing, not sure why
		}
	}
	
	Store.prototype.draw = function() {
		this.$address = templatize(this, "#templates > .address");
		var $marker = templatize(this, "#templates > .overlay");

        if($("#categories").length > 0) {
            if (this.status != 1) { this.$address.add($marker).find(".coming_soon").remove(); }
        } else {
            this.$address.add($marker).find(".coming_soon").remove();
            this.$address.find(".category").remove();
        }

        if (this.logo) {
			$marker.find(".logo").append("<img src='/img/locators/" + this.logo + "' alt='" + this.name + "' />");
		}
        // if not paywave, check if phone number is null
        if(typeof isPaywave == 'undefined') {
            if(this.phoneno == "null" || this.phoneno == null){
                $marker.find(".phone_no").remove();
            }
        }

        var start_loc = escape($.cookie("paywave-location"));
		var end_loc = escape([this.address1, this.city, this.state, this.zip].join(","));

        $marker.find(".directions a")
			.attr("href", "http://" + maps_host + "/maps?saddr=" + start_loc + "&daddr=" + end_loc);
        var cat = categories[this.category];
        var iconType = "default";

        if (cat) {
            this.$address.find(".category").addClass("cat"+ cat.id);
            //this.$address.find(".category").css("background-color", "#" + cat.color);
            if(typeof isPaywave != 'undefined' && isPaywave)
                iconType = "cat_" + cat.id;
        }
		var gmarker = create_marker(this.GeoPoint, $marker.html(), iconType, this.$address);

        existing_markers.push(gmarker);
        this.markerIndex = existing_markers.length - 1;


		var me = this;
		var panel = $marker.find(".panel").get(0);
		// add hover and click events to both the address and the marker
		this.$address
			.hover(function(event) {
				//GEvent.trigger(gmarker, "mouseover");
                me.$address.addClass("hover");

            }, function() {
				//GEvent.trigger(gmarker, "mouseout");
                me.$address.removeClass("hover");
            })
			.bind("click", { merchant: this.name, category: category_translations[categories[this.category]]}, function(event) {
				// trigger custom analytics, but only if this item was not already selected
				if (!me.$address.is(".active")) { VISA.Analytics.event(event); }
			})
			.click(function(event) {
                GEvent.trigger(gmarker, "click");
                if ($(event.target).not("a").length) { // ignore clicks on links, e.g. 'driving directions'
					$("#addresses .active").removeClass("active"); // clear previous selections
					me.$address.addClass("active");
				} else { // link item, trigger link analytics
					VISA.Analytics.navigation(event);
				}
			});
		
		$("#addresses").append(this.$address);
	}
	
	Store.prototype.isDrawn = function() {
		return (this.$address != null);
	}
	
	Store.prototype.show = function() {
		//if(!all_drawn) return;
        this.$address.show();
        if(existing_markers.length > this.markerIndex ){
            existing_markers[this.markerIndex].hideFlag = false;
            existing_markers[this.markerIndex].show();
        }
	}
	
	Store.prototype.hide = function() {
		//if(!all_drawn) return;
        this.$address.hide();
        if(existing_markers.length > this.markerIndex ){
            existing_markers[this.markerIndex].hideFlag = true;
            existing_markers[this.markerIndex].hide();
        }
	};

    // print locator function  - zoe
    function printLocator (){
        var categories = '';
        $.each(selected_category, function(i, cat){
            if(categories != "") categories += ",";
            categories += getCategoryId(cat);
        });
        var printURL = '/locators/locator-print.jsp?location=' + escape($("#location").val()) + '&lat=' + geo_result.lat() + '&long=' + geo_result.lng();
        printURL += '&locale=' + locale + '&serviceType=' + serviceType + ((categories != "" || categories != "0")? ('&categories=' + categories): '')  + '&pageTotal=' + pageTotal;
        
        var props="scrollbars=yes,directories=no,status=no,resizable=yes,toolbar=no,menubar=no,top=50,left=50"
        popUp(printURL, 700, 600, props)
    }

    function getCategoryId (catName) {
        var catId = "0";
        $.each(category_array.categories, function(i, cat) {
            if(catName == cat.name) {
                catId = cat.id;
                return  false;
            }
        });
        return catId;
    }
	
})();
