MeasureWithBearingExtension = new OpenLayers.Class(GeoMOOSE.UX.Extension, {

	/* displayDescending
	    false : 1 .. n displayed in the log table
	    true  : n .. 1 displayed in the log table
	*/
	displayDescending: true,
	


	units: {
		length: [
			{'label' : 'Feet', 'inches_per' : 12},
			{'label' : 'Yards', 'inches_per' : 36},
			{'label' : 'Chains', 'inches_per' : 792},
			{'label' : 'Miles', 'inches_per' : 63360},
			{'label' : 'Inches', 'inches_per' : 1},
			{'label' : 'Meters', 'inches_per' : 39.37}, 
			{'label' : 'Kilometers', 'inches_per' : 39370.079}
		]
	},

	titles: {
		'length' : 'Measure Length',
		'area' : 'Measure Area',
		'total' : 'Total:',
		'segment' : 'Segment:',
		'bearing' : 'Bearing:',
		'units' : 'Units:',
		'clear' : 'Clear Log'
	},

	is_area: false,

	id_ref: {},

	/* short hand function */
	id: function() {
		return OpenLayers.Util.createUniqueID('measure');
	},

	/* entries should contain a two element object with "measure" and "bearing" properties */
	entries: [],
	/* flag set after a meausre completes.  When true, the log is reset before refresh */
	reset_entries: false,
	/* iterate over the known entries */
	get_segment_total: function() {
		var sum = 0;
		for(var i = 0, len=this.entries.length; i < len; i++) {
			sum += this.entries[i].measure;
		}
		return sum;
	},

	clearLogTable: function() {
	},

	/*
	 * calculate_bearing
	 * Calculates the relative heading between point_a and point_b
	 */
	calculate_bearing: function(point_a, point_b) {
	},

	start_measure_length: function() {
		this.isArea = false;
		this.displayTitle = this.titles['length'];
		this.start_measure();
	},

	start_measure_area: function() {
		this.isArea = true;
		this.displayTitle = this.titles['area'];
		this.start_measure();
	},

	/*
	 * Clear out the tab and setup the necessary bits for display.
	 */
	start_measure: function() {
		Tabs.showTab(CONFIGURATION.show_results_in);
		var p = document.getElementById(Tabs.getTab(CONFIGURATION.show_results_in));

		/* clear out old content */
		/* this is slower than .innerHTML='' but it is more memory friendly */
		while(p.firstChild) {
			p.removeChild(p.firstChild);
		} 

		/* display a title */
		var title_div = document.createElement('div');
		title_div.className = 'measure-tool-title';
		p.appendChild(title_div);
		title_div.innerHTML = this.displayTitle;

		/* display some indicators */
		var make_divs = ['total','segment','bearing','units'];
		for(var i = 0; i < make_divs.length; i++) {
			var to_make = make_divs[i];
			var div = document.createElement('div');
			p.appendChild(div);
			var title = document.createElement('span');
			title.className = 'measure-tool-display-title';
			div.appendChild(title);
			title.innerHTML = this.titles[to_make];

			var display = document.createElement('span');
			display.className = 'measure-tool-display';
			this.id_ref[to_make] = this.id(); 
			display.id = this.id_ref[to_make];
			div.appendChild(display);
		}

		/* create the unit conversion drop down */
		var select_p = document.getElementById(this.id_ref['units']);
		var select = document.createElement('select');
		this.id_ref['units_select'] = this.id();
		select.id = this.id_ref['units_select'];
		select_p.appendChild(select);
		for(var i = 0; i < this.units.length.length; i++) {
			var opt = document.createElement('option');
			opt.setAttribute('value', i);
			select.appendChild(opt);
			opt.appendChild(document.createTextNode(this.units.length[i].label));
		}

		select.onchange = OpenLayers.Function.bind(function() {
			var sel = document.getElementById(this.id_ref['units_select']);
			this.convert_to = this.units.length[sel.selectedIndex].inches_per;
			this.update_log_table();
			this.update_measurements();
		}, this);

		/* set default units */
		this.convert_to = this.units.length[0].inches_per;

		/* create a clear button */
		var clear_div = document.createElement('div');
		p.appendChild(clear_div);
		var clear_label = document.createElement('span');
		clear_div.appendChild(clear_label);
		clear_label.innerHTML = ' '
		clear_label.className = 'measure-tool-display-title';

		var clear_button = document.createElement('button');
		clear_div.appendChild(clear_button);
		clear_button.innerHTML = this.titles['clear'];
		clear_button.onclick = OpenLayers.Function.bind(function () {
			this.clear_log();
			this.update_log_table();
			this.update_measurements();
		}, this);



		/* startup log table */
		var table = document.createElement('table');
		p.appendChild(table);
		/* create the head */
		var thead = document.createElement('thead');
		table.appendChild(thead);
		var header = document.createElement('tr');
		thead.appendChild(header);
		var elems = ['#', this.titles['segment'], this.titles['bearing']];
		for(var i = 0; i < elems.length; i++) {
			var td = document.createElement('td');
			td.className = 'measure-tool-header-cell';
			header.appendChild(td);
			td.innerHTML = elems[i];
		}

		var tbody = document.createElement('tbody');
		this.id_ref['tbody'] = this.id();
		tbody.id = this.id_ref['tbody'];
		table.appendChild(tbody);
	},

	/*
	 * format_measure
	 * Format the display output of an individual measure.
	 * This function can be overridden by someone wanting to only modify this bit.
	 */
	format_measure: function(measure) {
		/* stolen from the standard measure tool */
		var converted_measure = measure / this.convert_to;
		return commifyNumber(converted_measure.toFixed(CONFIGURATION.measure_tool.precision));
	},
	update_measurements: function () {
		var to_update = {
			'segment' : this.format_measure(this.current_measure),
			'total' : this.format_measure(this.current_total),
			'bearing' : this.current_bearing
		};

		for(var update in to_update) {
			var element = document.getElementById(this.id_ref[update]);
			element.innerHTML = to_update[update];
		}

	},

	clear_log: function() {
			this.reset_entries = false;
			this.entries = new Array();
			this.update_log_table();
	},

	show_measure: function(event) {
		if(this.reset_entries) {
			this.clear_log();

		}

		/* need to use these to prevent the disparity between the mousemove and 
			mouse click events. (Moving = one measure, then clicking on what seems the same spot
			will create a small measurement differential */
		/* needing these fundementally annoys me but it makes the app work. */
		this.current_measure = event.measure;
		this.current_bearing = this.get_bearing_from_event(event);
		this.current_total = this.current_measure + this.get_segment_total();

		this.update_measurements();
	},

	get_bearing_from_event: function(event) {
		var components = event.geometry.components;
		/* if we have two points, the bearing will be valid,
			more important if we have a length > 1 we can actually make the array refs */
		var len = components.length;
		if(len > 1) {
			return this.get_bearing(components[len-2],components[len-1]);
		}
		/* set it to nil */
		return '-';
	},

	finish_measure: function(event) {
		/* update the display */
		/* update the log */
		/* flag the stack to be reset */
		this.reset_entries = true;
	},

	update_log_table: function() {
		var tbody = document.getElementById(this.id_ref['tbody']);
		/* clear it out ... */
		while(tbody.firstChild) {
			tbody.removeChild(tbody.firstChild);
		}

		/* put all the rows in... */
		for(var i = 0, len = this.entries.length; i < len; i++) {
			var row = document.createElement('tr');
			if(this.displayDescending) {
				tbody.insertBefore(row, tbody.firstChild);
			} else {
				tbody.appendChild(row);
			}
			var infos = [(i+1)+':', this.format_measure(this.entries[i].measure), this.entries[i].bearing];

			/* this is intentionally a constant, "3" is a lot cheaper in memory than "infos.length"
				if you want to add something to infos, up the 3 to 4,5,6,100 or whatever you need */
			for(var x = 0; x < 3; x++) {
				var cell = document.createElement('td');
				row.appendChild(cell);
				cell.innerHTML = infos[x];
			}
		}
	},

	log_measure: function(event) {
		/* add the entry to the internal log */
		this.entries.push({
			'measure' : this.current_measure,
			/* set the offset to "back 1" in order to prevent logging the 
				bearing of the double click */
			'bearing' : this.current_bearing 
		});
		/* refresh the log table */
		this.update_log_table();
	},

	load: function() {
		/* unregister the old events */
		Tools['measure'].events.unregister('activate', Tools['measure'], startupMeasureLength);
		Tools['measure'].events.unregister('measuremove', Tools['measure'], measureToolLengthLog);
		Tools['measure'].events.unregister('measurepartial', Tools['measure'], measureToolPartial);
		Tools['measure'].events.unregister('measure', Tools['measure'], measureToolPartial);


		/* replace the current measure tool functionality */
		Tools['measure'].events.register('activate', this, this.start_measure_length);
		Tools['measure'].events.register('measuremove', this, this.show_measure);
		Tools['measure'].events.register('measurepartial', this, this.log_measure);
		Tools['measure'].events.register('measure', this, this.finish_measure);
	},

	get_bearing: function(point_a, point_b) {
		var bearing = '-';
		if(point_a && point_b) {
			var bearing = 'N0-0-0E';

			var rise = point_b.y - point_a.y;
			var run = point_b.x - point_a.x;
			if(rise == 0) {
				if(point_a.x > point_b.x) {
					bearing = 'Due West';
				} else {
					bearing = 'Due East';
				}
			} else if(run == 0) {
				if(point_a.y > point_b.y) {
					bearing = 'Due South';
				} else {
					bearing = 'Due North';
				}
			} else {
				var ns_quad = 'N';
				var ew_quad = 'E';
				if(rise < 0) {
					ns_quad = 'S';
				}
				if(run < 0) {
					ew_quad = 'W';
				}
				/* we've determined the quadrant, so we can make these absolute */
				rise = Math.abs(rise);
				run = Math.abs(run);
				/* convert to degrees */
				var degrees = Math.atan(run/rise) * (180/Math.PI);
				/* and to DMS ... */
				var d = parseInt(degrees);
				var t = (degrees - d) * 60;
				var m = parseInt(t);
				var s = parseInt(60 * (t-m));

				bearing = ns_quad+d+'-'+m+'-'+s+ew_quad;
			}
		}
		return bearing;
	}

});

GeoMOOSE.UX.register('MeasureWithBearingExtension');

/*
 * Some Suggested CSS
 *
[css start]

.measure-tool-title {
	font-size: 1.1em;
	font-weight: bold;
	margin-bottom: .25em;
}

.measure-tool-display-title {
	display: inline-block;
	width: 6em;
	padding-left: .2em;
	font-weight: bold;
}

.measure-tool-header-cell {
	text-decoration: underline;
}

[css end]


*/

