/*

	Map Functions Script

*/       
var map = null;
var token = null;
var l = null;	//general layer
var myLayer = null; //layer for the selected hotel
var myShape = null;	//this is the selected hotel
var sCityCode = null;
var sHotelCode = null;
var sMarkers = null;
var mPos = null;
var pairIDs = new Array();
var defHotel = null;	//hotelcode of selected hotel
var defMarker = null;	//marker belonging to selected hotel
var imgPath = "/images/msmaps/";
var mapLoaded = null;
var num = "zzz";
var hotels = []; //local array of hotels

//for default view
var centreLatitude = null;
var centreLongitude = null;
var zoomLevel = null;

//selected hotel
var hotelLat = null;
var hotelLong = null;

var selectedHotelCode = null;
var selectedCityCode = null;
var selectedCityName = null;

//setup the map. loads based on the city centre  
function GetMap() 
{
	//var lat = document.getElementById('centreLatitude').value;
	//var lon = document.getElementById('centreLongitude').value;
	//var zoom = document.getElementById('zoomLevel').value;
	getToken();
	map = new VEMap('myMap');
	map.SetClientToken(token); 
	var mo = new VEMapOptions();
	mo.EnableBirdseye = false;
	
	map.LoadMap(new VELatLong(centreLatitude, centreLongitude), zoomLevel, VEMapStyle.Shaded, false, VEMapMode.Mode2D, false, 0, mo);
	map.SetMapStyle(VEMapStyle.Shaded);
	map.AttachEvent('onchangemapstyle', EventMapStyleChange);
}

//protect against choosing road style map, stay on shaded
function EventMapStyleChange(e)
{
	if (map.GetMapStyle() == VEMapStyle.Road)
	{
		map.SetMapStyle(VEMapStyle.Shaded);
	}
}
        		
		
//Change the default icon to our own icon.
function changeIcons(pin) 
{
	
	if ( defMarker != null ) {
		num = defMarker.replace("span_msftve_1001_2", "");
		num = num / 1;
		num = num + 1;
	}
	var numShapes = l.GetShapeCount();
	for (var i = 0; i < numShapes; ++i) {
		var marker = l.GetShapeByIndex(i);
		var myNum = i + 1;
		
		if ( num == myNum ) {
			marker.SetZIndex('7000');
			marker.SetCustomIcon("<div id=\'marker\'><img src=\'"+imgPath+"city-map-marker-highlighted-"+myNum+".png\'></div>");
			marker.SetDescription(hotels.markers[i].category);
		}
		else {
			marker.SetZIndex('5000');
			marker.SetCustomIcon("<div id=\'marker\'><img src=\'"+imgPath+"city-map-marker-"+myNum+".png\'></div>");
			marker.SetDescription(hotels.markers[i].category);
		}
	}
}
        

//function to centre the map on the known city centre
function centreMap() 
{
	//var lat = document.getElementById('centreLatitude').value;
	//var lon = document.getElementById('centreLongitude').value;
	map.SetCenter(new VELatLong(centreLatitude, centreLongitude));
}

//Centre map on known city centre and zoom to preselected level
function centreAndZoomMap() 
{
	var lat = centreLatitude; //document.getElementById('centreLatitude').value;
	var lon = centreLongitude; //document.getElementById('centreLongitude').value;
	var zoom = zoomLevel; //document.getElementById('zoomLevel').value;
	if (lat != "" && lon != "" && zoom != ""){
		map.SetCenterAndZoom(new VELatLong(lat, lon), zoom);
	}
}


//Zoom map to preselected
function zoomMap() 
{
	map.SetZoomLevel(zoomLevel);
}

//sets the pin to the highlighted version of the marker. Used for mouse overs.
function setCustomMarker(pin) 
{
	pin = pin.replace("span_", "");
	var num = pin.replace("msftve_1001_2", "");
	num = num / 1;
	num = num + 1;
	var marker = l.GetShapeByID(pin);
	marker.SetCustomIcon("<div id=\'marker\'><img src=\'"+imgPath+"city-map-marker-highlighted-"+num+".png\'></div>");
}

//Pan the map to a provided pushpin
function panMapToPushPin(arrayIndex) 
{
	highlightHotel(arrayIndex);
	map.PanToLatLong(new VELatLong(hotels.markers[arrayIndex].point.latitude,hotels.markers[arrayIndex].point.longitude));
	
}

//Will highlight a chosen marker, add a copy of that marker to a new layer, and make the shape highlighted.
function addShapeOnNewLayer(newMarkerID, newMarker)
{
	var num = newMarkerID.replace("msftve_1001_2", "");
	num = num / 1;
	num = num + 1;
	if (myShape != null){ myLayer.DeleteShape(myShape); }
	if (myLayer != null)	{map.DeleteShapeLayer(myLayer);	}
	myLayer = new VEShapeLayer();
	shapeLatLon = newMarker.GetPoints()[0];
	map.AddShapeLayer(myLayer);
	myShape = new VEShape(VEShapeType.Pushpin, shapeLatLon);
	myShape.SetTitle(hotels.markers[num-1].hotelname);
	myShape.SetDescription(hotels.markers[num-1].category);
	myShape.SetCustomIcon("<div id=\'marker\'><img src=\'" +imgPath+"city-map-marker-highlighted-"+num+".png\'></div>");
	myShape.SetZIndex('7000');
	myLayer.AddShape(myShape);
}
		
function cursor_change(pin) 
{
	document.body.style.cursor = 'pointer';
	setCustomMarker(pin);
	pin = pin.replace("span_", "");
	var marker = l.GetShapeByID(pin);
	marker.SetZIndex('8000');
}

function cursor_clear(pin) 
{
	document.body.style.cursor = 'default';
	changeIcons();
}


			            
/** 
* Returns true if point is in rectangle. 
* 
* @param {VELatLong} point Point to check. 
* @param {VELatLongRectangle} rect Bounding box. 
*/
// Originally from here I think http://www.stpe.se/2009/02/virtual-earth-point-in-bounding-box-test/
function isPointInRect(point, rect) 
{
	return ((rect.TopLeftLatLong.Longitude <= rect.BottomRightLatLong.Longitude && // longitude  
			 rect.TopLeftLatLong.Longitude <= point.Longitude &&
			 rect.BottomRightLatLong.Longitude >= point.Longitude)
			 || (rect.TopLeftLatLong.Longitude > rect.BottomRightLatLong.Longitude &&  // longitude crosses 180 degrees  
			 rect.TopLeftLatLong.Longitude >= point.Longitude &&
			 rect.BottomRightLatLong.Longitude <= point.Longitude))
			 && (rect.TopLeftLatLong.Latitude >= point.Latitude &&     // latitude  
			 rect.BottomRightLatLong.Latitude <= point.Latitude);
}



//reset the map. Used on the button and also when setting up the map.
//Will focus on the hotel, or the city
function resetMap()
{
	//make it so the only highlighted hotel is the original (if there is one)
	unhighlightAllHotel();

	if(centreLatitude ==0 && centreLongitude == 0) 
	{
		//if we're using default values
		var p = getCentreOfRect(l.GetBoundingRectangle());
		centreLatitude = p.Latitude;
		centreLongitude = p.Longitude;
		zoomLevel = getZoomForRect(l.GetBoundingRectangle());
	}	
	if(hotelLat != undefined)
	{
	map.SetCenterAndZoom(new VELatLong(hotelLat,hotelLong),zoomLevel);
	}
	else if(centreLatitude != undefined )
	{	
		map.SetCenterAndZoom(new VELatLong(centreLatitude,centreLongitude),zoomLevel);
	}	

	//map style back to normal.
	if(map.GetMapStyle() != VEMapStyle.Shaded)
	{
		map.SetMapStyle(VEMapStyle.Shaded);
	}

	//redraw all the icons.
	processIcons();
}

//this is the startup function called from the tab click
function myDelay () {
	if ( mapLoaded != 'yes' ){ 
		setTimeout("kickStart()", 150);
	}
}

//this function starts the map drawing, and loads the hotels layer
function kickStart()
{
	//If we've not city details stick something in!
	//We'll fix these later when we load the layer
	if(centreLatitude == undefined)
	{
		centreLatitude=0;
	}
	
	if(centreLongitude == undefined)
	{
		centreLongitude = 0;
	}
	
	if(zoomLevel == undefined)
	{
		zoomLevel = 12;
	}
	
	GetMap();
	
	AddMyJSONLayer( '/maps/GetHotels.asp?citycode=' + selectedCityCode + '&format=json');
	mapLoaded = 'yes';
}


//for distance calcs
var earthRadius = 6367; //radius in km
var kmToMiles = 0.62137;

//calculate the distance in KM between two points
function haversineDistance(latlong1,latlong2)
{
       var lat1 = DegtoRad(latlong1.Latitude);
       var lon1 = DegtoRad(latlong1.Longitude);
       var lat2 = DegtoRad(latlong2.Latitude);
       var lon2 = DegtoRad(latlong2.Longitude);
 
       var dLat = lat2-lat1;
       var dLon = lon2-lon1; 
       var cordLength = Math.pow(Math.sin(dLat/2),2)+Math.cos(lat1)*Math.cos(lat2)*Math.pow(Math.sin(dLon/2),2); 
       var centralAngle = 2 * Math.atan2(Math.sqrt(cordLength), Math.sqrt(1- cordLength)); 
       
       return earthRadius * centralAngle;
}

//calculate the distance in miles between two points
function distanceInMiles(latlong1,latlong2)
{
	var distance =  haversineDistance(latlong1,latlong2) * kmToMiles ;
	distance = distance.toFixed(2);
	return distance;
}

function DegtoRad(x)
{
       return x*Math.PI/180;
}

function RadtoDeg(x)
{
       return x*180/Math.PI;
}

function AddMyJSONLayer( sUrl )
{
	var request = YAHOO.util.Connect.asyncRequest('GET', sUrl, callback); 
}


var handleSuccess = function(o){
	if(o.responseText !== undefined){

	 
	        // Use the JSON Utility to parse the data returned from the server 
	        try { 
	            hotels = YAHOO.lang.JSON.parse(o.responseText); 
				var i = null;
				l = new VEShapeLayer();
				for ( i=0;hotels.markers.length > i; i +=1)
				{
					var newHotel = new VEShape(VEShapeType.Pushpin , new VELatLong(hotels.markers[i].point.latitude,hotels.markers[i].point.longitude) );
					newHotel.SetTitle(hotels.markers[i].hotelname);
					newHotel.SetDescription(hotels.markers[i].category);
					if (hotels.markers[i].hotelcode == selectedHotelCode)
					{
						hotels.markers[i].highlighted = true;
						
						hotelLat = hotels.markers[i].point.latitude;
						hotelLong = hotels.markers[i].point.longitude;
						
					}
					else
					{
						hotels.markers[i].highlighted = false;
					}
					var currentPinHTML = '<div {0}>{1}</div>'
					l.AddShape(newHotel);
					hotels.markers[i].markerid = newHotel.GetID();
				}

	        } 
	        catch (x) { 
	            alert("JSON Parse failed!"); 
	            return; 
	        } 
			map.AddShapeLayer(l);
			map.AttachEvent("onclick", mapClickHandler);
			map.AttachEvent("onchangeview",	buildupHotelTable);	
			// call new function to build hotel list
			//processIcons(); //have added this to reset map now
			buildupHotelTable();
			resetMap();
			
	}
}

var handleFailure = function(o){
	if(o.responseText !== undefined){
		div.innerHTML = "<li>Transaction id: " + o.tId + "</li>";
		div.innerHTML += "<li>HTTP status: " + o.status + "</li>";
		div.innerHTML += "<li>Status code message: " + o.statusText + "</li>";
	}
}

var callback =
{
  success:handleSuccess,
  failure: handleFailure,
  argument: { foo:"foo", bar:"bar" }
};

function mapClickHandler(e)
{
	//find the clicked element and go there
	var i = null;
	if (e.elementID != null)
	{
		for ( i=0;hotels.markers.length > i; i +=1)
		{
			if(e.elementID.indexOf(hotels.markers[i].markerid) >=0 )
			{
				whichLink(i);
			}
		}
	}
}

function buildupHotelTable()
{
	var changeClass = null;
for ( var i=0;hotels.markers.length > i; i +=1)
	{
	var itemHTML = '';
		
	if (!isPointInRect(new VELatLong(hotels.markers[i].point.latitude,hotels.markers[i].point.longitude), map.GetMapView()))
		{	changeClass = 'map-list-off-map';  }
	else
	{ changeClass = 'map-list-default';	}
				
		itemHTML += '<span onMouseOver="mouseOverHotel('+ i +');" onMouseOut="mouseOffHotel(' + i + ');" class="'+changeClass+'" id="span_' + hotels.markers[i].markerid + '" onclick="panMapToPushPin('+i+');" >';
		itemHTML += i+1 +"&nbsp;&nbsp;"+ hotels.markers[i].hotelname + ":"+hotels.markers[i].category + '</span>';
		hotels.markers[i].hotelListHTML = itemHTML;
	}
	
	// Re-sort markers into a table with 2x columns
	var numPoints = hotels.markers.length;
	var newBuild = '<table align="center" width="600">';
	var trBegin = '';
	var trEnd = '';
	for (var z = 0; z < numPoints; ++z) {
			if ( z % 2 == 0 ) { trBegin = '<tr>'; trEnd = ''; }
			else { trBegin = ''; trEnd = '</tr>'; }
			newBuild += trBegin + '<td>'+ hotels.markers[z].hotelListHTML + '</td>' + trEnd;
	}
	newBuild += '</table>'; 
	document.getElementById('myList').innerHTML = newBuild;	
}

function processIcons()
{

for ( i=0;hotels.markers.length > i; i +=1)
	{
		var marker =  l.GetShapeByID(hotels.markers[i].markerid);
		if(hotels.markers[i].highlighted == true)
		{
			marker.SetZIndex('7000');
			marker.SetCustomIcon("<div id=\'marker\'><img src=\'"+imgPath+"city-map-marker-highlighted-"+(i+1)+".png\'></div>");
		
		}
		else
		{
			marker.SetZIndex('5000');
			marker.SetCustomIcon("<div id=\'marker\'><img src=\'"+imgPath+"city-map-marker-"+(i+1)+".png\'></div>");
		}
		
	}
}

function highlightHotel(arrayIndex)
{
	//document.body.style.cursor = 'pointer';
	//first "unhighlight" all but selected
	
	unhighlightAllHotel();
	hotels.markers[arrayIndex].highlighted = true;
	processIcons();
}

function unhighlightAllHotel()
{
	for (var i=0;hotels.markers.length > i; i +=1)
	{
		if (hotels.markers[i].highlighted && !(selectedHotelCode == hotels.markers[i].hotelcode))
		{
			hotels.markers[i].highlighted = false;
		}
	}
}

function mouseOverHotel(arrayIndex)
{
	document.body.style.cursor = 'pointer';
	var marker = l.GetShapeByID(hotels.markers[arrayIndex].markerid);
	marker.SetZIndex('8000');
	marker.SetCustomIcon("<div id=\'marker\'><img src=\'"+imgPath+"city-map-marker-highlighted-"+(arrayIndex+1)+".png\'></div>");
}

function mouseOffHotel(arrayIndex)
{
	document.body.style.cursor = 'default';
	processIcons();
}


function whichLink(hotel)
{
	var currentURL = location.href;

	if (currentURL.match(/destination/))
	{
		//destination link
		hotels.markers[hotel].destinationlink = '/destination/'+selectedCityName+'/hotel/'+ hotels.markers[hotel].hotelcode;
		//alert(hotels.markers[hotel].destinationlink);
		window.location.href=hotels.markers[hotel].destinationlink ;
	}
	else
	{
		//booking link
		var qs;
		qs = window.location.search.substring(1);
		qs = qs.replace(/hotelcode=[0-9]*/g,'hotelcode=' + hotels.markers[hotel].hotelcode);
		qs = qs.replace(/highlighthotel=[0-9]*/g,'highlighthotel=' + hotels.markers[hotel].hotelcode);

		hotels.markers[hotel].bookinglink = '/booking/hotelpicbooking.asp?' + qs;
		//alert(hotels.markers[hotel].bookinglink);
		window.location.href=hotels.markers[hotel].bookinglink;

	}
}
 
//given a VELatLongRectangle, calculate the centre point	
function getCentreOfRect(rect)
{
	var centrelat = (rect.TopLeftLatLong.Latitude + rect.BottomRightLatLong.Latitude )/2 ;
	var centrelong = (rect.TopLeftLatLong.Longitude + rect.BottomRightLatLong.Longitude )/2 ;
	return new VELatLong(centrelat,centrelong);
}


//given a VELatLongRectangle, calculate the zoomlevel that encompasses box	
function getZoomForRect(rect)
{
	//http://msdn2.microsoft.com/en-us/library/aa940990.aspx
	//and
	//http://social.msdn.microsoft.com/Forums/en-US/vemapcontroldev/thread/cc92b20f-48c8-4895-9ac1-415478c31f54

	var defaultScales = new Array(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 diagonal in KM
	var diagKM = haversineDistance(rect.TopLeftLatLong,rect.BottomRightLatLong);

	//dimensions of the map - need to remove px or percentage and convert to int
	var mapWidth = parseFloat(document.getElementById('myMap').style.width);
	var mapHeight = parseFloat(document.getElementById('myMap').style.height);
	var mapDiag = Math.sqrt(mapWidth * mapWidth + mapHeight * mapHeight);

	var meanScale = diagKM  /mapDiag;

	var zoom = 1;
	for(var ii =1; ii<19;ii++)
	{
		if(meanScale>=defaultScales[ii])
		{
			zoom = ii;
			break;
		}
	}
	zoom = zoom-1;	//This just zooms us out 1 more level to ensure we've got everything nicely in context
	return zoom;
}