if (typeof ihs == "undefined")
    var ihs = {};
ihs.gmap = {
    loaded: false,
    markers: [],
    map: null,
    mapElementID: "gmap_div",
    directionsElementID: "gmap_directions",
    handlers: {},
    isDebug: false,
    centerLat: null,
    centerLon: null,
    defaultZoom: 12,
    directionsTemplate: new Template("http://www.google.com/maps?f=d&saddr=#{source}&daddr=#{destination}&hl=en&geocode=&mra=ls&ie=UTF8&z=12&layer=c&pw=2"),
    
    resultIcon: "http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/blank.png",
    
	gmapLoad: function(e) {
	    if (GBrowserIsCompatible()) {
	    	if (ihs.gmap.isDebug) {
	    		ihs.util.debug("Creating new map");
	    	}
		    this.map = new GMap2(document.getElementById(this.mapElementID));
		    if (this.markers.length > 0) {
		        this.map.setCenter(this.markers[0].point, this.defaultZoom);
		    } else {
		        this.map.setCenter(new GLatLng(this.centerLat, this.centerLon), this.defaultZoom);
	        }        
		    for (var i = 0; i < this.markers.length; i++) {
		        var marker = this.markers[i].getMarker();
		        this.map.addOverlay(marker);
		    }
		    this.map.addControl(new GSmallMapControl());
		    this.map.addControl(new GMapTypeControl());
		    this.loaded = true;
		    this.applyHandlers(this.handlers['gmapLoad'], arguments);  
	    }
	},
	
    applyHandlers: function(handlerArr, args) {
        var retVal;
        if (handlerArr != null && typeof handlerArr != "undefined") {
            for (var x = 0; x < handlerArr.length; x++) {
                if (handlerArr[x] != null && typeof handlerArr[x] != "undefined") {
                    retVal = handlerArr[x].apply(this, args);
                }
            }
        }
        return retVal;
    },
    
    registerHandler: function(event, handler) {
    	if (ihs.gmap.isDebug) {
    		ihs.util.debug("Registering new handler for event "+event);
    	}
        if (this.handlers[event] == null || typeof this.handlers[event] == "undefined") {
            this.handlers[event] = [];
        }
        this.handlers[event].push(handler);
    },
    
    showDirections: function(dir_text) {
        this.map.clearOverlays();
        var dirDiv = document.getElementById(this.directionsElementID);
        dirDiv.innerHTML = '';
        var directions = new GDirections(this.map, dirDiv);
        directions.load(dir_text);
        $(this.directionsElementID).show();
    },
    
    getDirectionsLink: function(source, dest) {
    	return this.directionsTemplate.evaluate({source: source, destination: dest});
    }
};

ihs.gmap.localSearch = {
    searchFormID: "hotelFilterForm",
    refererTrackParam: "referertrackid",
    refererTrackValue: 10031,
    geoLatParam: "geoLat",
    geoLonParam: "geoLon",
    geoDescParam: "geoDescription",
    geoMilesParam: "geoMiles",
    geoStreetParam: "geoStreet",
    geoCityParam: "geoCity",
    geoStateParam: "geoState",
    geoCountryParam: "geoCountry",
    geoPhoneParam: "geoPhone",
    geoMilesValue: 15,
    geoSortParam: "orderBy",
    geoSortValue: 4,

    addSearchToMap: true,
    searchControl: null,
    localSearch: null,
    searchResultsID: "search_results",
    
    onGenerateMarkerHtmlCallback: function(marker, html, result) {
		if (ihs.gmap.isDebug) {
			ihs.util.debug("Generating html for result "+result.titleNoFormatting);
		}
        var handlerArr = ihs.gmap.handlers['generateMarkerHtml'];
        var retVal = ihs.gmap.applyHandlers(handlerArr, arguments);
        if (retVal)
            return retVal;
        else
            return html;
    },
    
    onMarkersSetCallback: function(markers) {
    	if (ihs.gmap.isDebug) {
    		ihs.util.debug("Generating markers for results "+$A(markers).pluck("title"));
    	}
        var handlerArr = ihs.gmap.handlers['markersSet'];
        ihs.gmap.applyHandlers.apply(this, [handlerArr, arguments]);
    },
    
    onSearchComplete: function() {
        var handlerArr = ihs.gmap.handlers['searchComplete'];
        return ihs.gmap.applyHandlers.apply(this, [handlerArr, arguments]);
    },
    
    onSearchStarting: function() {
        var handlerArr = ihs.gmap.handlers['searchStarting'];
        return ihs.gmap.applyHandlers.apply(this, [handlerArr, arguments]);
    },
    
    onIdle: function() {
        var handlerArr = ihs.gmap.handlers['searchIdle'];
        return ihs.gmap.applyHandlers.apply(this, [handlerArr, arguments]);
    },
    
    loadSingleton: function(divid, center) {
    	if (ihs.gmap.isDebug) {
    		ihs.util.debug("Creating new singleton local search control");
    	}
        this.searchControl = new GSearchControl();

        this.localSearch = new GlocalSearch();
        this.searchControl.addSearcher(this.localSearch);
        // Set the Local Search center point
        this.localSearch.setCenterPoint(center);

		this.searchControl.setSearchCompleteCallback(this, this.onSearchComplete.bind(this));
		this.searchControl.setSearchStartingCallback(this, this.onSearchStarting.bind(this));
        // tell the searcher to draw itself and tell it where to attach
        this.searchControl.draw(document.getElementById(divid));
        
    },
    
    bindToMap: function(map) {
    	if (ihs.gmap.isDebug) {
    		ihs.util.debug("Binding local search control to map");
    	}
        var lscOpts = {resultList: document.getElementById(this.searchResultsID),
                   onGenerateMarkerHtmlCallback: this.onGenerateMarkerHtmlCallback.bind(this),
                   onMarkersSetCallback: this.onMarkersSetCallback.bind(this),
                   onSearchCompleteCallback: this.onSearchComplete.bind(this),
                   onSearchStartingCallback: this.onSearchStarting.bind(this),
                   onIdleCallback: this.onIdle.bind(this)};    
        this.searchControl = new google.maps.LocalSearch(lscOpts); 
        map.addControl(this.searchControl);
    },
    
    getAddressPlain: function(result) {
        var txt = result.streetAddress+" "+result.city+", "+result.region+" "+result.country;
        return txt;
    },
    
    generateResultSortUrl: function(result, url) {
        if (url.indexOf('?') < 0) {
            url += "?";
        } else {
            url += "&";
        }
        url += this.geoLatParam+"="+result.lat;
        url += "&"+this.geoLonParam+"="+result.lng;
        url += "&"+this.geoDescParam+"="+escape(result.titleNoFormatting);
        url += "&"+this.geoStreetParam+"="+escape(result.streetAddress);
        url += "&"+this.geoCityParam+"="+escape(result.city);
        url += "&"+this.geoStateParam+"="+escape(result.region);
        url += "&"+this.geoCountryParam+"="+escape(result.country);
        url += "&"+this.geoPhoneParam+"="+escape(this.getResultPhone(result));
        url += "&"+this.geoSortParam+"="+this.geoSortValue;
        url += "&"+this.refererTrackParam+"="+this.refererTrackValue;
        return url;
    },
    
    submitSortForm: function(e, marker, result) {
        var frm = document.getElementById(this.searchFormID);
    	if (ihs.gmap.isDebug) {
    		ihs.util.debug("Submitting search form for result "+result.titleNoFormatting);
    	}
        if (frm) {
            frm[this.geoSortParam].value = this.geoSortValue;
            
            var geoLat = this.getOrCreateFormField(frm, this.geoLatParam);
	    	if (ihs.gmap.isDebug) {
	    		ihs.util.debug("Got form input for geoLat "+geoLat);
	    	}
            geoLat.value = result.lat;
            var geoLon = this.getOrCreateFormField(frm, this.geoLonParam);
            geoLon.value = result.lng;
            var geoDesc = this.getOrCreateFormField(frm, this.geoDescParam);
            geoDesc.value = result.titleNoFormatting;
            
            var referer = this.getOrCreateFormField(frm, this.refererTrackParam);
            referer.value = this.refererTrackValue;
            if (result.streetAddress && result.streetAddress != "") { 
                var geoStreet = this.getOrCreateFormField(frm, this.geoStreetParam);
                geoStreet.value = result.streetAddress;
            }
            if (result.city && result.city != "") { 
                var geoCity = this.getOrCreateFormField(frm, this.geoCityParam);
                geoCity.value = result.city;
            }
            if (result.region && result.region != "") { 
                var geoState = this.getOrCreateFormField(frm, this.geoStateParam);
                geoState.value = result.region;
            }
            if (result.country && result.country != "") { 
                var geoCountry = this.getOrCreateFormField(frm, this.geoCountryParam);
                geoCountry.value = result.country;
            }
            if (result.phoneNumbers && result.phoneNumbers.length > 0) {
                var geoPhone = this.getOrCreateFormField(frm, this.geoPhoneParam);
                geoPhone.value = this.getResultPhone(result);
            }
            frm.submit();
        } else {
            alert("Sorry- unable to sort hotels by location");
        }
    },
    
    getOrCreateFormField: function(frm, field) {
        return (Form.getInputs(frm, 'hidden', field).length > 0) ? Form.getInputs(frm, 'hidden',field)[0] : this.createHiddenField(frm, field)
    },
    
    createHiddenField: function(frm, name) {
    	if (ihs.gmap.isDebug) {
    		ihs.util.debug("Creating hidden form field "+name);
    	}
        var input = document.createElement('input');
        input.setAttribute('name', name);
        input.setAttribute('type', 'hidden');
        frm.appendChild(input);
    	if (ihs.gmap.isDebug) {
    		ihs.util.debug("Created hidden form field "+input);
    	}
        return input;
    },
    
    getResultPhone: function(result) {
        var i = 0;
        var phone = "";
        if (result.phoneNumbers) {
	        while (i < result.phoneNumbers.length && 
	                result.phoneNumbers[i].type != "main") {
	            i++;
	        }
	        if (!result.phoneNumbers[i] && i > 0) {
	            i = 0;
	        }
	        if (result.phoneNumbers[i] && result.phoneNumbers[i].number)
                phone = result.phoneNumbers[i].number;
        }
        return phone;
    }
    
};

ihs.gmap.registerHandler('gmapLoad',
    function() {
        if (ihs.gmap.localSearch.addSearchToMap) {
            ihs.gmap.localSearch.bindToMap(this.map);
        }        
    });
    
ihs.gmap.marker = {
    pattern: new RegExp("<span class=\"placeholder ([\\w\\d_\\.]+)\">[\\w\\d\\s_]+</span>"),
    
    fromTemplate: function(id, obj) {
        var el = document.getElementById(id);
        if (!el)
            return "";
        var tplText = el.innerHTML;
        var replFunc = function(s) {
		    var prop = s[1];
		    return (obj[prop]) ? ((obj[prop] instanceof Array) ? obj[prop].join(' ') : obj[prop]) : "";
		}
		return tplText.gsub(this.pattern, replFunc);
    }
};

ihs.gmap.Polygon = function() { this.initialize.apply(this, arguments);}
ihs.gmap.Polygon.prototype = {
		name: null,
		latLons: [],
		city: null,
	    state: null,
	    country: null,
	    polygon: null,
		point: null,
		color: "#F33F00",
		borderColor: "#FFFFFF",
		borderWidth: 5,
		
		initialize: function(name, latLons) {
			if (ihs.gmap.isDebug) {
				ihs.util.debug("Creating new polygon for "+name);
			}
		    this.name = name;
		    this.latLons = latLons;
		    this.city = null;
		    this.state = null;
		    this.country = null;
		    this.polygon = null;
		    this.point = new GLatLng(this.latLons[0][0], this.latLons[0][1]);
		},
		
		getMarker: function() {
	        if (this.polygon == null) {
	        	gLatLons = [];
	        	for(var i = 0; i < this.latLons.length; i++)
	        		gLatLons[i] = new GLatLng(this.latLons[i][0], this.latLons[i][1]);
	            this.polygon = new GPolygon(gLatLons, this.color, this.borderWidth, 1, this.borderColor, 0.2);
	        }
	        return this.polygon;
	    },
	    
	    setColor: function(color) {
	        this.color = color;
	    },
	    
	    setBorderColor: function(borderColor) {
	        this.borderColor = borderColor;
	    },
	    
	    setBorderWidth: function(borderWidth) {
	        this.borderWidth = borderWidth;
	    }
};

ihs.gmap.Marker = function() { this.initialize.apply(this, arguments);}
ihs.gmap.Marker.prototype = {
    name: null,
    lat: null,
    lon: null,
    address: null,
    city: null,
    state: null,
    country: null,
    phoneNumber: null,
    zip: null,
    marker: null,
    point: null,
    info: null,

    initialize: function(name, lat, lon) {
		if (ihs.gmap.isDebug) {
			ihs.util.debug("Creating new marker for "+name+" at "+lat+", "+lon);
		}
        this.name = name;
        this.lat = lat;
        this.lon = lon;
        this.address = null;
        this.city = null;
        this.state = null;
        this.zip = null;
        this.marker = null;
        this.point = new GLatLng(this.lat, this.lon);
    },
    
    
    getMarker: function() {
        if (this.marker == null) {
            this.marker = new GMarker(this.point, {title: this.name});
            GEvent.addListener(this.marker, "click", this.openInfoWindow.bindAsEventListener(this));     
        }
        return this.marker;
    },
    
    setAddress: function(address, city, state, zip) {
        this.address = address;
        this.city = city;
        this.state = state;
        this.zip = zip;
    },
    
    setPhoneNumber: function(phoneNumber) {
        this.phoneNumber = phoneNumber;
    },
    
    openInfoWindow: function() {
        var handlerArr = ihs.gmap.handlers['showInfoText'];
        ihs.gmap.applyHandlers.apply(this, [handlerArr, []]);
        this.marker.openInfoWindowHtml(this.info);
    },
    
    createInfoText: function() {
        this.info = "<b>"+this.name+"</b>";
        var handlerArr = ihs.gmap.handlers['createInfoText'];
        ihs.gmap.applyHandlers.apply(this, [handlerArr, []]);
        return this.info;
    },
    
    getAddressText: function() {
        var txt = "<div class=\"gmap_address_info\">"+
                "<span class=\"gmap_address\">"+this.address+"</span><br/>"+
                "<span class=\"gmap_town\">"+this.city+", "+this.state+" "+this.zip+"</span><br />";
        if (this.phoneNumber && typeof this.phoneNumber != "undefined")
            txt += "<span class=\"gmap_phone\">"+this.phoneNumber+"</span>";
        txt += "</div>";
        return txt;
    },
    
    getAddressPlain: function() {
        var txt = (this.address == null || this.address == "") ? this.name : this.address;
        txt += " "+this.city+", "+this.state+" "+this.zip;
        return txt;
    }
};

ihs.gmap.Hotel = function() { this.initialize.apply(this, arguments);}

ihs.gmap.Hotel.prototype = Object.extend(new ihs.gmap.Marker(), {
    infoLink: null,
    imageLink: null,
    ratesLink: null,
    rates: [],
    maxRatesShown: 3,
    
    setInfoLink: function(link, linkText) {
        this.infoLink = "<a href=\""+link+"\">"+linkText+"</a>";
    },
    
    setImageLink: function(img) {
        this.imageLink = "<img src=\""+img+"\" border=\"0\" />";
    },
    
    setRatesLink: function(link, linkText) {
        this.ratesLink = "<a href=\""+link+"\">"+linkText+"</a>";
    },
    
    createInfoText: function() {
        this.info = "<div class=\"gmap_hotel_info\">";
        if (this.imageLink) {
            this.info += "<div class=\"gmap_hotel_image\">"+this.imageLink+"</div>";
        }
        this.info += "<div class=\"gmap_hotel_title\">"+this.name+"</div>"+this.getAddressText();
        if (this.infoLink) {
            this.info += "<div class=\"gmap_hotel_info_link\">"+this.infoLink+"</div>";
        }
        if (this.ratesLink) {
            this.info += "<div class=\"gmap_hotel_rates_link\">"+this.ratesLink+"</div>";
        }
        if (this.rates.length > 0) {
            this.info += "<p class=\"gmap_rates\"><span class=\"gmap_rates_title\">Available Rates</span>";
	        for (var i = 0; i < this.rates.length && i < this.maxRatesShown; i++) {
	            this.info += "<br /><span class=\"gmap_rate\">"+this.rates[i]+"</span>";
	        }
	        this.info += "</p>";
        }
        this.info += "</div>";
        var handlerArr = ihs.gmap.handlers['createInfoText'];
        ihs.gmap.applyHandlers.apply(this, [handlerArr, []]);
        return this.info;
    }
});

ihs.gmap.localSearch.Result = Class.create();
ihs.gmap.localSearch.Result.prototype = Object.extend(new ihs.gmap.Marker(), {
    resultIcon: "http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/blank.png",
    
    getMarker: function() {
        if (this.marker == null) {
            var rsIcon = new GIcon(G_DEFAULT_ICON);
            rsIcon.image = this.resultIcon;
            this.marker = new GMarker(this.point, {title: this.name, icon: rsIcon});
            GEvent.addListener(this.marker, "click", this.openInfoWindow.bindAsEventListener(this));     
        }
        return this.marker;
    },
    
    createInfoText: function() {
        this.info = "<div class=\"gmap_result_info\">"+
                    "<h2 class=\"gmap_result_title\">"+this.name+"</h2>"+
                    "<p class=\"gmap_result_address\">"+this.getAddressText()+"</p></div>";
        var handlerArr = ihs.gmap.handlers['createInfoText'];
        ihs.gmap.applyHandlers.apply(this, [handlerArr, []]);
        return this.info;
    }
});

ihs.gmap.LogFunc = function() {
    if (ihs.gmap.loaded)
        this.makeCall();
    else 
        ihs.gmap.registerHandler('gmapLoad', this.makeCall.bind(this));
};

if (ihs.logging != undefined)
	ihs.logging.clicklogs.sources.push(new ihs.logging.ExternalSource({
							            name: "Google Maps",
							            elementID: ihs.gmap.mapElementID,
							            isRevenue: false,
							            isCost: false,
							            attach: ihs.gmap.LogFunc,
							            linkRoot: 'googlemaps.com',
							            searchString: function(obj) { return obj.getAttribute('id');}
							        }));

ihs.gmap.localSearch.LogFunc = function() {
    ihs.gmap.registerHandler('searchComplete',this.makeCall.bind(this));
};
if (ihs.logging != undefined)
	ihs.logging.clicklogs.sources.push(new ihs.logging.ExternalSource({
	                                    name: "Google Local Search",
	                                    elementID: ihs.gmap.localSearch.searchResultsID,
	                                    isRevenue: false,
	                                    isCost: false,
	                                    attach: ihs.gmap.localSearch.LogFunc,
	                                    linkRoot: 'google.search.LocalSearch',
	                                    searchString: function(obj) {return obj.getAttribute('id');}
	                                }));