var _gMapInstances = [];

/**
 * Returns instance of the map object
 * @param int Index of the instance; by default it is 0
 * @return GMapHeartLand
 */
function getMapInstance(index)
{
	if (!index)
		index = 0;
		
	return _gMapInstances[index];
}

function GMapHeartLand(objDom) 
{
	// Unload
	$('body').unload(GUnload);
	
	if (!GBrowserIsCompatible())
		return;	
	
	this.map = new GMap2(objDom);
	this.bounds = new GLatLngBounds();
	this.markers = [];

	this.lastHighligthedMarker = false;
	
	// Map config
	this.map.setCenter(new GLatLng(40.561807971278185, -80.04913330078125), 13);
	this.map.addControl(new GSmallMapControl());
	this.map.addControl(new GMapTypeControl());
	
	this.baseIcon = new GIcon();
	this.baseIcon.iconSize = new GSize(25, 25);
	this.baseIcon.iconAnchor = new GPoint(9, 34);
	this.baseIcon.infoWindowAnchor = new GPoint(9, 2);
	this.baseIcon.infoShadowAnchor = new GPoint(18, 25);
	this.bounds = new GLatLngBounds();
	
	// Broadcast event
	$(objDom).trigger("mapLoaded", [this]);
	
	// Save instance
	_gMapInstances.push(this);
	
	/* FUNCTIONS */
	
	/**
	 * Returns DOM element that hold the map
	 * Can be used to add event listeners to a map
	 * @return object
	 */
	this.getContainer = function()
	{
		return this.map.getContainer();
	}
	
	/**
	 * Returns GMap object
	 * @return GMap2
	 */
	this.getMap = function()
	{
		return this.map	
	}
	
	/**
	 * Returns list of map markers
	 * @return array
	 */
	this.getMarkers = function()
	{
		return this.markers;
	}
	
	/**
	 * Place address markers
	 * @param array Array of GLngLat for each address
	 * @param array URL for more info
	 */
	this.addAddressMarkers = function(addresses, links)
	{
		var marker;
		var hoverMarker;
		
		for(var i = 0; i < addresses.length; i++) {
			if (addresses[i].lng() == 0 && addresses[i].lat() == 0)
				continue;
				
			marker = new GMarker(addresses[i], {icon: this.getMarkerIcon()});
			hoverMarker = new GMarker(addresses[i], {icon: this.getMarkerIcon(true), zIndexProcess: function(marker){ return 100; }});
			
			// Find house id
			var url = links[i];
			var parts = url.match(/aspx\?ID\=([0-9]+)/i);
			if (parts) {
				marker.houseId = parts[1];
				hoverMarker.houseId = parts[1];
			} else {
				marker.houseId = 0;
				hoverMarker.houseId = 0;
			}
			
			// Add marker to the map
			this.map.addOverlay(marker);
			this.map.addOverlay(hoverMarker);
			
			if (!(typeof(window.addressExtendBounds) != 'undefined' && window.addressExtendBounds[i] == 0))
				this.extendBounds(marker);
			
			// Add to local collection
			this.markers.push([marker, hoverMarker]);
			
			hoverMarker.hide();
			
			// Bind default marker events
			var index = this.markers.length-1;
			GEvent.addListener(marker, "mouseover", GEvent.callbackArgs(this, this.highlightMarker, index));
			GEvent.addListener(hoverMarker, "click", GEvent.callbackArgs(this, this.showMarkerInfoWindow, index, url));
		}
		
		// Trigger custom event
		$(this.getContainer()).trigger("addedAddressMarkers", [this]);
	}
	
	this.getMarkerIcon = function(hover)
	{	
		// Create icon
		var icon = new GIcon(this.baseIcon);
		
		if (!hover) {
			// Normal
			icon.image = "images/maps/markers/default.png";
			icon.iconSize = new GSize(15,24);
		} else {
			// Hover
			icon.image = "images/maps/markers/default-over.png";
			icon.iconSize = new GSize(20,30);
		}
		
		return icon;
	}
	
	/**
	 * Returns array of markers related to a house
	 * First item of the array is a normal marker; second is "hover" marker that is hidden
	 * 
	 * @param int
	 * @return array
	 */
	this.findMarkerByHouse = function(houseId)
	{
		return this.markers[this.findMarkerIndexByHouse(houseId)];
	}
	
	/**
	 * Returns array of markers related to a house
	 * First item of the array is a normal marker; second is "hover" marker that is hidden
	 * 
	 * @param int
	 * @return array
	 */
	this.findMarkerIndexByHouse = function(houseId)
	{
		for(var i = 0; i < this.markers.length; i++) {
			if (this.markers[i][0].houseId == houseId)
				return i;
		}
		
		return null;
	}
	
	/**
	 * Shows information bubble for a marker
	 * @uses Number.formatMoney()
	 * @param int Marker index
	 */
	this.showMarkerInfoWindow = function(index, url) 
	{
		var current = this.markers[index][1];
		if (!current) return;
		
		var div = $("<div />").append('<div id="community-bubble-container">Loading ...</div>');
		// Open bubble
		//current.openInfoWindow(div.html());
		
		$.get('location_results.aspx', {request: "ajax", action: "communityInfo", id: current.houseId}, function(data){
			var price = parseFloat($("StartingPrice", data).text());
			
			// Open bubble
			current.openInfoWindow('<ul class="community-bubble" style="padding:0px; margin:0px;">'+
					'<li class="title">'+$("Name", data).text()+'</li>'+
					'<li><strong>Starting Price</strong>: '+ (isNaN(price) ? 'N/A' : '$'+ price.formatMoney()+'\'s') +'</li>'+
					'<li><strong>School District</strong>: '+$("SchoolDistrict", data).text()+'</li>'+
					'<li><a href="'+url+'">More Information &raquo;</a></li>'+
				'</ul>');
		});	
	}
	
	/**
	 * Highligth a marker with specified index within "markers" array
	 * @param int Index of the marker to highligth
	 */
	this.highlightMarker = function(index)
	{
		if (this.lastHighligthedMarker !== false) {
			var last = this.markers[this.lastHighligthedMarker];	
			last[0].show();
			last[1].hide();
			
			delete last;
		}
		
		if (this.markers[index]) {
			var current = this.markers[index];
			current[0].hide();
			current[1].show();
			
			delete current;
			this.lastHighligthedMarker = index;
		}
	}
	
	/**
	 * Extend map bounds using a marker and set appropriate zoom level
	 * @param GMarker
	 */
	this.extendBounds = function(marker)
	{
		var point = marker.getLatLng();
		this.bounds.extend(point);
		
		var zoom = this.map.getBoundsZoomLevel(this.bounds);
		var center = this.bounds.getCenter();
		this.map.setCenter(center, zoom);
	}
}

Number.prototype.formatMoney = function(c, d, t){
    var n = this, c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "." : d, t = t == undefined ? "," : t,
    i = parseInt(n = (+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
    return (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t)
    /*+ (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "")*/;
};

function map_showDirections(domId, from, to)
{
	var map = getMapInstance();
	var container = document.getElementById(domId);
	var directions = new GDirections(map.getMap(), container);
	
	// Reset container
	directions.clear();
	container.innerHTML = "";
	
	// Error handling
	GEvent.addListener(directions, "error",  GEvent.callbackArgs(directions, handleDirectionsErrors));
	
	directions.load("from: " + from + " to: " + to.lat() + "," + to.lng(), {"locale": "en_US"});
}

//function map_bind

/*
var _lastSelectedLocation;
var gMapMarkers = [];
var gMapIndex = -1;

GMap2.prototype.init = function (id, markerList, markerLinks, dirId, infoWindows)
{	
	this.id = id;
	this.addControl(new GSmallMapControl());
	this.addControl(new GMapTypeControl());	

	if(dirId) {
		this.directions = new GDirections(this, document.getElementById(dirId));
		
		GEvent.addListener(this.directions, "error", handleErrors);
		GEvent.addListener(this.directions, "load", onGDirectionsLoad);
	}

	// init
	this.mI = 0;
	this.addressIndex = 0;
	if(markerList) {
		this.lastSelectedMarker = false;
		this.addresses = markerList;
		this.markers = [];
		if(markerLinks)
			this.links = markerLinks;
		
		this.baseIcon = new GIcon();
		this.baseIcon.iconSize = new GSize(25, 25);
		this.baseIcon.iconAnchor = new GPoint(9, 34);
		this.baseIcon.infoWindowAnchor = new GPoint(9, 2);
		this.baseIcon.infoShadowAnchor = new GPoint(18, 25);
		this.bounds = new GLatLngBounds();

		gMapIndex++;
		gMapMarkers[gMapIndex] = {map: this, markers: []};

		//this.showMarkers();
	}
	
	this.addOverlay(new GMarker(new GLatLng(40.561807971278185, -80.04913330078125)));
	this.setCenter(new GLatLng(40.561807971278185, -80.04913330078125), 10);
}

GMap2.prototype.showMarkers = function()
{	
	for (this.addressIndex in this.addresses) {
		if (this.addresses[this.addressIndex].lat() != 0 && this.addresses[this.addressIndex].lng() != 0)
			this.putMarker(this.addresses[this.addressIndex], this.links[this.addressIndex]);
	}
	
	gMapMarkers[gMapIndex].markers = this.markers;
}

GMap2.prototype.putMarker = function(gLatLng, url)
{
	// Create icon
	var mIcon = new GIcon(this.baseIcon);
	mIcon.image = "images/maps/markers/default.png";
	mIcon.iconSize = new GSize(15,24);
	// Hover
	var mHoverIcon = new GIcon(this.baseIcon);
	mHoverIcon.image = "images/maps/markers/default-over.png";
	mHoverIcon.iconSize = new GSize(20,30);
	
	// Create marker
	var marker = new GMarker(gLatLng);
	alert(typeof(gLatLng));
	var markerHover = new GMarker(gLatLng, {icon: mHoverIcon, zIndexProcess: function(marker){ return 100; }});
	
	// Find house id
	var parts = url.match(/aspx\?ID\=([0-9]+)/i);
	if (parts) {
		marker.houseId = parts[1];
		markerHover.houseId = parts[1];
	} else {
		marker.houseId = 0;
		marker.houseId = 0;
	}
	
	// Setup events
	//GEvent.addListener(marker, "mouseover", GEvent.callbackArgs(this, this.highlightLocation, parts ? parts[1] : 0));
	//GEvent.addListener(marker, "mouseover", GEvent.callbackArgs(this, this.highlightMarker, this.mI));
	//GEvent.addListener(markerHover, "click", GEvent.callbackArgs(this, this.markerWindow, this.mI, url));
	
	//this.markers[this.mI] = [marker, markerHover];
	//this.addOverlay(marker);
	//this.addOverlay(markerHover);
	//this.extendAndSetMapCenter(gLatLng);
	
	// Hive hover
	//markerHover.hide();
	
	//this.mI++;
}

GMap2.prototype.markerWindow = function(index, url)
{
	var current = this.markers[index][1];
	
	$.get('location_results.aspx', {request: "ajax", action: "communityInfo", id: current.houseId}, function(data){
		var price = parseFloat($("StartingPrice", data).text());
		
		current.openInfoWindowHtml(
			'<dl class="community-bubble">'+
				'<dt class="title">'+$("Name", data).text()+'</dt>'+
				'<dt>Starting Price: </dt>'+
				'<dd>'+(isNaN(price) ? 'N/A' : '$'+ price.formatMoney())+'</dd>'+
				'<dt>School District: </dt>'+
				'<dd>'+$("SchoolDistrict", data).text()+'</dd>'+
				'<dt><a href="'+url+'">More Information</a></dt>'+
			'</dl>'
			);																				
		});
}

GMap2.prototype.setDirections = function(from,to)
{
	//alert("from: " + from + " to: " + to);
	this.directions.load("from: " + from + " to: " + to, {"locale": "en_US"});
}

GMap2.prototype.extendAndSetMapCenter = function(point)
{
	this.bounds.extend(point);
	
	var zoom = this.getBoundsZoomLevel(this.bounds);
	var center = this.bounds.getCenter();
	this.setCenter(center, zoom);
}


GMap2.prototype.highlightMarker = function(index)
{
	if (this.lastSelectedMarker !== false) {
		var last = this.markers[this.lastSelectedMarker];	
		last[0].show();
		last[1].hide();
		
		delete last;
	}
	
	if (this.markers[index]) {
		var current = this.markers[index];
		current[0].hide();
		current[1].show();
		
		this.highlightLocation(current[0].houseId);
		
		delete current;
		this.lastSelectedMarker = index;
	}
}

GMap2.prototype.highlightLocation = function(houseId)
{
	if (typeof(jQuery) == "undefined") return;
	if ($(".locations-results").size() == 0) return;
	
	if (_lastSelectedLocation)
		$(".locations-results a[href*=id\="+_lastSelectedLocation+"]").parents("tr").removeClass("selected");

	$(".locations-results a[href*=id\="+houseId+"]").parents("tr").addClass("selected");
	_lastSelectedLocation = houseId;
}*/

function handleDirectionsErrors()
{
	address = document.getElementById("street");
	switch(this.getStatus().code) {
		case G_GEO_UNKNOWN_ADDRESS:
			alert("Google Maps could not find an address matching the one you entered:\n\n"+address.value+"\n\nPlease include more information, if possible, and try again.");
			break;
		
		case G_GEO_SERVER_ERROR:
	 		alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + this.getStatus().code);
			break;
			
		case G_GEO_MISSING_QUERY:
			alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + this.getStatus().code);
			break;
			
		case G_GEO_BAD_KEY:
			alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + this.getStatus().code);
			break;
			
		case G_GEO_BAD_REQUEST:
			alert("A directions request could not be successfully parsed.\n Error code: " + this.getStatus().code); 
			break;
			
		default:
			alert("An unknown directions error occurred.");
			break;
	} 
}