/*********************************************************************\
*                                                                     *
* epolys.js                                          by Mike Williams *
*                                                                     *
* A Google Maps API Extension                                         *
*                                                                     *
* Adds various Methods to GPolygon and GPolyline                      *
*                                                                     *
* .Contains(latlng) returns true is the poly contains the specified   *
*                   GLatLng                                           *
*                                                                     *
* .Area()           returns the approximate area of a poly that is    *
*                   not self-intersecting                             *
*                                                                     *
* .Distance()       returns the length of the poly path               *
*                                                                     *
* .Bounds()         returns a GLatLngBounds that bounds the poly      *
*                                                                     *
* .GetPointAtDistance() returns a GLatLng at the specified distance   *
*                   along the path.                                   *
*                   The distance is specified in metres               *
*                   Reurns null if the path is shorter than that      *
*                                                                     *
* .GetIndexAtDistance() returns the vertex number at the specified    *
*                   distance along the path.                          *
*                   The distance is specified in metres               *
*                   Reurns null if the path is shorter than that      *
*                                                                     *
* .Bearing(v1?,v2?) returns the bearing between two vertices          *
*                   if v1 is null, returns bearing from first to last *
*                   if v2 is null, returns bearing from v1 to next    *
*                                                                     *
*                                                                     *
***********************************************************************
*                                                                     *
* Version 1.1       6-Jun-2007                                        *
* Version 1.2       1-Jul-2007 - fix: Bounds was omitting vertex zero *
*                                add: Bearing                         *
*                                                                     *
\*********************************************************************/


// === A method for testing if a point is inside a polygon
// === Returns true if poly contains point
// === Algorithm shamelessly stolen from http://alienryderflex.com/polygon/ 
GPolygon.prototype.Contains = function(point) {
  var j=0;
  var oddNodes = false;
  var x = point.lng();
  var y = point.lat();
  for (var i=0; i < this.getVertexCount(); i++) {
    j++;
    if (j == this.getVertexCount()) {j = 0;}
    if (((this.getVertex(i).lat() < y) && (this.getVertex(j).lat() >= y))
    || ((this.getVertex(j).lat() < y) && (this.getVertex(i).lat() >= y))) {
      if ( this.getVertex(i).lng() + (y - this.getVertex(i).lat())
      /  (this.getVertex(j).lat()-this.getVertex(i).lat())
      *  (this.getVertex(j).lng() - this.getVertex(i).lng())<x ) {
        oddNodes = !oddNodes
      }
    }
  }
  return oddNodes;
}

// === A method which returns the approximate area of a non-intersecting polygon in square metres ===
// === It doesn't fully account for spechical geometry, so will be inaccurate for large polygons ===
// === The polygon must not intersect itself ===
GPolygon.prototype.Area = function() {
  var a = 0;
  var j = 0;
  var b = this.Bounds();
  var x0 = b.getSouthWest().lng();
  var y0 = b.getSouthWest().lat();
  for (var i=0; i < this.getVertexCount(); i++) {
    j++;
    if (j == this.getVertexCount()) {j = 0;}
    var x1 = this.getVertex(i).distanceFrom(new GLatLng(this.getVertex(i).lat(),x0));
    var x2 = this.getVertex(j).distanceFrom(new GLatLng(this.getVertex(j).lat(),x0));
    var y1 = this.getVertex(i).distanceFrom(new GLatLng(y0,this.getVertex(i).lng()));
    var y2 = this.getVertex(j).distanceFrom(new GLatLng(y0,this.getVertex(j).lng()));
    a += x1*y2 - x2*y1;
  }
  return Math.abs(a * 0.5);
}

// === A method which returns the length of a path in metres ===
GPolygon.prototype.Distance = function() {
  var dist = 0;
  for (var i=1; i < this.getVertexCount(); i++) {
    dist += this.getVertex(i).distanceFrom(this.getVertex(i-1));
  }
  return dist;
}

// === A method which returns the bounds as a GLatLngBounds ===
GPolygon.prototype.Bounds = function() {
  var bounds = new GLatLngBounds();
  for (var i=0; i < this.getVertexCount(); i++) {
    bounds.extend(this.getVertex(i));
  }
  return bounds;
}

// === A method which returns a GLatLng of a point a given distance along the path ===
// === Returns null if the path is shorter than the specified distance ===
GPolygon.prototype.GetPointAtDistance = function(metres) {
  // some awkward special cases
  if (metres == 0) return this.getVertex(0);
  if (metres < 0) return null;
  var dist=0;
  var olddist=0;
  for (var i=1; (i < this.getVertexCount() && dist < metres); i++) {
    olddist = dist;
    dist += this.getVertex(i).distanceFrom(this.getVertex(i-1));
  }
  if (dist < metres) {return null;}
  var p1= this.getVertex(i-2);
  var p2= this.getVertex(i-1);
  var m = (metres-olddist)/(dist-olddist);
  return new GLatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m);
}

// === A method which returns the Vertex number at a given distance along the path ===
// === Returns null if the path is shorter than the specified distance ===
GPolygon.prototype.GetIndexAtDistance = function(metres) {
  // some awkward special cases
  if (metres == 0) return this.getVertex(0);
  if (metres < 0) return null;
  var dist=0;
  var olddist=0;
  for (var i=1; (i < this.getVertexCount() && dist < metres); i++) {
    olddist = dist;
    dist += this.getVertex(i).distanceFrom(this.getVertex(i-1));
  }
  if (dist < metres) {return null;}
  return i;
}

// === A function which returns the bearing between two vertices in decgrees from 0 to 360===
// === If v1 is null, it returns the bearing between the first and last vertex ===
// === If v1 is present but v2 is null, returns the bearing from v1 to the next vertex ===
// === If either vertex is out of range, returns void ===
GPolygon.prototype.Bearing = function(v1,v2) {
  if (v1 == null) {
    v1 = 0;
    v2 = this.getVertexCount()-1;
  } else if (v2 ==  null) {
    v2 = v1+1;
  }
  if ((v1 < 0) || (v1 >= this.getVertexCount()) || (v2 < 0) || (v2 >= this.getVertexCount())) {
    return;
  }
  var from = this.getVertex(v1);
  var to = this.getVertex(v2);
  if (from.equals(to)) {
    return 0;
  }
  var lat1 = from.latRadians();
  var lon1 = from.lngRadians();
  var lat2 = to.latRadians();
  var lon2 = to.lngRadians();
  var angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) );
  if ( angle < 0.0 ) angle  += Math.PI * 2.0;
  angle = angle * 180.0 / Math.PI;
  return parseFloat(angle.toFixed(1));
}




// === Copy all the above functions to GPolyline ===
GPolyline.prototype.Contains             = GPolygon.prototype.Contains;
GPolyline.prototype.Area                 = GPolygon.prototype.Area;
GPolyline.prototype.Distance             = GPolygon.prototype.Distance;
GPolyline.prototype.Bounds               = GPolygon.prototype.Bounds;
GPolyline.prototype.GetPointAtDistance   = GPolygon.prototype.GetPointAtDistance;
GPolyline.prototype.GetIndexAtDistance   = GPolygon.prototype.GetIndexAtDistance;
GPolyline.prototype.Bearing              = GPolygon.prototype.Bearing;

/************************************************************
 nog wat functiekes

************************************************************/

function createDistanceMarkers(polyline,divider)
{
 for (var i=0; i<polyline.Distance(); i+=divider) {
      var point = polyline.GetPointAtDistance(i);
      if (point && i != 0) {
		map.addOverlay(createMarker(point,"<b>"+ i /divider+"</b> km"));
      }
    }
}
// Creates a marker at the given point with the given number label
function createMarker(point, description) 
{  var marker = new GMarker(point);  
	GEvent.addListener(marker, "click", function() {    marker.openInfoWindowHtml(description);  });  
	return marker;
}


function createDistanceMarkersWithImage(polyline,divider)
{
 for (var i=0; i<polyline.Distance(); i+=divider) {
      var point = polyline.GetPointAtDistance(i);
      if (point && i != 0) {
		//map.addOverlay(createMarker(point,"<b>"+ i /divider+"</b> km"));
		var imageUrl;
		imageUrl = "http://www.sport.be/layoutimages/googlemaps/iconb"+i/divider+".png";
		var icon = new GIcon();
		icon.image = imageUrl;
		icon.shadow = "http://www.google.com/mapfiles/shadow50.png";
		icon.iconSize = new GSize(20, 34);
		icon.shadowSize = new GSize(37, 34);
		icon.iconAnchor = new GPoint(9, 34);
		map.addOverlay(new GMarker(point, icon));
      }
    }
}

function LoadGPXFileIntoGoogleMap(map, filename)
{
  // Remove any existing overlays from the map.
  map.clearOverlays();

  var request = GXmlHttp.create();
  request.open("GET", filename, true);
  request.onreadystatechange = function()
  {
    if (request.readyState == 4)
    {
      parser = new GPXParser(request.responseXML, map);
      parser.SetTrackColour("#ff0000");		// Set the track line colour
      parser.SetTrackWidth(5);			// Set the track line width
      parser.SetMinTrackPointDelta(0.001);		// Set the minimum distance between track points
      parser.CenterAndZoom(request.responseXML, G_NORMAL_MAP);	// Center and Zoom the map over all the points.
      parser.AddTrackpointsToMap();			// Add the trackpoints
      parser.AddWaypointsToMap();			// Add the waypoints
    }
  }
  request.send(null);
}


  function GV_Background_Opacity(map,opacity) {
	if (opacity == null) { return; }
	if (opacity <= 0) { opacity = 0; }
	else if (opacity > 1) { opacity = opacity/100; }
	gv_bg_opacity = opacity; // this is a global and absolutely necessary for the "moveend" listener
	var screen_opacity = 1-opacity; // this function alters the screen, not the bg
	var id = 'gv_opacity_screen';
	if (!document.getElementById(id)) {
		var new_screen = document.createElement("div");
		new_screen.id = id;
		new_screen.className = 'gmnoprint gv_opacity_screen';
		new_screen.style.position = "absolute";
		// new_screen.style.backgroundColor = "#ffffff";
		new_screen.style.opacity = screen_opacity;
		new_screen.style.filter = "alpha(opacity="+screen_opacity*100+")";
		new_screen.style.KhtmlOpacity = screen_opacity;
		new_screen.style.MozOpacity = screen_opacity;
		map.getPane(G_MAP_MAP_PANE).appendChild(new_screen);
		GEvent.addListener(map, "moveend", function() {
			GV_Background_Opacity(map,eval('gv_bg_opacity'));
		});
	}
	GV_Update_Background_Screen(map,id,screen_opacity);
}
function GV_Update_Background_Screen(map,id,screen_opacity) {
	if (map && document.getElementById(id) && screen_opacity != null) {
		var screen = document.getElementById(id);
		var screen_scale = 3; // how many times bigger than the current width & height is it?
		var map_width = map.getSize().width;
		var map_height = map.getSize().height;
		var nw = new GLatLng(map.getBounds().getNorthEast().lat(),map.getBounds().getSouthWest().lng());
		var offset = map.fromLatLngToDivPixel(nw);
		screen.style.visibility = (screen_opacity == 0) ? 'hidden' : 'visible';
		screen.style.opacity = screen_opacity;
		screen.style.filter = "alpha(opacity="+screen_opacity*100+")";
		screen.style.KhtmlOpacity = screen_opacity;
		screen.style.MozOpacity = screen_opacity;
		screen.style.left = offset.x-(map_width*((screen_scale-1)/2))+"px"; screen.style.top = offset.y-(map_height*((screen_scale-1)/2))+"px";
		screen.style.width = screen_scale*map_width+"px"; screen.style.height = screen_scale*map_height+"px";
		if (document.getElementById('gv_opacity_selector')) {
			var op_menu = document.getElementById('gv_opacity_selector');
			for (i=0; i<op_menu.length; i++) {
				if (op_menu[i].value != '' && op_menu[i].value == Math.round(100*(1-screen_opacity))/100) {
					op_menu.selectedIndex = i;
				}
			}
		}
	}
}

