var map = null;
var directions = {};
var use_marker_clustering = true;

// Display a retrieved route diagram.
function drawroute(id) {
	segments = directions[id];
	//alert(segments.lines.length);
	for(var k in segments.lines) {
		// segments.lines[k].color = '#00693E';
		segments.lines[k].opacity = 0.5;
		map.addOverlay(segments.lines[k]); // draw route segment
		//console.log(segments.lines[k]);
	}
	// draw marker for each stop (geocode) in the route
	if(use_marker_clustering) {
		var markerCluster = new MarkerClusterer(map, segments.markers, {maxZoom:14, gridSize:60});
	} else {
		for (var i=0; i<segments.markers.length; i++) {
	    	map.addOverlay(segments.markers[i]);	
		}
	}
}

// We draw the route diagram in segments of 25 >= n >= 2 waypoints.
// This function will find the start and end indices (inclusive) of the next continuous segment.
// Continuous is defined as consisting of a set of valid points that are all within Metro Vancouver.
// This is needed because invalid waypoints can't be included in the directions request to GMap,
// and the set of stop coordinates in TransitDB is incomplete and unreliable.
function next_continuous_segment(arr, start) {
  var l = arr.length;
  if(!start) {
    start = 0;
  } else if(start >= l-1 || start < 0) {
    // no more segments if start pos is invalid or pointing at the last element
    return false;
  }
  var started = false; // whether the first valid coordinate has been found yet
  var start_inx = start; // start segment search from this index
  var length = 0;
  var i = start;
  for(; i<l; i++) {
    // max number of waypoints allowed is 25.
    if(!coordinate_in_range(arr[i][0], arr[i][1]) || length >= 25) {
      if(started) {
        break;
      } else {
        continue;
      }
    } else {
      if(!started) {
        if(arr[i+1] && !coordinate_in_range(arr[i+1][0], arr[i+1][1])) {
          // if start 
          continue;
        }
        started = true;
        start_inx = i;
      }
      length++;
    }
  }
  // index range of next continuous segment; inclusive
  // if there are no more valid coordinates ahead of the start index, return false
  return started ? [start_inx, i-1] : false;
}

function prepare_marker(index, latlng_obj) {
  var pos_disp = index+1;
	var newIcon = MapIconMaker.createLabeledMarkerIcon({ label: pos_disp+"", primaryColor: "#00ff00"});
	var marker = new GMarker(latlng_obj, {icon:newIcon, title:stopinf[index].name});
	marker.bindInfoWindow(document.getElementById('s'+index));
	return marker;
}

// A separate method is needed to draw stops that are adjacent to bad stops on both sides.
// This is because the Directions method won't accept single coordinates (of course).
// This function looks ahead of the given segment and processes these isolated stops until
// it reaches a new segment or the end. Then it returns an updated segment.
function process_isolated_stops(id, stops, seg) {
  while(seg[1] - seg[0] + 1 == 1) {
    var marker = prepare_marker(seg[0], new GLatLng(stops[seg[0]][0],stops[seg[0]][1]));
		directions[id].markers.push(marker);
    seg = next_continuous_segment(stops, seg[1]);
  }
  return seg;
}

// Retrieve and process a complete route diagram.
// Uses a recursive event callback method, which serializes loading and divides the work into appropriately-sized chunks.
// Includes a lot of handling for bad stop coordinate data, to ensure that as much useful data is shown as possible.
function loadroute(stops, gdir, id) {
	if(!directions[id]) {
	  directions[id] = {lines:[], distances:[], markers:[]};
  }
    GEvent.addListener(gdir, "load", function() {
    	directions[id].lines.push(gdir.getPolyline()); // TODO: handle case of failed or broken requests
    	directions[id].distances.push(gdir.getDistance());
		  var geocodes = gdir.getNumGeocodes();
  		// draw marker for each stop in the given route segment
  		var pos = seg[0];
  		for (var i=0; i<geocodes; i++) {
  			var marker = prepare_marker(pos, gdir.getMarker(i).getLatLng());
  			// check for redundant markers at the endpoints of each segment
  			// first marker in each segment is redundant with last marker in last segment
  			// unless the 2 points don't form a continuous line (i.e. when a bad stop is between them)
  			if(i!=seg[0] || (i==seg[0] && seg[0]!=last_seg[1])) {
      		directions[id].markers.push(marker);
      	}
  			pos++;
  		}

      // prepare to recurse, or finish up and draw the diagram.
  		last_seg = seg;
  		seg = next_continuous_segment(stops, seg[1]);
  		if(seg) {
  		  seg = process_isolated_stops(id, stops, seg);
  		}
  		if(seg) {
        gdir.loadFromWaypoints(stops.slice(seg[0], seg[1]+1),{getPolyline:true});
      } else {
        drawroute(id); // draw entire route at once, when the entire route is loaded
      }
    });
    
  // bootstrap!
  var seg = next_continuous_segment(stops, 0);
  var last_seg = [-1,-1];
  if(seg) {
	  seg = process_isolated_stops(id, stops, seg);
	}
  if(seg) {
    gdir.loadFromWaypoints(stops.slice(seg[0], seg[1]+1),{getPolyline:true});
  } else {
    // something has gone horribly wrong if we never got a continous segment
  }
}

function center(stops) {
  // find the first 2 valid route endpoints: i.e.: not (0,0)
	for(var i=0; i<stops.length; i++) {
	  if(stops[i][0]!=0 && stops[i][1]!=0) {
	    var validpt1_inx = i;
	    break;
	  }
	}
	for(var i=stops.length-1; i>0; i--) {
	  if(stops[i][0]!=0 && stops[i][1]!=0) {
	    var validpt2_inx = i;
	    break;
	  }
	}
	// make a rectangle, find the midpoint, center map on it
	var lat = (stops[validpt2_inx][0] - stops[validpt1_inx][0])/2 + stops[validpt1_inx][0];
	var lng = (stops[validpt2_inx][1] - stops[validpt1_inx][1])/2 + stops[validpt1_inx][1];
	if(coordinate_in_range(lat, lng)) {
	  map.setCenter(new GLatLng(lat, lng), 12);
  } else {
    map.setCenter(new GLatLng(49.2623, -123.076828), 12);
  }
}

function initialize() {
	if (GBrowserIsCompatible()) {
		map = new GMap2(document.getElementById("route_map"));

	  map.setUIToDefault();
	  //map.disableScrollWheelZoom();

    var dir0 = new GDirections();
    center(tstops);
    loadroute(tstops, dir0, 'dir0');
	}
}