﻿//<![CDATA[
// thanks to Wolfgang Pichler, http://www.wolfpil.de/, modified by dlek

// Global variables
var poly;
var polyinter;
var count = 0;
var points = new Array();
var markers = new Array();
var tooltip;
var currentspeed=0;
var lineColor = "yellow";
var lineWeight = 2;
var lineOpacity = .8;


function addIcon(icon) { // Add icon attributes
     icon.shadow= "icons/mm_20_shadow.png";
     icon.iconSize = new GSize(12, 20);
     icon.shadowSize = new GSize(22, 20);
     icon.iconAnchor = new GPoint(6, 20);
     icon.infoWindowAnchor = new GPoint(5, 1);
}


function showTooltip(marker) { // Display tooltips
     tooltip.innerHTML = marker.tooltip;
     tooltip.style.display = "block";

     // Tooltip transparency specially for IE
     if(typeof(tooltip.style.filter) == "string") {
     tooltip.style.filter = "alpha(opacity:70)";
     }

     var currtype = map.getCurrentMapType().getProjection();
     var point= currtype.fromLatLngToPixel(map.fromDivPixelToLatLng(new GPoint(0,0),true),map.getZoom());
     var offset= currtype.fromLatLngToPixel(marker.getLatLng(),map.getZoom());
     var anchor = marker.getIcon().iconAnchor;
     var width = marker.getIcon().iconSize.width + 6;
     var height = 10;
     var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(offset.x - point.x - anchor.x + width, offset.y - point.y -anchor.y - height)); 
     pos.apply(tooltip);
}


function initDistance(x,y,speed) {
     // Add a div element for toolips
     if(!tooltip)
        tooltip = document.createElement("div");
     tooltip.className="distancetip";
     map.getPane(G_MAP_MARKER_PANE).appendChild(tooltip);
     currentspeed=speed;
    
    //draw first waypoint
    leftClick(null,new GLatLng(x,y));
    
    // Add click listener for next waypoints
    GEvent.addListener(map, "click", leftClick);
}


function leftClick(overlay, point, speed) {
if(point) {
    count++;

    var icon = new GIcon();
    icon.image = "icons/mm_20_purple.png";
    addIcon(icon);

    // Make markers draggable
    var marker = new GMarker(point, {icon:icon, draggable:true, bouncy:false, dragCrossMove:true});
    //map.addOverlay(marker);
    marker.content = count;
    markers.push(marker);

    GEvent.addListener(marker, "mouseover", function() {
        showTooltip(marker);
    });

    GEvent.addListener(marker, "mouseout", function() {
        tooltip.style.display = "none";
    });

    // Drag listener
    GEvent.addListener(marker, "dragend", function() {
        //tooltip.style.display= "none";
        drawDistance();
    });

    GEvent.addListener(map, "singlerightclick", function(){
        clearDistance();
    });

    drawDistance();
  }
}

function drawDistance(){

    if(markers.length==0)
        return;

    if(poly) { map.removeOverlay(poly); }
    points.length = 0;
    map.clearOverlays();

    for(i = 0; i < markers.length; i++) {
        points.push(markers[i].getLatLng());
        map.addOverlay(markers[i]);
    }
    
    poly = new GPolyline(points, lineColor, lineWeight, lineOpacity);
    
    //Distance, time to go and ETA
    var dist = poly.getLength()/1852;
    var course = 0;
    if(markers.length>1)
        course = bearing(markers[markers.length-2].getPoint(),markers[markers.length-1].getPoint());
    var totalmins = Math.floor(dist*60/currentspeed);
    var days = Math.floor(totalmins/1440);
    totalmins%=1440;
    var hours = Math.floor(totalmins/60);
    totalmins%=60;
    var minutes = Math.floor(totalmins);
    var eta = new Date();
    eta.setTime(eta.valueOf() + dist*3600000/currentspeed);

    var tip = "";
    if(markers.length>1 && currentspeed>0.5)
        tip="Waypoint" + (markers.length-1).toString() + ": " + dist.toFixed(1) + " NM, "
        + course + "&deg;"
        + "<br/>" + days + "d " + hours + "h " + minutes + "min (at " + currentspeed.toFixed(1) + " knots)"
        + "<br/>ETA: " + eta.getUTCFullYear() + "-" + zeroPad(eta.getUTCMonth(),2) + "-" + zeroPad(eta.getUTCDate(),2) + " " + zeroPad(eta.getUTCHours(),2) + ":" + zeroPad(eta.getUTCMinutes(),2) + " (UTC)"
        + "<br/><span style=\"font-size:7pt\">(Click on next waypoint"
        + "<br/>or Right-click to clear)</span>";
    else if(markers.length>1 && currentspeed<=0.5)
        tip="Waypoint" + (markers.length-1).toString() + ": " + dist.toFixed(1) + " NM, "
        + course + "&deg;"
        + "<br/><span style=\"font-size:7pt\">(Click on next waypoint"
        + "<br/>or Right-click to clear)</span>";
    else
        tip = "Waypoint0<br/><span style=\"font-size:7pt\">Click on next waypoint</span>";

    markers[markers.length-1].tooltip=tip;
    showTooltip(markers[markers.length-1]);
    map.addOverlay(poly);
}

function clearDistance() {
//alert("clear");
if(markers.length>1)    {   //avoid clearing if we have the first point only
    tooltip.style.display = "none";
    GEvent.clearListeners(map, "singlerightclick");
    GEvent.clearListeners(map, "click");
    map.clearOverlays();
    points.length = 0;
    markers.length = 0;
    count = 0;
 }
 //clear intersection
 if(polyinter) {
    tooltip.style.display = "none";
    GEvent.clearListeners(map, "singlerightclick");
    map.clearOverlays();
    inter1=0;
    inter2=0;
 }
}

function zeroPad(num,count){
    var numZeropad = num + '';
    while(numZeropad.length < count) {
        numZeropad = "0" + numZeropad;
    }
    return numZeropad;
}

     function bearing(from, to) {
     // Returns the bearing in degrees between two points.
       // Convert to radians.
       var lat1 = from.latRadians();
       var lon1 = from.lngRadians();
       var lat2 = to.latRadians();
       var lon2 = to.lngRadians();

       // Compute the angle.
       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;

       // And convert result to degrees.
       angle = angle * 180.0 / Math.PI;
       angle = angle.toFixed(1);

       return angle;
     }

//Returns the point of intersection of two paths defined by point and bearing
function intersection(p1, brng1, p2, brng2) {
   var lat1 = p1.latRadians();
   var lon1 = p1.lngRadians();
   var lat2 = p2.latRadians();
   var lon2 = p2.lngRadians();
  var brng13 = brng1*Math.PI/180, brng23 = brng2*Math.PI/180;
  var dLat = lat2-lat1, dLon = lon2-lon1;
  
  dist12 = 2*Math.asin( Math.sqrt( Math.sin(dLat/2)*Math.sin(dLat/2) + 
    Math.cos(lat1)*Math.cos(lat2)*Math.sin(dLon/2)*Math.sin(dLon/2) ) );
  if (dist12 == 0) return null;
  
  // initial/final bearings between points
  brngA = Math.acos( ( Math.sin(lat2) - Math.sin(lat1)*Math.cos(dist12) ) / 
    ( Math.sin(dist12)*Math.cos(lat1) ) );
  if (isNaN(brngA)) brngA = 0;  // protect against rounding
  brngB = Math.acos( ( Math.sin(lat1) - Math.sin(lat2)*Math.cos(dist12) ) / 
    ( Math.sin(dist12)*Math.cos(lat2) ) );
  
  if (Math.sin(lon2-lon1) > 0) {
    brng12 = brngA;
    brng21 = 2*Math.PI - brngB;
  } else {
    brng12 = 2*Math.PI - brngA;
    brng21 = brngB;
  }
  
  alpha1 = (brng13 - brng12 + Math.PI) % (2*Math.PI) - Math.PI;  // angle 2-1-3
  alpha2 = (brng21 - brng23 + Math.PI) % (2*Math.PI) - Math.PI;  // angle 1-2-3
  
  if (Math.sin(alpha1)==0 && Math.sin(alpha2)==0) return null;  // infinite intersections
  if (Math.sin(alpha1)*Math.sin(alpha2) < 0) return null;       // ambiguous intersection
  
  alpha3 = Math.acos( -Math.cos(alpha1)*Math.cos(alpha2) + 
                       Math.sin(alpha1)*Math.sin(alpha2)*Math.cos(dist12) );
  dist13 = Math.atan2( Math.sin(dist12)*Math.sin(alpha1)*Math.sin(alpha2), 
                       Math.cos(alpha2)+Math.cos(alpha1)*Math.cos(alpha3) )
  lat3 = Math.asin( Math.sin(lat1)*Math.cos(dist13) + 
                    Math.cos(lat1)*Math.sin(dist13)*Math.cos(brng13) );
  dLon13 = Math.atan2( Math.sin(brng13)*Math.sin(dist13)*Math.cos(lat1), 
                       Math.cos(dist13)-Math.sin(lat1)*Math.sin(lat3) );
  lon3 = lon1+dLon13;
  lon3 = (lon3+Math.PI) % (2*Math.PI) - Math.PI;  // normalise to -180..180º
  
  return new GLatLng(lat3*180/Math.PI, lon3*180/Math.PI);
}


function drawIntersection(index1, index2) {
    if(polyinter) { map.removeOverlay(polyinter); }
    points=new Array();
    //find intersection point
    p1=new GLatLng(x[mmsi[index1]], y[mmsi[index1]]);
    p2=new GLatLng(x[mmsi[index2]], y[mmsi[index2]]);
    interpoint=intersection(p1, course[index1], p2, course[index2]);

    if(interpoint && p1.distanceFrom(interpoint)/1852<100) { //intersection in less than 100 miles
        //right click listener to clear    
        GEvent.addListener(map, "singlerightclick", function(){
            clearDistance();
        });

        //draw polyline
        points.push(p1);
        points.push(interpoint);
        points.push(p2);    
        polyinter = new GPolyline(points, lineColor, lineWeight, lineOpacity);
        map.addOverlay(polyinter);
        
        //marker with info
        var icon = new GIcon();
        icon.image = "icons/mm_20_purple.png";
        addIcon(icon);
        var marker = new GMarker(interpoint, {icon:icon, draggable:false, bouncy:false});

        //calculations and info
        var distance1=p1.distanceFrom(interpoint)/1852.0;
        var distance2=p2.distanceFrom(interpoint)/1852.0;
        var time1=Math.floor(distance1/speed[index1]*600.0);
        var time2=Math.floor(distance2/speed[index2]*600.0);
        distance1=Math.round(distance1*100)/100.0;
        distance2=Math.round(distance2*100)/100.0;
        var info="Course Intersection at:<br/>";
        info+=shipname[index1]+": " + time1 + " minutes (" + distance1 + " n.miles at " + speed[index1]/10.0 + " knots)<br/>";
        info+=shipname[index2]+": " + time2 + " minutes (" + distance2 + " n.miles at " + speed[index2]/10.0 + " knots)";
        
        //tooltip
        if(!tooltip)
            tooltip = document.createElement("div");
        tooltip.className="distancetip";
        map.getPane(G_MAP_MARKER_PANE).appendChild(tooltip);
        map.addOverlay(marker);
        marker.tooltip=info;
        showTooltip(marker);
    }
}

function predicted(startpoint, bearing, speed, minutes) {
//returns the predicted geo point starting from current point, with given bearing, speed and time
    var d = speed * minutes/60.0; //distance in nm
    var R = 3440.0; //earth radius in nm
    var brng = bearing*Math.PI/180; //in radius
    var lat1 = startpoint.latRadians();
    var lon1 = startpoint.lngRadians();

    var lat2 = Math.asin(Math.sin(lat1)*Math.cos(d/R) + Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng));
    var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1), Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));

    return new GLatLng(lat2*180/Math.PI, lon2*180/Math.PI);
}

function drawPredicted(shipindex, minutes) {
if(speed[shipindex]>5 && minutes>0) {
    points=new Array();
    //find predicted point
    p1=new GLatLng(x[mmsi[shipindex]], y[mmsi[shipindex]]);
    p2=predicted(p1, course[shipindex], speed[shipindex]/10.0, minutes);

    //color
    var color=shipcolor[shiptype[shipindex]];
    if(color=="lightgreen")
        color="green";
    else if(color=="lightgray")
        color="gray";
    else if(color=="magenta")
        color="purple";
    else if(color=="cyan")
        color="aqua";

    //draw polyline
    points.push(p1);
    points.push(p2);    
    var poly = new GPolyline(points, color, 1, lineOpacity);
    map.addOverlay(poly);
    }
}

//]]>

