//"Presents a helicopter landing pad ground overlay
//written by: Paul van Dinther
//            Dinther Product Design
//            Software development and specialists in simulation
//            email: vandinther@gmail.com
//
//Copyright 2010 Dinther Product Design Ltd
//
//This unit assumes the ge variable represents the ge plugin.
//This unit uses globals.js

//places overlay with size defined in meters corrected for latitude
function createOverlay(name, latitude, longitude, metersToLocalLon, height, width, angle, href, drawOrder) {
	var latLonBox = ge.createLatLonBox('');
	var myGroundOverlay = ge.createGroundOverlay('');
	if (drawOrder == null) {drawOrder = 10;}
	myGroundOverlay.setName(name);
	myGroundOverlay.setIcon(ge.createIcon(''));
	myGroundOverlay.getIcon().setHref(href);
	myGroundOverlay.setLatLonBox(latLonBox);
	myGroundOverlay.setDrawOrder(drawOrder);
	setLatLonBoxAsMeters(myGroundOverlay.getLatLonBox(), latitude, longitude, metersToLocalLon, height, width, angle);
	ge.getFeatures().appendChild(myGroundOverlay);
	return (myGroundOverlay);
} 


function createScreenOverlay(anchorx, anchory,left,top,width,height, units,imageUrl, drawOrder){
	var myScreenOverlay = ge.createScreenOverlay('');
	myScreenOverlay.setDrawOrder(drawOrder+4);
	myScreenOverlay.setIcon(ge.createIcon(''));
	myScreenOverlay.getIcon().setHref(imageUrl);
	myScreenOverlay.getScreenXY().setXUnits(units);
	myScreenOverlay.getScreenXY().setYUnits(units);
	myScreenOverlay.getScreenXY().setX(anchorx);
	myScreenOverlay.getScreenXY().setY(anchory);
	myScreenOverlay.getOverlayXY().setXUnits(units);
	myScreenOverlay.getOverlayXY().setYUnits(units);
	myScreenOverlay.getOverlayXY().setX(left);
	myScreenOverlay.getOverlayXY().setY(top);
	myScreenOverlay.getSize().setXUnits(units);
	myScreenOverlay.getSize().setYUnits(units);  
	if (width != 0 && height != 0){	
		myScreenOverlay.getSize().setX(width);
		myScreenOverlay.getSize().setY(height);
	}
	myScreenOverlay.setVisibility(true);
	myScreenOverlay.getColor().setA(255);
	ge.getFeatures().appendChild(myScreenOverlay);
	return (myScreenOverlay);
}   
    
//assumes use of standard framework providing mouseX, mouseXInset,mouseXfract, mouseY, mouseYInset and mouseYfract
mouseInArea = function(left,top,width,height,units){
	switch(units){
		case ge.UNITS_FRACTION:		{var lmouseX = mouseXfract; var lmouseY = mouseYfract; break; }
		case ge.UNITS_PIXELS:		{var lmouseX = mouseX; var lmouseY = mouseY; break; }
		case ge.UNITS_INSET_PIXELS:     {var lmouseX = mouseXInset; var lmouseY = mouseYInset;  break; }
	}
	var _inBox = false;
	if (lmouseX > left && lmouseX < left + width ){
		if (lmouseY > top && lmouseY < top + height){
			_inBox = true;
		}
	}
	return( _inBox);
}   
    
//defines latlonbox at a given location expressed in size and width and height in meters and angle
function setLatLonBoxAsMeters(latLonBox, latitude, longitude, metersToLocalLon, height, width, angle){    
    height = height * G_metersToLocalLat * 0.5;
    width = width * metersToLocalLon * 0.5;
    latLonBox.setNorth(latitude + height);
    latLonBox.setSouth(latitude - height);
    latLonBox.setEast(longitude + width);
    latLonBox.setWest(longitude - width);
    latLonBox.setRotation(-angle+90);
    return (latLonBox);
}


//returns approximate location coordinates based on bearing in degrees and distance in meters relative to location1
//assign variable to return and use as myvar.latitude ect.
//Requires global.js
function getlocalBDLocation(latitude, longitude, metersToLocalLon, bearing, distance){
	//calc lat and lon delta distances in meters  
	var radBearing = bearing * G_degreesToRad;
	var latDelta = Math.cos(radBearing);
	var lonDelta = Math.sin(radBearing);
	var outLatitude = latitude + latDelta * distance * G_metersToLocalLat;
	var outLongitude = longitude +  lonDelta * distance * metersToLocalLon;
	//fix lon
	if (outLongitude > 180) { outLongitude -= 360;}
	if (outLongitude < -180) { outLongitude += 360;}
	return{latitude:outLatitude, longitude:outLongitude};
}

//returns distance between two coordinates in meters.
function getDistance(latitude1, longitude1, latitude2, longitude2, metersToLocalLon){
	var deltaLat = (latitude1 - latitude2) / G_metersToLocalLat;
	var deltaLon = (longitude1 - longitude2) / metersToLocalLon;
	var distance = Math.sqrt(Math.pow(deltaLat,2) + Math.pow(deltaLon,2));
	return ( distance );
}

//returns approximate bearing location2 in relation to location1
function getBearingDistance(latitude1,longitude1, latitude2,longitude2, metersToLocalLon){
	//calc lat and lon delta distances in meters  
	var deltalat = (latitude2 - latitude1) / G_metersToLocalLat;
	var deltalon = (longitude2-longitude1) / metersToLocalLon;
	var distance = Math.sqrt((deltalat * deltalat) + (deltalon * deltalon));
	var bearing = Math.atan2(deltalon,deltalat)/G_degreesToRad;
	return{bearing:bearing, distance:distance};
}

function createMovableGroundOverlay(latitude,longitude, height, width, heading, url){
	this.groundOverlay = createOverlay('',latitude,longitude, getMetersToLocalLon(latitude),height,width,heading,url);
	this.setLocation = function(latitude, longitude, heading, MetersToLocalLon){
		if (this.groundOverlay){
			setLatLonBoxAsMeters(this.groundOverlay.getLatLonBox(),latitude, longitude, MetersToLocalLon,height,width,heading); 
		}	
	}
}

function pointInLatLngBox(latitude, longitude, latLngBox){
	return (longitude < latLngBox.getEast() && longitude > latLngBox.getWest() && latitude > latLngBox.getSouth() && latitude < latLngBox.getNorth());
}

//Rotates location1 around location2 at the given angle in degrees
//cosLatitude is passed in as it is usually already known un the globals.js unit
function rotateLocationAround(latitude,longitude,centerlat,centerlng, angle, cosLatitude){
 var x = (longitude - centerlng) * cosLatitude;
 var y = latitude - centerlat;
 var radAngle = -angle * G_degreesToRad;
 var cosAngle = Math.cos(radAngle);
 var sinAngle = Math.sin(radAngle);
 var latnew = centerlat + (y * cosAngle + x * sinAngle);
 var longnew = centerlng + (x * cosAngle - y * sinAngle)/cosLatitude;
 return{latitude: latnew, longitude: longnew};
}

function fix360(angle){
	while (angle > 360) { angle -= 360 }
	while (angle < 0) { angle += 360 }
	return ( angle );
}

function fix180(angle){
	while (angle > 180) { angle -= 360 }
	while (angle < -180) { angle += 360 }
	return ( angle );
}

//tests point in KMLPolygon
function locationInPolygon(kmlPoly, latitude, longitude){
  var locationInBoundary = function(boundary, latitude, longitude){
      var j=0;
      var inside = false;
      var x = longitude;
      var y = latitude;
      var lat1 = 0;
      var lat2 = 0;
      var lon1 = 0;
      var lon2 = 0;
      var coordinates = boundary.getCoordinates();
      var pointCount = coordinates.getLength();
      
      for (var i=0; i < pointCount; i++) {
        j++;
        if (j == pointCount) {j = 0;}
        lat1 = coordinates.get(i).getLatitude();
        lat2 =coordinates.get(j).getLatitude();
        lon1 = coordinates.get(i).getLongitude();
        lon2 = coordinates.get(j).getLongitude();
        if (((lat1 < y) && (lat2 >= y)) 
        || ((lat2 < y) && (lat1 >= y))) {
          if ( lon1 + (y - lat1)
          /  (lat2-lat1)
          *  (lon2 - lon1)<x ) {
            inside = !inside
          }
        }
      }
      return inside;
    }
  var inside = false;
  var outer = kmlPoly.getOuterBoundary();
  inside = locationInBoundary(outer, latitude, longitude);
  if (inside){
    //check all inner boundaries if any.
    var inners = kmlPoly.getInnerBoundaries().getChildNodes();
    for (var i=0; i < inners.getLength(); i++) {
	inside = locationInBoundary(inners.item(i), location);
       //inners are like holes in a polygon
       if (inside){ inside = !inside; break;}
   }
  } 
  return inside;
 };

//Forces a value between two limits.
function clamp(val, min, max) {
	return Math.min(Math.max(min,val),max);
};

// Keep an angle in [-180,180]
function fixAngle(a) {
  while (a < -180) {
    a += 360;
  }
  while (a > 180) {
    a -= 360;
  }
  return a;
}

// Keep an angle in [0,360]
function fix360Angle(a) {
  while (a < 0) {
    a += 360;
  }
  while (a > 360) {
    a -= 360;
  }
  return a;
}

//Return the angle in degrees between two vectors
function getAngleDeg(V1,V2){
	return (Math.acos(VectorAngleCosine(V1,V2)) * (180/Math.PI));
}

//Return the cosine of the angle between two vectors
function VectorAngleCosine(V1, V2){
	return (V3.dot(V1,V2)/(V3.length(V1)*V3.length(V2)));
};

function getUrlParameter( name )
{
	name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	var regexS = "[\\?&]"+name+"=([^&#]*)";
	var regex = new RegExp( regexS );
	var results = regex.exec( window.location.href );
	if( results == null )
		return "";
	else
	    return results[1];
};

//returns approximate bearing and tilt in degrees and distance in meters of location2 in relation to location1
//Tilt value where 0 means looking straight down. Pass Camera as location1 and target
//Values can be applied directly to camera properties
//more accurate but slower calculations here: http://www.movable-type.co.uk/scripts/latlong.html
function getBearingDistanceTilt(latitude1, longitude1, altitude1, latitude2, longitude2, altitude2, metersToLocalLon){  
  //calc lat and lon delta distances in meters  
  var deltalatmeters = (latitude2 - latitude1) / G_metersToLocalLat;
  if (deltalatmeters == 0){deltalatmeters = 1;}
  var deltalonmeters = (longitude2-longitude1) / metersToLocalLon;
  var bearing = Math.atan(deltalonmeters/deltalatmeters)/G_degreesToRad;
  if (deltalatmeters < 0) {bearing = 180 + bearing;}
  //calculate distance
  var distance = Math.sqrt((deltalatmeters * deltalatmeters) + (deltalonmeters * deltalonmeters));
  //calculate tilt
  var deltaAltitude = altitude1 - altitude2;
  var tilt = Math.atan( distance/deltaAltitude)/G_degreesToRad;
  if (tilt < 0){tilt = 180 + tilt}
  //Include altitude in true distance reading
  var range = Math.sqrt((deltaAltitude * deltaAltitude) + (distance * distance));
  bearing = fixAngle(bearing);
  return{bearing:bearing, tilt:tilt, distance:distance, range:range};
};

function isDefined(value){
	if (value == null) {
		return false;
	} else if (typeof(value) == 'undefined') {
		return false;
	} else {
		return true;
	}
}


//Corrects screenOverlay aspect for a given targetWidth or targetHeight. Choose either one.
//The aspect is screen aspect is screen width / height
function correctAspectSize(screenOverlay, bitmapWidth, bitmapHeight, targetWidth, targetHeight, aspect){
	if (targetWidth > 0){
		var newHeight = (1/bitmapWidth) * bitmapHeight * targetWidth * aspect;
		if (isDefined(screenOverlay)){
			screenOverlay.getSize().setY(newHeight);
		}
		return newHeight;
	} else if (targetHeight > 0) {
		var newWidth = (1/bitmapHeight) / bitmapWidth * targetHeight * aspect; //to test
		if (isDefined(screenOverlay)){
			screenOverlay.getSize().setX(newWidth);
		}
		return newWidth;
	}
};

//Corrects screenOverlay position for a given originalX and originalY. Provide either targetX or Y and put in zero for the one to be calculated.
//The aspect is screen aspect is screen width / height
function correctAspectPosition(screenOverlay, orgiginalX, orgiginalY, targetX, targetY, aspect){
	if (targetX > 0){
		var newY = orgiginalY * aspect;
		if (isDefined(screenOverlay)){
			screenOverlay.getOverlayXY().setY(newY);
		}
		return newY;
	} else if (targetY > 0){	
		var newX = orgiginalX / aspect; //to test
		if (isDefined(screenOverlay)){
			screenOverlay.getOverlayXY().setX(newX);
		}
		return newX;
	}
};

//Creates something to focus on top of plugin
//by not setting any background color the control remains invisible on most browsers
//Otherwise it is placed discretely in the lower left corner of the ge window
//Serves as workaround for ancient issue with keyboard events
//Place this code in mouseup event handler:

//document.getElementById('takecontrol').focus();
function createFocusControl(containerid) {
	var button = document.createElement('a');
	button.id = 'takecontrol';
	button.href = '#';
	button.style.display = 'block';
	button.innerHTML = 'PIA';
	button.id = 'takecontrol';
	button.style.position = 'absolute';
	button.style.left = '5px';
	button.style.bottom = '5px';
	button.style.width = '25px';
	button.style.height = '18px';
	document.getElementById(containerid).appendChild(button);
};
