function TControlDirections(opts)
{
	// save options
	this._opts = opts;

	// default properties
	this._active = false;

	// loading?
	this._loading = false;

	// show traps?
	this._show_traps = false;

	// ajax request handler
	this._ajax_request = null;

}
TControlDirections.prototype = new GControl();

// Constants
TControlDirections.BTN_WIDTH = 75;
TControlDirections.BTN_TEXT = "Directions";
TControlDirections.BTN_SELECTED_STYLE = 'color: black; border-style: solid; border-color: rgb(52, 86, 132) rgb(108, 157, 223) rgb(255, 255, 255) rgb(255, 255, 255); border-width: 1px; font-size: 12px; font-weight: bold;'+
					' width: '+(TControlDirections.WIDTH-2)+'px;';
TControlDirections.BTN_NOT_SELECTED_STYLE = 'color: black; border-style: solid; border-color: white rgb(176, 176, 176) rgb(176, 176, 176) white; border-width: 1px; font-size: 12px;'+
						' width: '+(TControlDirections.WIDTH-2)+'px;';
TControlDirections.RIGHT_OFFSET = 0;
TControlDirections.TOP_OFFSET = 7;

// Initialize control
TControlDirections.prototype.initialize = function (map)
{
        // store map reference
        this._map = map;

	// for listeners
	var me = this;

	// create main container
	this._container = new Element('div', {
		style: "width:385px;"
	});

        // create button
        this._button_container = new Element('div', {
		title: "Get Directions", 
		style: 'border: 1px solid black; position: absolute; background-color: white; text-align: center; cursor: pointer; width: '+TControlDirections.BTN_WIDTH+"px;" 
	}).insert((this._button_element = new Element('div', { style: TControlDirections.BTN_NOT_SELECTED_STYLE } ).update(TControlDirections.BTN_TEXT)));

	// create input form
	this._input_form_container = new Element('div', {
		style: "border-style: solid; border-color: black; border-width: 1px; width: 235px; position:absolute; background-color: white; top: 15px; height: 120px; z-index: -1; text-align: center; padding-top:10px;"
	});
	this._input_form_container.insert('<table align="center" style="margin-left:auto; margin-right: auto;"><tr><td width="20px" align="center" valign="middle" style="padding:1px;vertical-align:middle"><div style="position:relative;width:16px;height:16px;overflow:hidden"><img src="http://maps.google.com/intl/en_ALL/mapfiles/dlimgs2.png" style="position: absolute; left: -32px; top: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; -webkit-user-drag: none; width: 233px; height: 34px;" /></div></td><td style="padding:1px;"><input type="text" size="25" id="tcd_point_a" /></td><td rowspan="2" valign="middle" width="20px" align="center" style="padding:1px;vertical-align:middle"><div style="position:relative;width:18px;height:18px;overflow:hidden"><img src="http://maps.google.com/intl/en_ALL/mapfiles/dlimgs2.png" style="position: absolute; left: -210px; top: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; -webkit-user-drag: none; width: 233px; height: 34px; cursor: pointer;" id="tcd_toggle_button" /></div></td></tr><tr><td align="center" valign="middle" style="padding:1px;vertical-align:middle"><div style="position:relative;width:16px;height:16px;overflow:hidden"><img src="http://maps.google.com/intl/en_ALL/mapfiles/dlimgs2.png" style="position: absolute; left: -160px; top: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; -webkit-user-drag: none; width: 233px; height: 34px;" /></div></td><td style="padding:1px;"><input type="text" size="25" id="tcd_point_b" /></td></tr><tr><td style="padding:1px;"colspan="3" align="center"><input type="checkbox" id="tcd_show_traps" checked /> Show traps along the route</td><tr><td colspan="3" align="center" style="padding:1px;padding-top:5px;"><input type="button" id="tcd_search_button" value="Get Directions" style="width:100px; height:20px; font-size:11px;" /></td></tr><tr id="tcd_loading_row"><td width="20px" align="center" valign="middle" style="padding:1px;vertical-align:middle"><img src="images/loading.gif" /></td><td id="tcd_loading" style="color:red; text-align:left; padding:1px; vertical-align:middle; font-size:10px;" colspan="2" align="left" valign="middle"></td></tr></table>').hide();

	// create display panel
	this._display_panel = new Element('div', {
                style: "border-style: solid; border-color: black; border-width: 1px; width: 373px; height: 466px; overflow-y: scroll; position:absolute; background-color: white; top: 15px; z-index: -1;"
        });
	this._display_panel.hide();

	// add to map	
        $(map.getContainer()).insert(this._container.insert(this._button_container).insert(this._input_form_container).insert(this._display_panel));

	// finish initialization
	window.setTimeout(function () { me._initialize_step2(); },0);

	return this._container;
}

TControlDirections.prototype._initialize_step2 = function ()
{
	var me = this;

	this._input_form_point_a = this._input_form_container.select("#tcd_point_a").first();
	this._input_form_point_b = this._input_form_container.select("#tcd_point_b").first();
	this._input_form_toggle_button = this._input_form_container.select("#tcd_toggle_button").first();
	this._input_form_search_button = this._input_form_container.select("#tcd_search_button").first();
	this._input_form_show_traps = this._input_form_container.select("#tcd_show_traps").first();
	this._input_form_loading_row = this._input_form_container.select("#tcd_loading_row").first();
	this._input_form_loading = this._input_form_container.select("#tcd_loading").first();
	this._input_form_loading_row.hide();
	this._input_form_container.hide();

	// GDirections object
	this._gdirections = new GDirections(this._map,this._display_panel);

	// setup event listeners
	GEvent.addListener(this._map,"tcd_cmd",function () { me._handleCMD(arguments); });
	GEvent.addDomListener(this._button_element,"click",function () {
		me._toggleActive();
	});

	GEvent.addDomListener(this._input_form_toggle_button,"click",function () {
		if(me._loading) return; // if loading state, ignore

		var aux = me._input_form_point_a.value;

		me._input_form_point_a.value = me._input_form_point_b.value
		me._input_form_point_b.value = aux;
	});

	GEvent.addListener(this._gdirections,"error",function () {
		alert("One or more addresses could not be computed from the query.");
		me._normalState();
	});
	GEvent.addListener(this._gdirections,"load",function () {
		me._requestTraps();
/*
		if(me._show_traps) me._requestTraps();
		else
		{
			me._normalState();
			me._input_form_container.hide();
			me._display_panel.show();
		}
*/
	});

	GEvent.addDomListener(this._input_form_search_button,"click",function () {
		var from = me._trim(me._input_form_point_a.value);
		var to = me._trim(me._input_form_point_b.value);
		me._show_traps = me._input_form_show_traps.checked;

		if(!from || !to) alert("Please enter both points");
		else
		{
			me._loadingState("Retrieving route...");
			me._gdirections.load("from:"+from+" to:"+to,{ locale: "en_US" });
		}
	});
	
	// check URL hash, if set to #directions, we should display directions form
	if(window.location.hash == "#directions") {
		this._toggleActive();
	}
}

// default position
TControlDirections.prototype.getDefaultPosition = function() { return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(TControlDirections.RIGHT_OFFSET,TControlDirections.TOP_OFFSET)); }
TControlDirections.prototype.printable = function () { return true; }
TControlDirections.prototype.selectable = function () { return false; }


// toggle active/inactive
TControlDirections.prototype._toggleActive = function ()
{
	if(this._active) this._deactivate();
	else this._activate();
}

TControlDirections.prototype._activate = function () 
{ 
	this._button_element.writeAttribute('style',TControlDirections.BTN_SELECTED_STYLE); 
	this._button_container.style.borderBottom = "solid white 1px";
	this._active = true; 

	// show input form
	this._input_form_container.show();
	this._container.style.height = "147px";
}
TControlDirections.prototype._deactivate = function () 
{
	// remove current direction
	this._normalState();
	this._gdirections.clear();
	this._display_panel.hide();

	// clear fields
	//this._input_form_point_a.value = "";
	//this._input_form_point_b.value = "";
	//this._input_form_show_traps.checked = false;
	this._display_panel.innerHTML = "";

	// clear any opened info window
	this._map.closeInfoWindow();

	// update button
	this._button_element.writeAttribute('style',TControlDirections.BTN_NOT_SELECTED_STYLE); 
	this._button_container.style.borderBottom = "solid black 1px";
	this._active = false; 

	// hide input form
	this._input_form_container.hide();
	this._container.style.height = "0px";
}

TControlDirections.prototype._loadingState = function (msg)
{
	if(!this._loading)
	{
		this._input_form_point_a.writeAttribute("disabled","disabled");
		this._input_form_point_b.writeAttribute("disabled","disabled");
		this._input_form_search_button.writeAttribute("disabled","disabled");
		this._input_form_show_traps.writeAttribute("disabled","disabled");
		this._input_form_loading_row.show();
		this._loading = true;
	}
	this._input_form_loading.update(msg);
}
TControlDirections.prototype._normalState = function ()
{
	// abort any pending request
	if(this._ajax_request) 
	{
		this._ajax_request.abort();
		this._ajax_request = null;
	}

        this._input_form_point_a.writeAttribute("disabled",false);
        this._input_form_point_b.writeAttribute("disabled",false);
        this._input_form_search_button.writeAttribute("disabled",false);
	this._input_form_show_traps.writeAttribute("disabled",false);
	this._input_form_loading_row.hide();
	this._input_form_loading.update();
        this._loading = false;
}

TControlDirections.prototype._trim = function (str)
{
   return str.replace(/^\s*|\s*$/g,"");
}

TControlDirections.prototype._requestTraps = function ()
{
	var polyline = this._gdirections.getPolyline();
	var details = { routes: Array() };
	var lastVertex = 0;

	this._loadingState("Compiling route information...");
	for(var i=0;i<this._gdirections.getNumRoutes();i++)
	{
		var	route = this._gdirections.getRoute(i);
		var 	r = { steps: Array() };

		// add start waypoint
		r.steps.push({ vertexes: [ { lat: route.getStep(0).getLatLng().lat(), lng: route.getStep(0).getLatLng().lng() } ], description: route.getStartGeocode().address, distance: 0, duration: 0 });

		for(var j=0;j<route.getNumSteps();j++)
		{
			var	step = route.getStep(j);
			var	s = { vertexes: Array() };

			// add vertexes
			for(var k=lastVertex;k<=step.getPolylineIndex();k++)
			{
				var v = polyline.getVertex(k);
				s.vertexes.push({lat: v.lat(), lng: v.lng() });
				lastVertex = k;
			}
			s.description = step.getDescriptionHtml();
			s.distance = step.getDistance();
			s.duration = step.getDuration();

			r.steps.push(s);
		}

		// add end waypoint
		s = { vertexes: Array() };
		for(var k=lastVertex;k<polyline.getVertexCount();k++)
		{
			var v = polyline.getVertex(k);
			s.vertexes.push({lat: v.lat(), lng: v.lng() });
		}
		s.description = route.getEndGeocode().address;
		s.distance = 0;
		s.duration = 0;
		r.steps.push(s);

		// route distance and duration
		r.distance = route.getDistance();
		r.duration = route.getDuration();

		details.routes.push(r);
	}

	// full distance and duration
	details.distance = this._gdirections.getDistance();
	details.duration = this._gdirections.getDuration();
	details.copyright = this._gdirections.getCopyrightsHtml();

	// get route bounds
	bounds = polyline.getBounds();
	details.bounds = { SW: { lat: bounds.getSouthWest().lat(), lng: bounds.getSouthWest().lng() }, NE: { lat: bounds.getNorthEast().lat(), lng: bounds.getNorthEast().lng() } };

	// convert to json
	json_data = Object.toJSON(details);

	// send to server
	var me = this;
	this._loadingState("Uploading route information...");
	this._ajax_request = new Ajax.Updater(this._display_panel,"rl/directions.php?traps="+(this._show_traps?"Y":"N"),{
		method: 'post',
		parameters: { route: json_data },
		onFailure: function () { alert("There was an error retrieving traps along your route, please try again"); me._normalState(); },
		onSuccess: function () {
			me._normalState();
                        me._input_form_container.hide();
                        me._display_panel.show();
			me._container.style.height = "492px";
		},
		onLoaded: function () { me._loadingState("Receiving response..."); }
	});
}

TControlDirections.prototype._handleCMD = function (args)
{
	switch(args[0])
	{
		case "blowup":
			var lat = args[1];
			var lng = args[2];

			this._map.showMapBlowup(new GLatLng(lat,lng));
		break;
	}
}
