// Google Map Control function library
// ============================================================
// This function picks up the click and opens the corresponding info window
function myclick(i) {
  gmarkers[i].openInfoWindowHtml(htmltexts[i]);
}

// ============================================================
function mapcenter(lat,lng,scale) {
  map.setCenter(new GLatLng(lat,lng),scale);
}

// ============================================================
// Takes 3 hexadecimal string color components and concatenates into standard HTML format
function RGB2Color(r,g,b) {
  return '#' + byte2Hex(r) + byte2Hex(g) + byte2Hex(b);
}

// ============================================================
function pointsToPixels(points) {
	var zoom = map.getZoom();
	var pixels = [];
  for (var n = 0 ; n < points.length ; n++ ) {
  	//var Px = normalProj.fromLatLngToPixel(points[n], zoom);
  	var Px = map.getCurrentMapType().getProjection().fromLatLngToPixel(points[n], zoom);
  	pixels.push(Px);
  }	
  return pixels;
}

// ============================================================
// Creates a marker at the given point with the given number label, icon and label symbol
function createMarker(marker_idx, point, name, htmltext, category) {
  var baseIcon = new GIcon();
  switch (category) {
   case 'all': icon = iconPushpin;
   break;
   case 'scene': icon = iconCross;
   break;
   case 'sceneSel': icon = iconCrossSel;
   break;
   case 'cou': icon = iconLandscape;
   break;
   case 'urb': icon = iconTown;
   break;
   case 'sig': icon = iconCastle;
   break;
   case 'acc': icon = iconAccomodation;
   break;
   case 'res': icon = iconFood;
   break;
   case 'spo': icon = iconSport;
   break;
   case 'com': icon = iconHome;
   break;
   default: icon = iconPushpin;
  }
  //var marker = new GMarker(point, {"icon": icon, "title": name});
  var marker = new GMarker(point, {"icon": icon});
  GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowHtml(htmltext);
  });
  // store the name so that the tooltip function can use it
  marker.tooltip = '<div class="marker_tooltip">'+name+'</div>';
  GEvent.addListener(marker,"mouseover", function() {
    showTooltipMarker(marker);
  });        
  GEvent.addListener(marker,"mouseout", function() {
    markerTooltip.style.visibility="hidden";
  });        
  // save the info we need to use later for the map_objectlist
  gmarkers[marker_idx] = marker;
  htmltexts[marker_idx] = htmltext;
  // add a line to the map_objectlist html
  map_objectlist_html += '<li><span class="small"><a href="javascript:myclick(' + marker_idx + ')">' + name + '</a></span></li>';
  //map_objectlist_html += '<a href="pano.php?id=" onmouseover="javascript:myclick(' + marker_idx + ')">' + name + '</a><br>';
  // add the entry to the select box
  marker_select_html += '<option> ' + name + '</option>';
  return marker;
}

// ============================================================
// marker tooltip handling
function showTooltipMarker(marker) {
 	markerTooltip.innerHTML = marker.tooltip;
	var point=map.getCurrentMapType().getProjection().fromLatLngToPixel(map.getBounds().getSouthWest(),map.getZoom());
	var offset=map.getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(),map.getZoom());
	var anchor=marker.getIcon().iconAnchor;
	var width=marker.getIcon().iconSize.width;
	var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(offset.x - point.x - anchor.x + width - 5,- offset.y + point.y +anchor.y - 5)); 
	pos.apply(markerTooltip);
	markerTooltip.style.visibility="visible";
}

// ============================================================
// generic tooltip handling
function showTooltipRoute(mouseLatLng) {
  //markerTooltip.innerHTML = route.tooltip;
 	routeTooltip.innerHTML = '<div class="route_tooltip">test route</div>';
	var point=map.getCurrentMapType().getProjection().fromLatLngToPixel(map.getBounds().getSouthWest(),map.getZoom());
	var offset=map.getCurrentMapType().getProjection().fromLatLngToPixel(mouseLatLng,map.getZoom());
	//var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(point.x,point.y)); 
	var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(offset.x - point.x ,- offset.y + point.y + 7)); 
	pos.apply(routeTooltip);
	routeTooltip.style.visibility="visible";
}

// ============================================================
// A function to read the data
function readMarkers(url) {
  createCookie("auth",1,COOKIE_EXPIRE_AUTH);
  var request = GXmlHttp.create();
  request.open("GET", url, true);
  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      var xmlDoc = request.responseXML;
      // obtain the array of markers and loop through it
      var markers = xmlDoc.documentElement.getElementsByTagName("marker");
      // hide the info window, otherwise it still stays open where the removed marker used to be
      map.getInfoWindow().hide();
      //map.clearOverlays();
      clearMarkers();
      // empty the arrays
      gmarkers.length = 0;
      htmltexts.length = 0;
      var gmarker = [];
      var marker_idx = 0;
      // reset the map_objectlist
      map_objectlist_html=map_objectlist_html_start;
      // reset the select box
      marker_select_html=marker_select_html_start;
      for (var i = 0; i < markers.length; i++) {
        // obtain the attribues of each marker
        var markerLat = parseFloat(markers[i].getAttribute("lat"));
        var markerLng = parseFloat(markers[i].getAttribute("lng"));
        var point = new GLatLng(markerLat,markerLng);
        var markerHtml = markers[i].getAttribute("html");
        var markerLabel = markers[i].getAttribute("label");
        var markerCategory = markers[i].getAttribute("category");
        // create the marker
        var marker = createMarker(marker_idx,point,markerLabel,markerHtml,markerCategory);
        //gmarkers.push(marker);
        //htmltexts.push(markerHtml);
        marker_idx++;
        map.addOverlay(marker);
      }
      // put the assembled map_objectlist_html contents into the map_objectlist div
      map_objectlist_html += map_objectlist_html_end;
      document.getElementById("map_objectlist").innerHTML = map_objectlist_html;
      // final part of the select box
      marker_select_html += marker_select_html_end;
      document.getElementById("marker_selection").innerHTML = marker_select_html;
    }
  }
  request.send(null);
}

// ============================================================
// A function to create polygons (regions and counties)
function readPolygon(url) {
  createCookie("auth",1,COOKIE_EXPIRE_AUTH);
  var request = GXmlHttp.create();
  request.open("GET", url, true);
  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      var xmlDoc = request.responseXML;
      var regions = xmlDoc.documentElement.getElementsByTagName("region");
      // obtain the attribues of the region
      var regionLabel = regions[0].getAttribute("label");
      var regionHtml = regions[0].getAttribute("html");
      var regionCategory = regions[0].getAttribute("category");
      var regionLat = parseFloat(regions[0].getAttribute("lat"));
      var regionLng = parseFloat(regions[0].getAttribute("lng"));
      var regionZoom = parseInt(regions[0].getAttribute("zoom"));
      // obtain the array of nodes and loop through it
      var nodes = xmlDoc.documentElement.getElementsByTagName("p");
    	clearPolygons();
      //region_idx=0;
      var gregion = [];
      var points = [];
      for (var i = 0; i < nodes.length; i++) {
        // obtain the attribues of each node
        var lat = parseFloat(nodes[i].getAttribute("lat"));
        var lng = parseFloat(nodes[i].getAttribute("lng"));
        var point = new GLatLng(lat,lng);
        points.push(point);
      }
      gregion['points'] = points;
      gregion['html'] = regionHtml;
      gregion['label'] = regionLabel;
      gregion['category'] = regionCategory;
      gregion['lat'] = regionLat;
      gregion['lng'] = regionLng;
      gregion['zoom'] = regionZoom;
      var polygon = new GPolygon(points,"#0000ff",2,.4,"#ff0000",.15);
      gregion['polygon'] = polygon;
      gregions.push(gregion);
      //region_idx++;
    	mapcenter(regionLat, regionLng, regionZoom);
    	map.addOverlay(polygon);
    	//alert (regionPoints);
    }
  	//alert ('failed');
  }
  request.send(null);
}

// ============================================================
// A function to create polylines (trails and roads)
function readPolyline(url) {
  createCookie("auth",1,COOKIE_EXPIRE_AUTH);
  var request = GXmlHttp.create();
  request.open("GET", url, true);
  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      var xmlDoc = request.responseXML;
      var routes = xmlDoc.documentElement.getElementsByTagName("route");
      // obtain the attribues of the route
      var routeLabel = routes[0].getAttribute("label");
      var routeHtml = routes[0].getAttribute("html");
      var routeCategory = routes[0].getAttribute("category");
      var routeLat = parseFloat(routes[0].getAttribute("lat"));
      var routeLng = parseFloat(routes[0].getAttribute("lng"));
      var routeZoom = parseInt(routes[0].getAttribute("zoom"));
      // obtain the array of nodes and loop through it
      var nodes = xmlDoc.documentElement.getElementsByTagName("p");
    	clearPolylines();
      //route_idx=0;
      var groute = [];
      var points = [];
      for (var i = 0; i < nodes.length; i++) {
        // obtain the attribues of each node
        var lat = parseFloat(nodes[i].getAttribute("lat"));
        var lng = parseFloat(nodes[i].getAttribute("lng"));
        var point = new GLatLng(lat,lng);
        points.push(point);
      }
    	//var zoom = map.getZoom();
      var pixels = [];
      for (var n = 0 ; n < points.length ; n++ ) {
      	//var Px = normalProj.fromLatLngToPixel(points[n], zoom);
      	//var Px = map.getCurrentMapType().getProjection().fromLatLngToPixel(points[n], zoom);
      	var Px = map.getCurrentMapType().getProjection().fromLatLngToPixel(points[n], routeZoom);
      	pixels.push(Px);
      }	
      groute['points'] = points;
      groute['pixels'] = pixels;
      groute['html'] = routeHtml;
      groute['label'] = routeLabel;
      groute['category'] = routeCategory;
      groute['lat'] = routeLat;
      groute['lng'] = routeLng;
      groute['zoom'] = routeZoom;
      var polyline = new GPolyline(points,"#00dd00",2,.6);
      groute['polyline'] = polyline;
      groutes.push(groute);
      //route_idx++;
    	mapcenter(routeLat, routeLng, routeZoom);
    	map.addOverlay(polyline);
    	//routePixels = pointsToPixels(routePoints);
    }
  }
  request.send(null);
}

// ============================================================
// clear all markers
function clearMarkers() {
  if (gmarkers.length) {
    for (var i = 0 ; i < gmarkers.length ; i++ ) {
     	map.removeOverlay(gmarkers[i]);
    }
  }
}

// ============================================================
// clear all polylines in the map
function clearPolylines() {
  if (groutes.length) {
    for (var i = 0 ; i < groutes.length ; i++ ) {
  	  map.removeOverlay(groutes[i]['polyline']);
  	}
	}
}

// ============================================================
// clear all polygons in the map
function clearPolygons() {
  if (gregions.length) {
    for (var i = 0 ; i < gregions.length ; i++ ) {
  	  map.removeOverlay(gregions[i]['polygon']);
  	}
	}
}

// ============================================================
// clear everything on the map - markers, polylines, polygons
function clearAllShapes() {
  map.clearOverlays();
}

// ============================================================
// checking if there is any polyline within a distThreshold reach of the mouse pointer
function getProximity(mouseLatLng,infoType) {
//function getProximity(mouseLatLng) {
  //var infoType = 'tooltip';
  //var infoType = 'infowindow';
	var zoom = map.getZoom();
	var minDist = distThreshold;
	//var mousePx = normalProj.fromLatLngToPixel(mouseLatLng, zoom);
	var mousePx = map.getCurrentMapType().getProjection().fromLatLngToPixel(mouseLatLng, zoom);
	if (groutes.length > 0) {
    for (var m = 0 ; m < groutes.length ; m++ ) {
      var routePixels = [];
      routePixels = groutes[m]['pixels'];
    	if (routePixels.length > 1) {
    		for (var n = 1 ; n < routePixels.length ; n++ ) {
    			if (routePixels[n].x != routePixels[n-1].x) {
    				var a = (routePixels[n].y - routePixels[n-1].y) / (routePixels[n].x - routePixels[n-1].x);
    				var b = routePixels[n].y - a * routePixels[n].x;
    				var dist = Math.abs(a*mousePx.x + b - mousePx.y) / Math.sqrt(a*a+1);
    			}
    			else {
    				var dist = Math.abs(mousePx.x - routePixels[n].x)
    			}
    			// length^2 of line segment 
    			var rl2 = Math.pow(routePixels[n].y - routePixels[n-1].y,2) + Math.pow(routePixels[n].x - routePixels[n-1].x,2);
    			// distance^2 of pt to end line segment
    			var ln2 = Math.pow(routePixels[n].y - mousePx.y,2) + Math.pow(routePixels[n].x - mousePx.x,2);
    			// distance^2 of pt to begin line segment
    			var lnm12 = Math.pow(routePixels[n-1].y - mousePx.y,2) + Math.pow(routePixels[n-1].x - mousePx.x,2);
    			// minimum distance^2 of pt to infinite line
    			var dist2 = Math.pow(dist,2);
    			// calculated length^2 of line segment
    			var calcrl2 = ln2 - dist2 + lnm12 - dist2;
    			// redefine minimum distance to line segment (not infinite line) if necessary
    			if (calcrl2 > rl2) {
    				dist = Math.sqrt( Math.min(ln2,lnm12) ); 
    			}
    			minDist = Math.min(minDist,dist);
    		}
    		if (minDist < distThreshold) {
    		  //document.body.style.cursor='help';
    		  switch (infoType) {
    		    case 'tooltip': 
    		      showTooltipRoute(mouseLatLng);
    		    break;
    		    case 'infowindow':
    		    default:
              routeTooltip.style.visibility="hidden";
        			map.openInfoWindowHtml(mouseLatLng,'Proximity Alert<br>Mouse distance to line: ' + minDist.toFixed(2));
          }
    		}
    		else {
    		  //document.body.style.cursor='hand';  // IE
    		  //document.body.style.cursor='pointer';
    		  switch (infoType) {
    		    case 'tooltip': 
              routeTooltip.style.visibility="hidden";
    		    break;
    		    case 'infowindow':
    		    default:
              routeTooltip.style.visibility="hidden";
         			//map.closeInfoWindow();
          }
    		}
    	}
    }
  }
}

// ============================================================
function getProximityMouseMove(mouseLatLng) {
  getProximity(mouseLatLng,'tooltip');
}

// ============================================================
function getProximityClick(overlay,mouseLatLng) {
  getProximity(mouseLatLng,'infowindow');
}


// ============================================================
// This function handles selections from the select box
// If the dummy entry is selected, the info window is closed
function handleSelected(opt) {
  var j = opt.selectedIndex - 1; 
  if (j > -1) {
    GEvent.trigger(gmarkers[j],"click");
  }
  else {
    map.closeInfoWindow();
  }
}

// ============================================================
// This function handles selections from the category list
function switchCategory(cat) {
  document.getElementById("cat_"+CategoryId_current).className='';
  document.getElementById("cat_"+cat).className='selected';
  CategoryId_current=cat;
  //readMarkers("map/mapdata-"+cat+".xml");
  //readMarkers("mapdata.xml.php");
  //readMarkers("mapdata.xml.php?category="+cat);
  readMarkers("/map-markers.xml.php?pst="+State_current+"&category="+cat+"&lang="+Lang_current);
  createCookie("cat",cat,COOKIE_EXPIRE);
  if (document.getElementById("scene_switch")) {
    ShowScenes_current = false;
    document.getElementById("scene_switch").innerHTML = LANG_SHOW_SCENES;
  }
  return false;
}


// === Geocoding with error handling ==========================
// Geocoding
function showAddress() {
  var map_search = document.getElementById("map_search").value;
  map_search += ', ' + state_name_search;
  // Perform the Geocoding
  geo.getLocations(map_search, function (result)
    { 
      // If that was successful
      if (result.Status.code == G_GEO_SUCCESS) {
        // How many resuts were found
        var map_search_message = map_search_message_start_part1 + result.Placemark.length + map_search_message_start_part2;
        // Loop through the results, placing markers
        for (var i=0; i<result.Placemark.length; i++) {
          addressArray = result.Placemark[i].address.split(", ");
          addressShort = '';
          for (var j=0; j<(addressArray.length-1); j++) {
            if (j>0) addressShort += ', ';
            addressShort += addressArray[j];
          }
          var p = result.Placemark[i].Point.coordinates;
          var marker = new GMarker(new GLatLng(p[1],p[0]));
          map_search_message += '<li><span class="small"><a href="javascript:mapcenter('+p[1]+','+p[0]+',13)">' + addressShort + '</a> <em>' + marker.getPoint() + '</em></span></li>';
          //map.addOverlay(marker);
        }
        //alert(map_search_message);
        map_search_message += map_search_message_end;
        document.getElementById("map_search_message").innerHTML = map_search_message;
        // centre the map on the first result
        var p = result.Placemark[0].Point.coordinates;
        map.setCenter(new GLatLng(p[1],p[0]),13);
      }
      // Decode the error status
      else {
        var reason = "\n" + "[Code " + result.Status.code + "]";
        if (geocode_reasons[result.Status.code]) {
          reason += "\n" + geocode_reasons[result.Status.code];
        } 
        alert(LANG_COULDNOT_FIND + ' "'+map_search+ '" ' + reason);
      }
    }
  );
}

