var map = null;
var maploaded = false;
var original_edit_point = null;

// NEW METHODS FOR GPOLYLINE CLASS

GPolyline.prototype._nextIndex = 0;
GPolyline.prototype._lastVertex = null;
GPolyline.prototype._getNextIndex = function () { return this._nextIndex; }
GPolyline.prototype._setNexIndex = function (index) { this._nextIndex = index; }
GPolyline.prototype.pushVertex = function (vertex) 
{
	// keep track of last vertex
	this._lastVertex = vertex;

	// push vertex
	this.insertVertex(this._getNextIndex(),vertex)
	this._setNexIndex(this._getNextIndex()+1);
}
GPolyline.prototype.isEmpty = function () { return (this._getNextIndex() == 0); }
GPolyline.prototype.getLastVertex = function () { return this._lastVertex; }

/*
GPolyline.prototype.pushVertex = function (vertex) { this.insertVertex(this.getVertexCount(),vertex); }
GPolyline.prototype.getLastVertex = function () { return this.getVertex(this.getVertexCount()-1); }
GPolyline.prototype.isEmpty = function () { this.getVertexCount() == 0; }
*/

// END OF NEW METHODS FOR GPOLYLINE CLASS

// TMarkerManager

function TMarkerManager(map)
{
	// map
	this._map = map;

	// markers
	this._markers = Array();
}

TMarkerManager.prototype.clearMarkers = function ()
{
	for(var i=0;i<this._markers.length;i++)
		this._map.removeOverlay(this._markers[i]);

	this._markers = Array();
}

TMarkerManager.prototype.addMarker = function (marker)
{
	// save marker index
	marker.index = this._markers.length;

	this._map.addOverlay(marker);
	this._markers.push(marker);
}

TMarkerManager.prototype.removeMarker = function (marker)
{
	this._map.removeOverlay(marker);
}

// END OF TMarkerManager

// POINT TOOLTIP CONTROL

function ToolTipOverlay() 
{
	// container element
	this._container = null;

	// map
	this._map = null;
}

ToolTipOverlay.prototype = new GOverlay();
ToolTipOverlay.prototype.initialize = function (map) 
{
	// store map reference
	this._map = map;

        // create container
        this._container = document.createElement("div");
	this._container.setAttribute('id','point_tooltip');
	$(this._container).hide();

        map.getContainer().appendChild(this._container);
        return this._container;
}

ToolTipOverlay.prototype.getDefaultPosition = function() { return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0, 0)); }
ToolTipOverlay.prototype.remove = function () { $(this._container).remove(); }
ToolTipOverlay.prototype.copy = function () { return new ToolTipOverlay(); }
ToolTipOverlay.prototype.redraw = function (force) { this.hide(); }

ToolTipOverlay.prototype.display = function (html,marker)
{
	this._container.innerHTML = html;

	// calculate position
	var point = this._map.getCurrentMapType().getProjection().fromLatLngToPixel(this._map.fromContainerPixelToLatLng(new GPoint(0,0),true),this._map.getZoom());
	var offset = this._map.getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(),this._map.getZoom());
	var anchor = marker.getIcon().iconAnchor;
	var width = marker.getIcon().iconSize.width + 5;
	var height = 0; //this._container.clientHeight;

	// position tooltip
	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(this._container);

	// show
	$(this._container).show();
}

ToolTipOverlay.prototype.hide = function () { $(this._container).hide(); }

// END OF TOOLTIP CONTROL

// POINT MANAGER CLASS
function TripManager(map,opts)
{
	// tooltip control
	this._tooltip = null;

	// loading
	this._loading = true;

	// marker manager
	this._mmanager = null;
	this._dmmanager = null;

	// map pointer
	this._map = map;

	// polylines array
	this._polylines = Array();

	// data markers
	this._data_markers = Array();

	// waiting coordinates marker
	this._waiting_marker = null;

	// start/end markers
	this._start_marker = this._end_marker = null;

	// recording?
	this._inprogress = opts.inprogress;

	// is owner?
	this._owner = opts.owner;

	// is iphone?
	this._is_iphone = opts.is_iphone;

	// tripid/code
	this._tripid = opts.tripid;

	// pointid
	this._pointid = opts.pointid;

	// last point
	this._last_updated_at = null;

	// downloading??
	this._downloading = false;

	// points array
	this._path_points = Array();

	// for listeners
	var me = this;

	// info window
	this._infowindow = this._map.getInfoWindow();

	// selected point, for distance calc
	this._selected_point = null;
	this._selected_slice = null;

	// OBJECT CONSTRUCTOR

        // center map, in default location
	this._map.setCenter(new GLatLng(TripManager.DEFAULT_LAT,TripManager.DEFAULT_LNG),TripManager.DEFAULT_ZOOM);

	var a = new GPolyline();
	this._map.addOverlay(a);

	// setup info window controller events
	GEvent.addListener(this._map,"infowindowopen",function () { me._abortDistanceCalculation(false); me._infoWindowController() });
	GEvent.addListener(this._map,"infowindowclose",function () { me._removeSelectedSlice() });
	GEvent.addListener(this._map,"click",function (overlay,latlng,overlaylatlng) { if(!overlay) me._abortDistanceCalculation(true) });

	// setup trip refresh events
	GEvent.addListener(this._map,"moveend",function () { if(me._shouldRefresh(false)) me._refreshRoute(); });
	GEvent.addListener(this._map,"zoomend",function () { me._abortDistanceCalculation(true); me._refreshRoute(); });

	// bind map events
	if(this._owner && !this._is_iphone) GEvent.addListener(this._map,"dblclick",function (overlay,latlng) { me._dblClickHandler(overlay,latlng); });

	if(!this._is_iphone) 
	{
		// add tooltip control
		this._tooltip = new ToolTipOverlay();
		this._map.addOverlay(this._tooltip);

		// add street view control
		map.addControl(new TControlStreetView());

		// add data points toggle
                map.addControl(new TControlButton({title: "Hide data points", text: "Data Points", width: 80, active: true, callback: function (ctl) {
                        ctl.toggle();

                        if(ctl.isActive())
                        {
				me._dmmanager.enabled = true;
				for(var j=0;j<me._data_markers.length;j++) if(me._data_markers[j]) me._dmmanager.addMarker(me._data_markers[j]);
                                ctl.changeTitle("Hide data points");
                        }
                        else
                        {
				me._dmmanager.enabled = false;
				me._dmmanager.clearMarkers();
                                ctl.changeTitle("Show data points");
                        }
                }}),new GControlPosition(G_ANCHOR_TOP_RIGHT,new GSize(308,7)));
	}

	// initialize trip
	this._initialize();

	// END OF OBJECT CONSTRUCTOR
}

// CONSTANTS

TripManager.MAX_DISTANCE 	= 2.00;	// miles
TripManager.DEFAULT_LAT 	= 37;
TripManager.DEFAULT_LNG 	= -95;
TripManager.DEFAULT_ZOOM	= 3;
TripManager.INITIAL_ZOOM 	= 14;
TripManager.POINT_ZOOM		= 14;
TripManager.UPDATE_INTERVAL 	= 5000; // miliseconds
TripManager.LOADING_TEMPLATE	= "Loading...";

// END OF CONSTANTS

// PRIVATE METHODS

TripManager.prototype._initialize = function ()
{
	// fetch trip bounds
        var url = "/trips.php?trip="+this._tripid+(this._is_iphone?"":"&point="+this._pointid)+"&action=bounds";

        var me = this;
        GDownloadUrl(url, function(data, responseCode) {

		var bounds = eval(data);

		if(bounds.length)
		{
			// zoom to entire trip
			me._centerWholeTrip(bounds);
			me._refreshRoute();
		}
		else 
		{
			me._showWaitingMessage();
			if(me._loading) me._finishLoading();
		}

		if(me._inprogress) window.setInterval(function () { me._updateRoute(); },TripManager.UPDATE_INTERVAL);
        });
}

TripManager.prototype._infoWindowController = function ()
{
	if(this._infowindow.loadURL)
	{
		var me = this;
		GDownloadUrl(this._infowindow.loadURL, function(data, responseCode) {
			me._map.updateInfoWindow([new GInfoWindowTab("label",data)]);
		});

		this._infowindow.loadURL = null;
	}
}

TripManager.prototype._dblClickHandler = function (overlay,latlng)
{
	if(!this._path_points.length) alert("This trips doesn't have any point yet");
	else
	{
		var	point;
		var	micon;
		var	marker;

		// get nearest point
		point = this._getNearestPoint(latlng);
		if(!point) return;

		this._placeDragMarker(point);
	}
}

TripManager.prototype._shouldRefresh = function (auto)
{
	// if we are selecting points to calculate distance, do not refresh points
	if(this._map.getInfoWindow().isHidden() && !this._selected_slice && !this._selected_point) return true;

	return false;
}

TripManager.prototype.handleDistanceCalculation = function (marker)
{
	if(this._selected_point)
	{
		var	idx1, idx2, ptArray, accIndex, actualIndex;

		// find correct indexes order
		if(marker.index < this._selected_point.index) { idx1 = marker.index; idx2 = this._selected_point.index; }	
		else { idx1 = this._selected_point.index; idx2 = marker.index; }	

		// locate initial polyline
		var accIndex = 0;
		for(var i=0;i<this._polylines.length;i++)
			if((accIndex + this._polylines[i].getVertexCount() - 1) >= idx1) break;
			else accIndex += this._polylines[i].getVertexCount();
		actualIndex = idx1 - accIndex;
		accIndex = idx1;

		// build highlighted polyline
		ptArray = Array();
		while(accIndex <= idx2)
		{
			// get vertex
			ptArray.push(this._polylines[i].getVertex(actualIndex));

			// update reference indexes
			accIndex++;
			actualIndex++;

			// check if current polyline if over, and if so, move to next one
			if(actualIndex >= this._polylines[i].getVertexCount()) 
			{
				i++; 
				actualIndex = 0;
			}
		}

		// close any info window that might be opened
		this._map.closeInfoWindow();
	
		// create slice polyline
		this._selected_slice = new GPolyline(ptArray,"#ff0000",null,null,{geodesic:true});

		// add to map
		this._map.addOverlay(this._selected_slice);

		// show distance information
		var distance = Math.abs(marker.distance - this._selected_point.distance);
		var time = Math.abs(marker.epoch - this._selected_point.epoch);
		this._map.openInfoWindowHtml(marker.getLatLng(),"<b>Total distance: </b>"+this._formatDistance(distance)+"<br/><b>Total time: </b>"+this._formatTime(time)+"<br/><b>Average speed: </b>"+this._calculateSpeed(distance,time));

		// de-select points
		this._abortDistanceCalculation(false);
	}
	else
	{
		this._abortDistanceCalculation(true);

		// selecting first point
		this._selected_point = marker;
		marker.setImage("/images/trip_point_sel.gif");	
	}
}

TripManager.prototype._removeSelectedSlice = function ()
{
	if(this._selected_slice)
	{
		this._map.removeOverlay(this._selected_slice);
		this._selected_slice = null;
	}
}

TripManager.prototype._abortDistanceCalculation = function (full)
{
	if(this._selected_point) this._selected_point.setImage("/images/trip_point"+((this._map.getZoom() < 17)?"_hidden":"")+".gif");
	this._selected_point = null;

	if(full && this._selected_slice) this._map.closeInfoWindow();
}

TripManager.prototype._placeDragMarker = function (point)
{
	var 	micon;
	var	latlng = point.point;

	// remove old marker, if exists
	this._removeDragMarker();

	// create drag marker icons
	micon = new GIcon(G_DEFAULT_ICON);
	micon.dragCrossImage = "/images/transparent.png";
	micon.dragCrossSize = new GSize(5,5);
	micon.dragCrossAnchor = new GPoint(3,3);

	// place drag marker
	this._drag_marker = new GMarker(latlng,{icon: micon, draggable: true});
	this._drag_marker.pointid = null;
	this._drag_marker.pointref = point;

	// attach event listeners
	var me = this;
	GEvent.addListener(this._drag_marker,"dragstart",function () { this.closeInfoWindow(); me._placeDragCross();  });

	var tim = 0;
	GEvent.addListener(this._drag_marker,"drag",function (ll) 
	{ 
		var tim2 = new Date();
		if (tim2.getTime() > tim)
		{
			me._updateDragCross(ll); 

			tim = tim2.getTime() + 50;
		}
	});

	GEvent.addListener(this._drag_marker,"dragend",function () { me._removeDragCross(); me._openPointInfoWindow(this,TripManager.LOADING_TEMPLATE); });

	GEvent.addListener(this._drag_marker,"click",function () { me._openPointInfoWindow(this,TripManager.LOADING_TEMPLATE); });

	// bind info window
	this._map.addOverlay(this._drag_marker);
	me._openPointInfoWindow(this._drag_marker,TripManager.LOADING_TEMPLATE);
}

TripManager.prototype._openPointInfoWindow = function (marker,html)
{
	var url = "/trips.php?action=view-point&trip="+this._tripid+(marker.pointid?"&pointid="+marker.pointid:"")+(marker.pointref?"&pointref="+marker.pointref.id:"");
	if(this._is_iphone)
	{
		showProgress();
		$("point_details").innerHTML = "Loading...";
		switchView("point");
                var me = this;
                GDownloadUrl(url, function(data, responseCode) {
			hideProgress();
                        $("point_details").innerHTML = data;
                });
	}
	else
	{
		this._infowindow.loadURL = url;
		marker.openInfoWindowHtml(html,{noCloseOnClick:marker.point?true:false});
	}
}

TripManager.prototype._placeDragCross = function ()
{
	var	cicon;

	cicon = new GIcon();
	cicon.image = "/images/drag_cross.png";
	cicon.iconSize = new GSize(16,16);
	cicon.shadow = "";
	cicon.iconAnchor = new GPoint(8,9);

	this._drag_cross = new GMarker(this._drag_marker.getLatLng(),{icon: cicon});
	this._map.addOverlay(this._drag_cross);
}

TripManager.prototype._removeDragCross = function ()
{
	if(this._drag_cross)
	{
		// place drag marker at current drag cross position
		this._drag_marker.setLatLng(this._drag_cross.getLatLng());

		this._map.removeOverlay(this._drag_cross);
		this._drag_cross = null;
	}
}

TripManager.prototype._updateDragCross = function (ll)
{
	var point = this._getNearestPoint(ll);

	if(point) 
	{
		this._drag_marker.pointref = point;
		this._drag_cross.setLatLng(point.point);
	}
}

TripManager.prototype._removeDragMarker = function ()
{
	if(this._drag_marker)
	{
		GEvent.clearListeners(this._drag_marker);

		this._drag_marker.closeInfoWindow();
		this._map.removeOverlay(this._drag_marker);
		this._drag_marker = null;
	}
}

TripManager.prototype._getNearestPoint = function (latlng)
{
	var	distance = -1;
	var	point = null;

	for(var i=0;i<this._path_points.length;i++)
	{
		var d = latlng.distanceFrom(this._path_points[i].point);
		if((distance == -1) || (d < distance))
		{
			distance = d;
			point = this._path_points[i];
		}
	}

	return point;
}

TripManager.prototype._buildIcon = function (image,type)
{
	var icon = new GIcon();

	if(type == 0)
        {
                icon.iconSize = new GSize(12, 20);
                icon.iconAnchor = new GPoint(6, 20);
                icon.image = image;
                icon.shadow = "/images/mm_20_shadow.png";
                icon.shadowSize = new GSize(22, 20);
                icon.infoWindowAnchor = new GPoint(5, 1);
        }
	else if(type == 1)
	{
		icon.iconSize = new GSize(26, 26);
		icon.iconAnchor = new GPoint(13, 13);
		icon.image = image;
		icon.shadow = "";
		icon.infoWindowAnchor = new GPoint(13, 13);
	}
	else if(type == 2)
	{
		icon.iconSize = new GSize(10,10);
		icon.iconAnchor = new GPoint(5, 5);
                icon.image = image;
                icon.shadow = "";
                icon.infoWindowAnchor = new GPoint(5, 5);
	}

	return icon;
}

TripManager.prototype._addStartMarker = function (point)
{
	if(this._start_marker) this._map.removeOverlay(this._start_marker);

	this._start_marker = new GMarker(point.point, {icon: this._buildIcon("/images/mm_20_green.png",0), zIndexProcess: function () { return 101; }});
	if(!this._is_iphone) 
	{
		var me = this;
		GEvent.addListener(this._start_marker,"mouseover",function () { me._tooltip.display("<b>Trip start</b> @ "+point.created_at,this); });
		GEvent.addListener(this._start_marker,"mouseout",function () { me._tooltip.hide(); });
	}

	this._map.addOverlay(this._start_marker);
}

TripManager.prototype._addEndMarker = function (point)
{
	if(this._end_marker) this._map.removeOverlay(this._end_marker);

	this._end_marker = new GMarker(point.point, {icon: this._buildIcon("/images/mm_20_red.png",0), zIndexProcess: function () { return 101; }});
	if(!this._is_iphone)
	{
		var html;

		if(this._inprogress) html = "<b>Current position</b> @ "+point.created_at+"<br/>";
		else html = "<b>Trip end</b> @ "+point.created_at+"<br/>";
		html += "<b>Distance:</b> "+this._formatDistance(point.distance);

		// update distance
		$("total_distance").innerHTML = this._formatDistance(point.distance);

		var me = this;
                GEvent.addListener(this._end_marker,"mouseover",function () { me._tooltip.display(html,this); });
                GEvent.addListener(this._end_marker,"mouseout",function () { me._tooltip.hide(); });
	}

	this._map.addOverlay(this._end_marker);
}

TripManager.prototype._showWaitingMessage = function ()
{
	var msg;

	this._waiting_marker = new GMarker(new GLatLng(TripManager.DEFAULT_LAT,TripManager.DEFAULT_LNG), {icon: this._buildIcon("/images/mm_20_green.png",0)});
	this._map.addOverlay(this._waiting_marker);

	if(this._inprogress) 
	{
		if(this._owner) msg = "<b>Waiting for coordinates....</b><p align='center'>"+(this._is_iphone?"<a href='trapster://start'>":"")+
					"You must start Trapster.<br>Otherwise no coordinates will be<br/>recorded."+(this._is_iphone?"</a>":"")+"</p>";
		else msg = "<b>Waiting for coordinates....</b>";
	}
	else msg = "<b>This trips has no coordinates</b>";

	this._waiting_marker.bindInfoWindowHtml(msg);
	this._waiting_marker.openInfoWindowHtml(msg);
}

TripManager.prototype._removeWaitingMessage = function ()
{
	this._waiting_marker.closeInfoWindow();
	this._map.removeOverlay(this._waiting_marker);
	this._waiting_marker = null;
}

TripManager.prototype._processPoints = function (points)
{
	// clear path points
	this._clearPolylines();

	if(points)
	{
		if(points.points.length)
		{
			// draw path
			this._addPoints(points.points);

			// keep track of last point
			this._last_updated_at = points.last_updated_at;
		}

		// plot data points
		// we plot it before path points in order to have path points OVER data points
		this._plotData(points.data_points);
	}

	if(this._loading) this._finishLoading();
}

TripManager.prototype._newPolyline = function ()
{
	var pl = new GPolyline();
	this._map.addOverlay(pl);
	this._polylines.push(pl);
	
	return pl;
}

TripManager.prototype._getLastPoint = function ()
{
	var	cpl = null;
	var	lp = null;

	if(this._polylines.length) cpl = this._polylines[this._polylines.length-1];
	if(cpl && !cpl.isEmpty()) lp = cpl.getLastVertex();
	else if(!cpl) cpl = this._newPolyline();

	return { cpl: cpl, lp: lp };
}

TripManager.prototype._clearPolylines = function ()
{
	for(var i=0;i<this._polylines.length;i++)
	{
		this._map.removeOverlay(this._polylines[i]);
		this._polylines[i] = null;
	}

	this._polylines = Array();
	if(!this._is_iphone) 
	{
		this._abortDistanceCalculation(true);
		this._mmanager.clearMarkers();
		this._path_points = Array();
	}

	if(this._start_marker) { this._map.removeOverlay(this._start_marker); this._start_marker = null; }
	if(this._end_marker) { this._map.removeOverlay(this._end_marker); this._end_marker = null; }
}

TripManager.prototype._addPoints = function (points)
{
	var	lp = null;
	var	cpl = null;
	var	last = null;

	// get last polyline and last vertex
	last = this._getLastPoint();
	lp = last.lp;
	cpl = last.cpl;

	for(var i=0;i<points.length;i++)
	{
		if(lp)
		{
			// check if should split
			if(points[i].state == "S") cpl = this._newPolyline();
		}

		// keep track of point
		if(!this._is_iphone) this._path_points.push(points[i]);

		// add marker to manager
		if(this._mmanager) this._mmanager.addMarker(this._createPointMarker(points[i]));

		lp = points[i].point;
		cpl.pushVertex(points[i].point);

		if(points[i].position == "F") this._addStartMarker(points[i]);
		else if(points[i].position == "L") this._addEndMarker(points[i]);
	}

	return;
}

TripManager.prototype._formatDistance = function (meters)
{
        // miles
        var miles = meters * 0.000621371192;
        if(miles < 0.1) miles = Math.round(meters * 3.2808399)+" ft";
        else miles = miles.toFixed(2)+" mi";

	return miles;
}

TripManager.prototype._formatTime = function (secs)
{
	var m, h, d;

	m = h = d = 0;
	if(secs > 3600*24) { d = Math.ceil(secs / (3600*24)); secs = secs % (3600*24); }
	if(secs > 3600) { h = Math.ceil(secs / 3600); secs = secs % 3600; }
	if(secs > 60) { m = Math.ceil(secs / 60); secs = secs % 60; }

	if(d) return d+" days, "+h+" hours, "+m+" minutes and "+secs+" seconds"; 
	else if(h) return h+" hours, "+m+" minutes and "+secs+" seconds"; 
	else if(m) return m+" minutes and "+secs+" seconds"; 
	else return secs+" seconds"; 
}

TripManager.prototype._calculateSpeed = function (meters,secs)
{
	var miles = meters * 0.000621371192;
	var hours = secs / 3600;
	var speed = miles/hours;

	return (speed.toFixed(0)+" mi/h");
}

TripManager.prototype._createPointMarker = function (point)
{
        var     marker;
	var	html;

	// build info window contents
	html = "";
	if(uname.toLowerCase() == "barros" || uname.toLowerCase() == "pt" || uname.toLowerCase() == "theauthor")	
		html = "<b>Point ID:</b> "+point.id+"<br/>";
	html += "<b>Date & Time:</b> "+point.created_at+"<br/>";
	html += "<b>Distance:</b> "+this._formatDistance(point.distance);
                
        marker = new GMarker(point.point,{icon: this._buildIcon("/images/trip_point"+((this._map.getZoom() < 17)?"_hidden":"")+".gif",2)});
        marker.pointid = point.id;
	marker.distance = point.distance;
	marker.epoch = point.epoch;
                        
        // event handlers       
	var me = this;
        GEvent.addListener(marker,"mouseover",function () 
	{ 
		var new_html = html;

		if(!me._selected_point || me._selected_point.index != this.index)
		{
			if(me._selected_point) new_html += "<br/><br/><em>Click to calculate distance <b>to</b> this point</em>";
			else new_html += "<br/><br/><em>Click to calculate distance <b>from</b> this point to another<em>";
		}
		else new_html += "<br/><br/><em>Click on <b>another</b> point to calculate the distance, or click this point to cancel";

		marker.setImage("/images/trip_point_sel.gif");
		if(!me._is_iphone) me._tooltip.display(new_html,marker);
	});
        GEvent.addListener(marker,"mouseout",function () 
	{ 
		if(!me._selected_point || me._selected_point.index != this.index) marker.setImage("/images/trip_point"+((me._map.getZoom() < 17)?"_hidden":"")+".gif");
		if(!me._is_iphone) me._tooltip.hide();
	});
	GEvent.addListener(marker,"click",function ()
	{
		if(!me._selected_point || me._selected_point.index != this.index) me.handleDistanceCalculation(this);
		else me._abortDistanceCalculation();

		// trigger mouseover event in order to refresh tooltip
		GEvent.trigger(this,"mouseover");
	});
	
	// bind info window
	//marker.bindInfoWindowHtml(html);
                        
        return marker;
}

TripManager.prototype._centerWholeTrip = function (bounds)
{
	if(bounds.length == 2)
	{
		// zoom to point
		this._map.setCenter(new GLatLng(bounds[0],bounds[1]),TripManager.POINT_ZOOM);
	}
	else
	{
		// zoom to bound
		var bound = new GLatLngBounds(new GLatLng(bounds[0],bounds[2]),new GLatLng(bounds[1],bounds[3]));

		this._map.setCenter(bound.getCenter(),this._map.getBoundsZoomLevel(bound));
	}
}

TripManager.prototype._finishLoading = function ()
{
	this._loading = false;
	$("loading").hide();

	// change message to refresh
	//$("loading_text").innerHTML = "Refreshing trip...";
}

TripManager.prototype._showLoading = function ()
{
	$("loading").show();
	this._loading = true;
}

TripManager.prototype._plotData = function (points)
{
	// remove deleted points
	for(var j=0;j<this._data_markers.length;j++)
	{
		var	found = false;

		if(!this._data_markers[j]) continue;

		for(var i=0;i<points.length;i++)
			if(this._data_markers[j].pointid == points[i].id) 
				if(this._data_markers[j].type == points[i].type)
					if(this._data_markers[j].cks == points[i].cks)
						points[i].skip = found = true;

		// remove from map
		if(!found)
		{
			if(this._dmmanager.enabled) this._dmmanager.removeMarker(this._data_markers[j]);
			this._data_markers[j] = null;
		}
	}
	
	for(var j=0;j<points.length;j++)
	{
		// didn't change??
		if(points[j].skip) continue;

		this._createDataMarker(points[j]);
	}
}

TripManager.prototype._createDataMarker = function (point)
{
	var type = 1;
	var marker;

	// add marker
	switch(point.type)
	{
		case 1: marker = new GMarker(point.point, {icon:this._buildIcon("/images/text_tag.png",1), zIndexProcess: function () { return 100; }}); break;
		case 2: marker = new GMarker(point.point, {icon:this._buildIcon("/images/image_tag.png",1), zIndexProcess: function () { return 100; }}); break;
		case 256: 
			if(!this._is_iphone) marker = new GMarker(point.point, {icon:this._buildIcon("/images/video_tag.png",1), zIndexProcess: function () { return 100; }});
			else return;
			//else marker = new GMarker(point.point, {icon:this._buildIcon("/images/image_tag.png",1)});
		break;
		case 4: 
			if(!this._is_iphone) marker = new GMarker(point.point, {icon:this._buildIcon("/images/sound_tag.png",1), zIndexProcess: function () { return 100; }});
			else return;
		break;
		default: return; break;
	}

	var html = "<b>Name: </b>"+point.name+"<br/>"+(point.summary?"<b>Summary: </b>"+point.summary+"<br/>":"")+"<b>Date & Time: </b>"+point.created_at+"<br/><br/><em>Click for full details!</em>";

	// place marker
	marker.pointid = point.id;
	marker.type = point.type;
	marker.cks = point.cks;
	this._data_markers.push(marker);
	if(this._dmmanager.enabled) this._dmmanager.addMarker(marker);

	// setup event handler
	var me = this;
	GEvent.addListener(marker,"mouseover",function ()
	{
		if(me._map.getInfoWindow().isHidden()) { me._tooltip.display(html,this); }
	});
	GEvent.addListener(marker,"mouseout",function () { me._tooltip.hide(); });
	GEvent.addListener(marker,"click",function () { me._openPointInfoWindow(this,TripManager.LOADING_TEMPLATE); });

	// open bubble if it's a point url
	if(this._pointid && point.id == this._pointid) window.setTimeout(function () { GEvent.trigger(marker,"click"); },0);
}

TripManager.prototype._getLocationInfo = function ()
{
	// get map bounds
	var bounds = this._map.getBounds();

	// get map center
	var center = bounds.getCenter();

	// get radius, in miles
	var radius = (center.distanceFrom(new GLatLng(center.lat(),bounds.getNorthEast().lng())) * 1.20) / 1609.344;

	return { center: center, radius: radius, zoom: this._map.getZoom() };
}

TripManager.prototype._drawCircularArea = function (point,rad)
{
        var ptArray = Array();
        var lat = parseFloat(point.lat());
        var lng = parseFloat(point.lng());

        var c1 = "#003ff3";
        var c2 = "#0000ff";

	rad = rad / 61;
        for (var d = 10; d < 380; d += 10) {

            var x = lat + (Math.cos((d/180)*Math.PI) * rad);
            var y = lng + (Math.sin((d/180)*Math.PI) * rad);
            var newPt = new GLatLng(x, y);
            ptArray.push(newPt);
        }

        this._map.addOverlay(new GPolygon(ptArray, c1, 5, 1, c2, .2));
}

TripManager.prototype._updateRoute = function ()
{
	if(!this._shouldRefresh(true)) return;

        var url = "/trips.php?trip="+this._tripid+"&action=lastpoint";

        if(this._downloading) return;
        this._downloading = true;

        var me = this;
        GDownloadUrl(url, function(data, responseCode) {
                me._downloading = false;

		var p = eval(data);
		if(p && p.point)
		{
			if(p.created_at != me._last_updated_at) 
			{
				if(me._waiting_marker)
				{
					me._removeWaitingMessage();
					me._map.setCenter(p.point,TripManager.INITIAL_ZOOM);
				}
				else if(!me._map.getBounds().containsLatLng(p.point)) me._map.setCenter(p.point);
				else me._refreshRoute();
			}
		}
        });
}

TripManager.prototype._refreshRoute = function ()
{
	var loc = this._getLocationInfo();	
	var url = "/trips.php?trip="+this._tripid+"&action=update&loc[lat]="+loc.center.lat()+"&loc[lng]="+loc.center.lng()+"&loc[radius]="+loc.radius+"&loc[zoom]="+loc.zoom;

	if(this._downloading) return;
	this._downloading = true;

	// show loading message
	//this._showLoading();

	// create marker manager
	if(!this._is_iphone && !this._mmanager) this._mmanager = new TMarkerManager(this._map);
	if(!this._dmmanager) { this._dmmanager = new TMarkerManager(this._map); this._dmmanager.enabled = true; }

	var me = this;
        GDownloadUrl(url, function(data, responseCode) {
		// process points
		var points = eval(data);
		me._processPoints(points);
		me._downloading = false;
        });
}

// END OF PRIVATE METHOD

function load(iphone)
{

	is_iphone = iphone;
	if (GBrowserIsCompatible()) 
	{
		if(iphone) map = new GMap2(document.getElementById("trapmap",{size: new GSize(320,370)}));
		else 
		{
			map = new GMap2(document.getElementById("trapmap"));
			map.addControl(new GLargeMapControl3D());
			map.addControl(new GMapTypeControl());
		}
		map.disableDoubleClickZoom();

		// initialize trip
		window.setTimeout(function ()
		{
			tripmanager = new TripManager(map,{owner: owner, is_iphone: iphone, inprogress: inprogress, tripid: tripid, pointid: pointid });
		},0);
	}
	maploaded = true;
}

function refreshMap() { map.checkResize(); }

function savePoint(f,add)
{
	if($("point_frame").contentWindow.document.body.innerHTML)
	{
		if($("point_frame").contentWindow.document.body.innerHTML == "SUCCESS")
		{
			tripmanager._refreshRoute();

			alert("Trip point successfully "+(add?"added to the trip":"saved"));
			if(!add) map.closeInfoWindow();
			else tripmanager._removeDragMarker();
		}
		else if($("point_frame").contentWindow.document.body.innerHTML == "DEL_SUCCESS")
		{
			tripmanager._refreshRoute();
			alert("Trip point successfully deleted");
			map.closeInfoWindow();
		}
		else alert($("point_frame").contentWindow.document.body.innerHTML);
	};
}

function removeImage()
{
	document.trip_point_frm.image_del.value = "Y";
	$("point_image").remove();

	return redrawInfoWindow();
}

function tellFriends(f)
{
	if(f.emails.value == "") alert("Enter at least one email address");
	else
	{
                new Ajax.Request('trips.php', {method:'post', postBody:$(f).serialize(), evalScripts:true,
                        onComplete:function(transport)
			{
			    if(200 == transport.status)
			    {
				if(transport.responseText == "SUCCESS")
				{
					alert("Trip successfully sent to your friend(s)");
					$('emails').value = "";
				}
				else alert(transport.responseText);
			    }
			    else alert("Unexpected error: "+transport.status);
                        }
                });

	}
	return false;
}

function showEditPoint()
{
	// save  current point details
	original_edit_point = $('edit_point').innerHTML;

	// show edit view
	$('view_point').hide();
	$('edit_point').show();

	return redrawInfoWindow();
}

function cancelEditPoint()
{
	// show view
	$('view_point').show();
	$('edit_point').hide();

	// restore edit view
	$('edit_point').innerHTML = original_edit_point;

	return redrawInfoWindow();
}

function redrawInfoWindow()
{
	map.updateInfoWindow(map.getInfoWindow().getTabs());

	return false;
}

