//http://code.google.com/apis/maps/documentation/polylinealgorithm.html

// Encode a signed number in the encode format.
function encodeSignedNumber(num) {
  var sgn_num = num << 1;

  if (num < 0) {
    sgn_num = ~(sgn_num);
  }

  return(encodeNumber(sgn_num));
}

// Encode an unsigned number in the encode format.
function encodeNumber(num) {
  var encodeString = "";

  while (num >= 0x20) {
    encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));
    num >>= 5;
  }

  encodeString += (String.fromCharCode(num + 63));
  return encodeString;
}

// Create the encoded polyline and level strings. If moveMap is true
// move the map to the location of the first point in the polyline.
function createEncodings(_points) {
  var i = 0;

  var plat = 0;
  var plng = 0;

  var encoded_points = "";
  var encoded_levels = "";

  for(i = 0; i < _points.length; ++i) {
    var point = _points[i];
    var lat = point.lat();
    var lng = point.lng();
    var level = 3;

//    alert(lat+', '+lng);

    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 encoded_points;
  /*
  // move if moveMap is true.
  if (moveMap) {
    document.map.setCenter(
        new GLatLng(points[0].Latitude, points[0].Longitude),
        document.map.getZoom());
  } 

  document.getElementById('encodedLevels').value = encoded_levels;
  document.getElementById('encodedPolyline').value = encoded_points;

  if (document.overlay) {
    document.map.removeOverlay(document.overlay);
  }

  if (points.length > 1) {
    document.overlay = GPolyline.fromEncoded({color: "#0000FF",
                                              weight: 10,
                                              points: encoded_points,
                                              zoomFactor: 32,
                                              levels: encoded_levels,
                                              numLevels: 4
                                             });

    document.map.addOverlay(document.overlay);
  } */
}
/*
function centerMap() {
  var address = document.getElementById('txtAddress').value;

  if (address.length > 0) {
    var geocoder = new GClientGeocoder();

    geocoder.getLatLng(address,
      function(point) {
        if (!point) {
          alert('Address "' + address + '" not found');
        } else {
          document.map.setCenter(point, 13);
        }
      });
  }
}*/

// Decode an encoded polyline into a list of lat/lng tuples.
function decodeLine (encoded) {
  var len = encoded.length;
  var index = 0;
  var array = [];
  var lat = 0;
  var lng = 0;

  while (index < len) {
    var b;
    var shift = 0;
    var result = 0;
    do {
      b = encoded.charCodeAt(index++) - 63;
      result |= (b & 0x1f) << shift;
      shift += 5;
    } while (b >= 0x20);
    var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
    lat += dlat;

    shift = 0;
    result = 0;
    do {
      b = encoded.charCodeAt(index++) - 63;
      result |= (b & 0x1f) << shift;
      shift += 5;
    } while (b >= 0x20);
    var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
    lng += dlng;

//    array.push([lat * 1e-5, lng * 1e-5]);
    array.push(new GLatLng(lat * 1e-5, lng * 1e-5));
  }
/*
  for (var i=0; i<array.length; i++)
  {
      alert(array[i]);
  }
*/
  return array;
}

// Decode an encoded levels string into a list of levels.
function decodeLevels(encoded) {
  var levels = [];

  for (var pointIndex = 0; pointIndex < encoded.length; ++pointIndex) {
    var pointLevel = encoded.charCodeAt(pointIndex) - 63;
    levels.push(pointLevel);
  }

  return levels;
}

// Decode the supplied encoded polyline and levels.
function decode() {
  var encoded_points = document.getElementById('encodedPolyline').value;
  var encoded_levels = document.getElementById('encodedLevels').value;

  if (encoded_points.length==0 || encoded_levels.length==0) {
    return;
  }

  var enc_points = decodeLine(encoded_points);
  var enc_levels = decodeLevels(encoded_levels);

  if (enc_points.length==0 || enc_levels.length==0) {
    return;
  }

  if (enc_points.length != enc_levels.length) {
    alert('Point count and level count do not match');
    return;
  }

  deleteAllMarkers();
  document.getElementById('pointList').options.length = 0;
  points = [];

  for (var i = 0; i < enc_points.length; ++i) {
    createPoint(enc_points[i][0], enc_points[i][1], enc_levels[i]);
  }

  createEncodings(true);
}
