// Javascript code written by Mark McClure in September 2006.

var small0=0;

// The encode function simply parses the input, calls the
// createEncodings function and sets the results.
/*
function encode() {
  var outString;
  var points = new Array();
  points = document.getElementById("polylineEncoder").inputPoints.value.split("\n");
  if (points[points.length - 1].length == 0) {
    points.pop();
  }
  
  small0 = 1*document.getElementById("polylineEncoder").small0in.value;

  temp = new Array();
  for(i=0; i < points.length; i++) {
    temp = points[i].split(", ");
    points[i] = {
      lat: 1*temp[0],
      lon: 1*temp[1],
      lev: "unset"
    }
  }
  setLevels(points);
  var result = createEncodings(points);
  outString = "new GPolyline.fromEncoded({\n  color: \"#0000ff\",\n  weight: 4,\n  opacity: 0.8,\n  points: ";
  outString = outString + "\"" + result.PointString + "\",\n";
  outString = outString + "  levels: \"" + result.ZoomString + "\",\n";
  outString = outString + "  zoomFactor: 2,\n  numLevels: 18\n});\n";
  document.getElementById("polylineEncoder").encodedPolyline.value = outString;
    
}
*/

// The createEncodings function is taken almost verbatim from
// http://www.google.com/apis/maps/documentation/polyline.js
// The only difference is the technique for passing data in and out.

function createEncodings(points) {
  var i = 0;

  var plat = 0;
  var plng = 0;

  var encoded_points = "";
  var encoded_levels = "";

  var lon=points.length;
  for(i = 0; i < points.length; ++i) 
  {
    var point = points[i];
    var lat = point.lat;
    var lng = point.lon;
    var level = point.lev;

    var late5 = Math.floor(lat * 1e5);
    var lnge5 = Math.floor(lng * 1e5);

    dlat = late5 - plat;
    dlng = lnge5 - plng;

    plat = late5;
    plng = lnge5;

    encoded_points += encodeSignedNumber(dlat) + encodeSignedNumber(dlng);
    encoded_levels += encodeNumber(level);
  }
  return {PointString: encoded_points,ZoomString:  encoded_levels}
}


// The next two functions are taken verbatim from
// http://www.google.com/apis/maps/documentation/polyline.js
function encodeSignedNumber(num) 
{
  var sgn_num = num << 1;

  if (num < 0) {
    sgn_num = ~(sgn_num);
  }

  return(encodeNumber(sgn_num));
}

function encodeNumber(num) 
{
  var encodeString = "";
  var nextValue;

  while (num >= 0x20) {
    nextValue = (0x20 | (num & 0x1f)) + 63;
    if (nextValue == 92) {
      encodeString += (String.fromCharCode(nextValue));
    }
    encodeString += (String.fromCharCode(nextValue));
    num >>= 5;
  }

  finalValue = num + 63;
  if (finalValue == 92) {
    encodeString += (String.fromCharCode(finalValue));
  }
  encodeString += (String.fromCharCode(finalValue));
  return encodeString;
}


// The next two functions set the level string,
// which is a bit trickier.

// dist(point1, point2) returns the distance between point1
// and point2 in meters.  Note that each point needs lat
// and lon properties.
function dist(point1, point2) {
  var deg = 0.0174532925199;
  
  return 12746004.5*Math.asin(Math.sqrt(
    Math.pow(Math.sin((point1.lat - point2.lat)*deg/2),2) + 
      Math.cos(point1.lat*deg)*Math.cos(point2.lat*deg)*
        Math.pow(Math.sin((point1.lon - point2.lon)*deg/2),2)));
}

// We set the levels here.
function setLevels(points) {
  var numLevels = 18;
  var small, i, j;
  var len = points.length;
  
  // Set the endpoints to show at all zoom levels
  points[0].lev = numLevels-1;
  points[len-1].lev = numLevels-1;
  
  // Starting at the largest possible level, we step down through
  // the levels labelling points which need to appear at
  // lower resolutions.
  for (level = numLevels-1; level >= 0; level--) {
    // Set "small" for the current level.
    // More generally, we might use
    // small = small0*Math.pow(2.0, -18*(numLevels-level)/numLevels);
    small = small0*Math.pow(2.0, level-18);
    
    // Figure out which points need to occur at this level,
    // the main criteria being that we've stepped a certain 
    // distance (called "small") from the previous set point.
    i = j = 1;
    while (i < len-1) {
      if (dist(points[i], points[j]) >= small && points[i].lev == "unset") {
        points[i].lev = level;
        j = i;
      }
      if (points[i].lev != "unset") {
        j=i;
      }
      i++;
    }
  }
  // Set any unset points to level 0.
  for (i=0; i < len; i++) {
    if (points[i].lev == "unset") {
      points[i].lev = 0;
    }
  }
}
