/////////////////////////////////////////////////////////////////
// FileName : maps.js
// Description : JavaScript methods for the virtual earth map
/////////////////////////////////////////////////////////////////

var _maxLat = null;
var _minLat = null;
var _maxLon = null;
var _minLon = null;

var ajaxMapLoaded = null;

// called by Map Helper when 
// loadMap() is called
function mapLoadCallback() {
	$("body").trigger("mapLoadComplete");
	ajaxMapLoaded = true;
	removeVEBubble();
}

function ajaxLoadMap(url) {
	if (ajaxMapLoaded === null) {
		// ajax call for map
		$.get(url, function(data) {
			var envelope = new Envelope(data);

			// updating the dom
			$("#resultsMapContainer").html(envelope.payload);

			// wait for dom to be ready
			ajaxMapLoaded = false;
			loadMapIfReady(0);

		}, "text");
	}
}

function loadMapIfReady(strikes) {
	if (window.loadMap && window.VEMap) {
		$("#loadingMap").hide();
		// end loop
		if($("#resultsMapContainer").is(":visible")) {
			setTimeout(function() {
				loadMap();
			}, 250);
		}
	} 
	else if(strikes < 100) {
		strikes++; // repeat until
		setTimeout(function() {
			loadMapIfReady(strikes);
		}, 250);
	}
}


// set a collection of push pin
// dataRows: collection of json object
function setCollectionPushpin(mapId, dataRows) {
	if(map) {
		clearMap();

		//create the layer
		var layer = new VEShapeLayer();
		for (i=0; i< dataRows.length; i++) {
			if (dataRows[i].lat != 0 && dataRows[i].lon != 0) {
				var pushpin = createPushpin(dataRows[i]);
				layer.AddShape(pushpin);
			}
		}
		map.AddShapeLayer(layer);

		var mapWidth = $("#" + mapId).width();
		var mapHeight = $("#" + mapId).height();
		var bestView = calculateMapBestView(points, mapWidth, mapHeight);

		map.SetCenterAndZoom(bestView.centerPoint, bestView.zoomLevel);
	}
}

function createPushpin(rowData) {
	var html = []; 
	html.push('<div id="mapBubble-' + rowData.propertyid + '" class="mapBubble">');
	html.push('<div class="bubbleContent">');
	html.push('<div class="t"></div>');
	html.push('<div class="buttons"><a href="javascript:closeBubble();" class="xbutton"></a></div>');
	html.push('<div><div class="photo">');
	html.push('<a href="/admin/listingdetails/mlsid/' + rowData.mlslistid + '/propertyid/' + rowData.propertyid + '/">');
	html.push('<img src="' + rowData.imageurl + '" height="56" width="77"></a>');
	html.push('</div><div class="info">');
	html.push('<ul><li class="price">');
	html.push('<a href="/admin/listingdetails/mlsid/' + rowData.mlslistid + '/propertyid/' + rowData.propertyid + '/">');
	html.push('<h3>' + rowData.price + '</h3></a></li>');
	html.push('<li class="address"><span>' + rowData.address + '</span></li>');
	html.push('<li class="csz"><span>' + rowData.csz + '</span></li>');
	html.push('<li class="beds"><span>' + rowData.beds + '</span><label> beds</label></li>');
	html.push('<li class="baths"><span>' + rowData.baths + '</span><label> baths</label></li>');
	html.push('<li class="remarks"><span>' + rowData.remarks + '</span></li>');
	html.push('</ul></div>');
	html.push('<div class="clearLeft"></div>');
	html.push('</div></div>');
	html.push('<div class="b"><div></div></div>');
	html.push('</div>');

	var description = html.join('');
	var point = new VELatLong(rowData.lat,rowData.lon);
	var marker = new VEShape(VEShapeType.Pushpin, point);
	marker.SetTitle('');
	marker.SetDescription(description);
	marker.SetCustomIcon('<div class="mapPoint"><span class="digit1 pushpin"></span></div>');
	points[counter] = point;
	markers[counter] = marker;
	counter++;

	return marker;
}

function toObj(json) {
	if (typeof json == "object") {
		return json;
	}
	else {
		// trim
		json = $.trim(json+"");

		// correct format
		if(json.charAt(0) != "{" && json.slice(-1) != "}") {
			json = "{" + json + "}";
		}
		// borrowed from jQuery-1.4
		if (window.JSON && window.JSON.parse) {
			return window.JSON.parse(json);
		}
		else {
			return (new Function("return " + json))();
		}
	}
}

function setPushpin(data) {
	rowData = toObj(data);

	//make sure there's lat and lon
	if (!rowData || !rowData.lat || !rowData.lon) return;
	var pushpin = createPushpin(rowData);

	// add marker on map
	map.AddShape(pushpin);
	adjustCenterCoords(rowData.lat, rowData.lon);
}

function deletePushpin(data) {
	rowData = toObj(data);

	//make sure there's lat and lon
	if (!rowData || !rowData.lat || !rowData.lon) return;

	for (i=0; i < points.length; i++) {
		if (points[i] != null) {
			var point = points[i];
			if (point.Latitude == rowData.lat && point.Longitude == rowData.lon) {
				map.DeleteShape(markers[i]);
				points[i] = null;
				return;
			}
		}
	}
}

function adjustCenterCoords(lat,lon) {
	lon = parseFloat(lon);
	lat = parseFloat(lat);
	if(!lon || !lat) return;

	_maxLon = (_maxLon != null) ? Math.max(lon, _maxLon) : lon;
	_minLon = (_minLon != null) ? Math.min(lon, _minLon) : lon;
	_maxLat = (_maxLat != null) ? Math.max(lat, _maxLat) : lat;
	_minLat = (_minLat != null) ? Math.min(lat, _minLat) : lat;

	var centerLon = (_minLon + _maxLon) / 2;
	var centerLat = (_minLat + _maxLat) / 2;

	map.SetCenterAndZoom(new VELatLong(centerLat, centerLon), 9);
}

function calculateMapBestView(mapPoints, mapWidth, mapHeight) {
	//calculate bounding rectangle
	var maxLat = -90, minLat = 90, maxLon = -180, minLon = 180;

	//default zoom scales in km/pixel from http://msdn2.microsoft.com/en-us/library/aa940990.aspx
	var defaultScales = [78.27152, 39.13576, 19.56788, 9.78394, 4.89197, 2.44598, 1.22299, 0.61150, 0.30575, 0.15287, .07644, 0.03822, 0.01911, 0.00955, 0.00478, 0.00239, 0.00119, 0.0006, 0.0003];

	//calculate bounding box for array of locations
	for (i = 0; i < mapPoints.length; i++) 
	{
		if (mapPoints[i].Latitude > maxLat)
			maxLat = mapPoints[i].Latitude;

		if (mapPoints[i].Latitude < minLat)
			minLat = mapPoints[i].Latitude;

		if (mapPoints[i].Longitude > maxLon)
			maxLon = mapPoints[i].Longitude;

		if (mapPoints[i].Longitude < minLon)
			minLon = mapPoints[i].Longitude;
	}

	//calculate center coordinate of bounding box
	var centerLat = (maxLat + minLat) / 2;
	var centerLong = (maxLon + minLon) / 2;

	//want to calculate the distance in km along the center latitude between the two longitudes
	var meanDistanceX = HaversineDistance(centerLat, minLon, centerLat, maxLon);

	//want to calculate the distance in km along the center longitude between the two latitudes
	var meanDistanceY = HaversineDistance(maxLat, centerLong, minLat, centerLong) * 2;

	//calculates the x and y scales
	var meanScaleValueX = meanDistanceX / (mapWidth || 100);
	var meanScaleValueY = meanDistanceY / (mapHeight || 100);
	var meanScale = (meanScaleValueX > meanScaleValueY) ? meanScaleValueX : meanScaleValueY;

	//intialize zoom level variable
	var zoom = 1;

	//calculate zoom level
	for (i = 1; i < 19; i++) {
		if (meanScale > defaultScales[i]) {
			zoom = i;
			break;
		}
	}

	// VIS-593 - limit to 14 level
	zoom = Math.min(14, zoom);

	//return a BestView object with the center point and zoom level to use
	return {"centerPoint": new VELatLong(centerLat, centerLong), "zoomLevel": zoom};
}

// Calculate the distance in kilometers between two coordinates
function HaversineDistance(lat1, lon1, lat2, lon2) {
	var earthRadius = 6371;
	var factor = Math.PI / 180;
	var dLat = (lat2 - lat1) * factor;
	var dLon = (lon2 - lon1) * factor;
	var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * factor) * Math.cos(lat2 * factor) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
	var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
	return earthRadius * c;
}


function redrawOpenBubble() {
	return;
}

function redrawWait() {
	if (openBubble && map) {
		if (busyRedraw) {
			// Wait for map to complete movements
			busyRedraw = false;
			setTimeout(redrawWait, 250);
		}
		else {
			// Wait for hell to freeze over 
			setTimeout(function() {
				var markerID = openBubble.GetID();
				markerID = markerID + "_1" + markerID.slice(-4);
				var e = {"elementID" : markerID};
				shape_onclickEvent(e);

				// Hack for ie
				setTimeout(function() { 
					if (openBubble){
						map.ShowInfoBox(openBubble)
						fixBubble(markerID, 0);
					} 
				}, 750);
			}, 250);
		}
	}
}

function selectOnMap(markerIndex) {
	if (map) {
		map.HideInfoBox();
		map.SetZoomLevel(12);
		map.SetCenter(points[markerIndex]);

		// VIS-2721
		openBubble = markers[markerIndex];

		// Wait for map to complete movements
		busyRedraw = false;
		setTimeout(redrawWait, 250);
	}
}

function clearMap() {
	_maxLat = null;
	_minLat = null;
	_maxLon = null;
	_minLon = null;

	// these vars are from global map script
	points = [];
	markers = [];
	counter = 0;

	if (map) {
		map.Clear();
	}
}

/**
* Remove virutal earth bubble formatting
*/
function removeVEBubble() {
	$(".customInfoBox-shadow").removeClass("customInfoBox-shadow").addClass("customInfoBox-shadow-hide");
	$(".customInfoBox-body").removeClass("customInfoBox-body").addClass("customInfoBox-body-hide");
	$("div.MSVE_MapContainer").pngFix();
}


function fixBubble(markerID, strikes) {
	var $marker = $("#" + markerID), $box = $("div.customInfoBox-with-leftBeak, div.customInfoBox-with-rightBeak");

	// all good let us test the location of the box
	if ($marker.length && $box.height() < 390 && strikes < 3) {
		// makes background smaller and aligns box bottom with marker top + close bubble on bottom click
		$box.find(".firstChild").children("br,p").remove().end().find("div.b").click(closeBubble);

		var mTop = parseInt($marker.offset().top + 0.5);
		var bOff = $box.offset(), bTop = mTop - parseInt($box.height() + 0.5);


		// move if it is way off
		if (Math.abs(bOff.top - bTop) > 15) {
			$box.offset({"top" : bTop, "left" : bOff.left});

		}
	}
	else {
		strikes++; // must incr before calling again
		setTimeout(function() { fixBubble(markerID, strikes) }, (strikes*50));
	}
}

// We want to add this class to the map marker 
// popups after they are loaded.
$(window).load(function() { 
	setTimeout(function() {
		if (window.loadMap && $("#map").is(":visible") ) {
			if (!map) {
				loadMap();
			}

			// fix css box issue in IE
			removeVEBubble();

			// multi points
			if (points.length > 1) {
				var mapWidth = $("#map").width();
				var mapHeight = $("#map").height();
				var bestView = calculateMapBestView(points, mapWidth, mapHeight);

				map.SetCenterAndZoom(bestView.centerPoint, bestView.zoomLevel);
			}
		}
	}, 50);
});

