/** package control */
BRdCJS_Package =
{	version: '1.1',
	lastupdate: 'June 2008',
	gmap_specification: 'v2.117 17th June 2008'
}

/** List Manipulation Functions */
ListFunctions = 
{	search:
		function(needle,haystack)
		{	for (var i=0;i<haystack.length;i++)
				if (haystack[i]==needle)
					return i;
			return -1;
		},
	rsearch:
		function(needle,haystack,endpt)
		{	if (typeof endpt=='undefined')
				endpt = haystack.length;
			for (var i=endpt-1;i>=0;--i)
				if (haystack[i]==needle)
					return i;
			return -1;
		},
	add:
		function(link,array)			
		{	if (ListFunctions.search(link,array)!=-1)
				return false;	//already in list
			array.push(link);
			return true;
		},
	remove:
		function(link,array)
		{	var loc = ListFunctions.search(link,array);
			if (loc>-1)
			{	if (loc==0)
					array.shift();
				else if (loc==array.length-1)
					array.pop();
				else
					return array.slice(0,loc).concat( array.slice(loc+1) );
			}
			return array;
		}
}

/** Conversion Functions */
ConversionFunctions =
{	mileInMeters: 1609.344,
	mileInYards: 1760,
	mileInFeet: 5280,
	yardInMeters: 0.9144,
	yardInFeet: 3,
	feetInMeters: 0.3048,
	kilometerInMeters: 1000,
	
	metersToMiles:
		function(meters)
		{	return (meters/1609.344);
		},
	metersToYards:
		function(meters)
		{	return (meters/0.9144);
		},
	metersToKilometers:
		function(meters)
		{	return (meters/1000.0);
		},
	distanceImperial:
		function(meters)
		{	if (meters>=BRdCConv.mileInMeters/5)
				return (meters/BRdCConv.mileInMeters).toFixed(2) + 'mi';
			else
				return (meters/BRdCConv.feetInMeters).toFixed(0) + 'ft';
		},
	distanceMetric:
		function(meters)
		{	if (meters>=1000)
				return (meters/1000).toFixed(2) + 'km';
			else if (meters<1)
				return (meters).toFixed(1) + 'm';
			else
				return (meters).toFixed(0) + 'm';
		}
}


/** BRdC_Marker 
	--	ptid	int			*ID number for retrieval from the database
	--	coord	GLatLng		*Coordinates of this Marker
	
*/
function BRdCMarker(ptcoord,ptID)
{	this.coord = ptcoord;
	this.ptid = (typeof ptID!='undefined') ? ptID : null;
}
BRdCMarker.prototype.GMarker = function()
{	if (typeof this.gmarker=='undefined')
	{	if ((typeof this.poi=='undefined') || (this.poi==0))
			this.gmarker = new GMarker( this.coord, {clickable:true, icon:{image:"img/circle13marker.png", iconSize: new GSize(13,13), iconAnchor: new GPoint(6,6)} } );
	}
	return this.gmarker;
}

/** BRdC_Route
	--	rtid		int				*ID number for retrieval from the database
	--	rtname		string			*Route Name
	--	rtperm		string			*Permission flag string
	--	rtownid		int				*Route Owner's ID number in database
	--	rtowner		string			*Route Owner's name
	--	rtdsc		string			*Route Description
	--	rtbox		GLatLngBounds	*Box that encompasses the route
	--	marks		array			*array of marked points that have info for the route
	--	startinfo	string			*Optional Instruction for the beginning of the route
	--	steps		array			*array of step data that keep the info for the steps

	--	distance	float			*length of route in meters

	--	inDisplays	array			*array of displays that show the route
	--	dirtyFlag	boolean			*Route has been changed
*/

function BRdCRoute(rtdata)
{	this.altered = false;
	this.inDisplays=new Array();
	if (typeof rtdata=='undefined')
	{	this.distance= 0.0;
		this.steps	= new Array();
		this.rtname = "Untitled Route";
		this.routeDescr = '';
		this.permission = '';
	}	else
	{	//load it from the route Data Obj see BRdC_loadRoute.php for a description
		var rtparse = rtdata.split('\n');
		var markcnt = 0;
		for (var ln in rtparse)
		{	var line = rtparse[ln];
			var cmd = line.split(":");
			switch (cmd[0])
			{	case 'RTBGN':
					this.steps = new Array();
					if (cmd.length==1)
						this.editsess = cmd[1];
					break;
				case 'RTI':
					this.rtid = parseInt(cmd[1]);
					this.permission = cmd[2];
					this.rtname = (cmd.length>4) ? cmd.slice(3).join(':') : cmd[3];
					break;
				case 'RTO':
					this.rtownid = parseInt(cmd[1]);
					this.rtowner = (cmd.length>3) ? cmd.slice(2).join(':') : cmd[2];
					break;
				case 'RTT':
					this.created = new Date(parseInt(cmd[1])*1000);
					this.lastsave= new Date(parseInt(cmd[2])*1000);
					break;
				case 'RTD':
					this.marks = new Array(parseInt(cmd[1]));
					this.rtdsc = (cmd.length>3) ? cmd.slice(2).join(':') : cmd[2];
					break;
				case 'RTB':
					this.rtbox = new GLatLngBounds(new GLatLng(parseFloat(cmd[3]),parseFloat(cmd[2])),new GLatLng(parseFloat(cmd[1]),parseFloat(cmd[4])) );
					break;
				case 'RTS':
					this.steps = new Array(cmd[1]);
					this.distance = parseFloat(cmd[2]);
					this.startinfo = (cmd.length>4) ? cmd.slice(3).join(':') : cmd[3];
					break;
				case 'MRK':
					cmd.shift();
					this.marks[markcnt] = new BRdCMarker(new GLatLng(parseFloat(cmd[1]),parseFloat(cmd[2])),parseInt(cmd[0]));
					if (cmd.length>3)
					{	this.marks[markcnt].setPOI( parseInt(cmd[3]) );
						this.marks[markcnt].setName(cmd[4]);
						this.marks[markcnt].setInfo( (cmd.length>6) ? cmd.slice(5).join(':') : cmd[5]);
					}
					markcnt++;
					break;
				case 'STP':
					cmd.shift();
					var mk_ptA, mk_ptB;
					var ptAid = parseInt(cmd[2]);
					var ptBid = parseInt(cmd[3]);
					for (mk_ptA = markcnt-1;mk_ptA>=0;--mk_ptA)
						if (this.marks[mk_ptA].ptid == ptAid)
							break;
					for (mk_ptB = markcnt-1;mk_ptB>=0;--mk_ptB)
						if (this.marks[mk_ptB].ptid == ptBid)
							break;
					this.steps[cmd[0]] = new BRdCRoute_Step(this, this.marks[mk_ptA], this.marks[mk_ptB], parseFloat(cmd[1]), (cmd.length>7) ? cmd.slice(6).join(':') : cmd[6]);
					this.steps[cmd[0]].setEncoded( cmd[4], cmd[5] );
					break;
				case 'RTEND':
					return this;
				default:
					//bad.
			}	//end switch
		}	//end for
	}
}
BRdCRoute.prototype.linkDisplay = function(display)
{	if (ListFunctions.add(display, this.inDisplays))
	{	for (var step in this.steps)
		{	this.steps[step].addToDisplay( display );
		}
		for (var mrk in this.marks)
		{	display.addMark( this.marks[mrk] );
		}
	}
}

/**	BRdCRoute_Step
	--	route		BRdCRoute			*The route that this step is a part of
	--	A			BRdCMarker			*Marker representing the start of this step
	--	B			BRdCMarker			*Marker representing the end of this step
	--	distance	float				*The distance of this step (in meters)
	--	instruct	string				*Optional Instruction for this step
	--	polyline	GPolyline			*Polyline for the step
*/

function BRdCRoute_Step( myRoute, mrkA, mrkB, dist, instr )
{	this.route = myRoute;
	this.A = mrkA;
	this.B = mrkB;
	this.distance = dist;
	this.instruct = instr;
	this.polyline = null;
}
BRdCRoute_Step.prototype.setEncoded = function( encline, enclvls )
{	this.polyline = new GPolyline.fromEncoded(	{	zoomFactor: 2,
													numLevels: 18,
													points: encline,
													levels: enclvls,
													color: "#3300AA",
													weight: 3,
													opacity: 0.8
												}	);
}
BRdCRoute_Step.prototype.addToDisplay = function( display )
{	display.map.addOverlay( this.polyline );
}
BRdCRoute_Step.prototype.removeFromDisplay = function( display )
{	display.map.removeOverlay( this.polyline );
}



/**	RouteDisplay
	--	map			GMap2			*The google maps object for this display
	--	markerbox	MarkerManager	*The Marker Manager for the GMap
*/
function RouteDisplay(map)
{	if (typeof map=='object')
	{	this.map = map;
		this.centerUSA();
		this.map.savePosition();
		this.map.enableScrollWheelZoom();
		new GKeyboardHandler(this.map);
		this.map.addControl( new GSmallMapControl() );
		this.map.removeMapType( G_SATELLITE_MAP );
		this.map.addControl( new GMapTypeControl() );
		this.map.addControl( new GScaleControl() );
		//I think we still prefer the open source MarkerManager to google's GMarkerManager 
		//if only because it has the stated capability to REMOVE markers once added.
		//it requires a seperate script to be loaded of course:
		//<script src="http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/src/markermanager.js" >
		this.markerbox = new MarkerManager( this.map, {trackMarkers:true, borderPadding:40} );

	}
}
RouteDisplay.prototype.centerUSA = function()
{	var initialPosSW = new GLatLng(10.9027, -107.4);
	var initialPosNE = new GLatLng(67.1527, -85.6);
	var initialBounds = new GLatLngBounds(initialPosSW,initialPosNE);
	this.map.setCenter( initialBounds.getCenter(), this.map.getBoundsZoomLevel(initialBounds) );
}
RouteDisplay.prototype.centerRoute = function(route)
{	this.map.setCenter( route.rtbox.getCenter(), this.map.getBoundsZoomLevel(route.rtbox) );
}
RouteDisplay.prototype.displayRoute = function(route)
{	route.linkDisplay( this );
}
RouteDisplay.prototype.addMark = function( mark )
{	this.map.addOverlay( mark.GMarker() );
}

