/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*
 * GeoMOOSE Site Configuration
 */

var CONFIGURATION = {
	'links_bar_html' : "",
	'mapserver_url' : "",
	'mapfile_root' : "",
	'fractional_zoom' : true,
	'scales' : [1,2,4,8,16,32,64,128,256,500,1000,5000],
	'max_extent' : [189783.560000,4816309.330000,761653.524114,5472346.500000],
	'initial_extent' : [410438.542057,5125011.551363637,540998.542057,5163644.278636363],
	'projection' : "EPSG:26915",
	'ground_units' : 'm',
	'coordinate_display' : {
		xy: true,	/* Ground Units */
		latlon: true,	/* Longitude and Latitude */
		usng: true	/* U.S. National Grid */
	},
	'tabs' : {
		'Catalog' : 'catalog-tab',
		'Search' : 'search-tab',
		'Services' : 'service-tab',
		'Results' : 'results-tab'
	},
	'default_tab' : 'Catalog',
	'catalog_name' : 'Catalog',
	'show_service_settings_in' : 'Services',
	'show_results_in' : 'Results',
	'zoomto' : {
/*		
		'Jump To:' : {
			'Dakota County' : [521238.614537864,4924218.86673578,473921.947801381,4974430.36885032],
			'Parcel Data' : [497205.409367,4923984.423582,477595.805945,4941970.52988],
			'Full State of MN' : [189783.560000,4816309.330000,761653.524114,5472346.500000]
		}
*/
	},
	'jumpto_scales' : {
		'1:12000' : 12000,
		'1:2400' : 2400,
		'1:1200' : 1200,
		'1:120' : 120
	},
	'startup_service' : false,
	'layer_controls' : {
		'up' : {on: true, tip: 'Move %LAYER% up on the stack'},
		'down' : {on: true, tip: 'Move %LAYER% down on the stack'},
		'fade' : {on: true, change_percent: 10, tip: 'Fade %LAYER%'},
		'unfade' : {on: true, change_percent: 10, tip: 'Unfade %LAYER%'},
		'refresh' : {on: false, tip: 'Manually refresh %LAYER%'},
		'cycle' : {on: false, tip: 'Refresh %LAYER% every 10 seconds', seconds: 10},
		'legend' : {on: true, tip: 'Show legend for %LAYER%'}
	},
	'measure_tool' : {
		'target_tab' : 'Results',
		'style' : {
			"Point" : {
				pointRadius: 4,
				graphicName: "square",
				fillColor: "white",
				fillOpacity: 1,
				strokeWidth: 1,
				strokeOpacity: 1,
				strokeColor: "#333333"
			},
			"Line" : {
				strokeWidth: 2,
				strokeColor: "#FF0000"
			},
			"Polygon" : {
				strokeWidth: 2,
				strokeColor: "#FF0000",
				fillColor: "#00FF00",
				fillOpacity: .5
			}
		},
		'line_units' : 'ft',
		'area_units' : 'acre'
	}
};
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

function GeomooseCatalog(parentDivId, olMap) {
	var elementCounter = 0;
	var MyCatalog = false;
	var MySelf = this;

	var MapbookLoaded = false;

	function getCatalogElementId() {
		elementCounter++;
		return 'catalog-'+elementCounter;
	}

	function toggleGroup() {
		/*var g = document.getElementById(groupElementId);*/
		var grpList = this.nextSibling;
		var className = new String(grpList.className);
		if(className.match('catalog-group-collapsed')) {
			grpList.className = className.replace('collapsed','expanded');
		} else {
			grpList.className = className.replace('expanded','collapsed');
		}
	}


	function renderGroup(groupElementId, group) {
		var p = document.getElementById(groupElementId);
		var ul = document.createElement('ul');
		ul.className = 'catalog';

		if(p.tagName == 'UL' && group.getAttribute('title')) {
			var li = document.createElement('li');
			p.appendChild(li);
			li.appendChild(document.createTextNode(group.getAttribute('title')));
			li.className = 'catalog-group';
			li.onclick = toggleGroup;
			li = null;
			if(parseBoolean(group.getAttribute('expand'))) {
				ul.className += ' catalog-group-expanded';
			} else {
				ul.className += ' catalog-group-collapsed';
			}
		} else {
			ul.className += ' catalog-group-expanded';
		}
		ul.id = getCatalogElementId();
		p.appendChild(ul);

		for(var i = 0; i < group.childNodes.length; i++) {
			var tagName = group.childNodes[i].tagName;
			if(tagName) {
				if(tagName == 'group') {
					renderGroup(ul.id, group.childNodes[i]);
				} else if(tagName == 'layer') {
					renderLayer(ul.id, group.childNodes[i]);
				}
			}
		}

		ul = null;
		p = null;
	}

	function iterateThroughLayers(pathString, fn) {
		var services = MyCatalog.getElementsByTagName('map-source');
		var paths = new String(pathString).split(':');

		for(var i = 0; i < services.length; i++) {
			var root = services[i].getAttribute('name');
			var layers = services[i].getElementsByTagName('layer');
			for(var l = 0; l < layers.length; l++) {
				var layerName = layers[l].getAttribute('name')
				for(var p = 0; p < paths.length; p++) {
					if(root+'/'+layerName == paths[p]) {
						var mapLayer = Map.getLayersByName(root)[0];
						if(mapLayer) {
							fn(mapLayer, paths[p]);
						}
					}
				}

			}
		}
	
	}

	this.refreshLayer = function(pathString) {
		iterateThroughLayers(pathString, function(mapLayer) {
			/* This forces the image to reload */
			mapLayer.params['GEOMOOSE_REFRESH'] = (new Date()).getTime();
			mapLayer.redraw();
		});
	}

	this.fadeLayer = function(pathString) {
		iterateThroughLayers(pathString, function(mapLayer) {
			if(mapLayer.opacity == null) { mapLayer.opacity = 1; }
			var newOpac = mapLayer.opacity - CONFIGURATION.layer_controls.fade.change_percent/100;
			if(newOpac < 0) { newOpac = 0; }
			mapLayer.setOpacity(newOpac);
		});
	}


	this.unfadeLayer = function(pathString) {
		iterateThroughLayers(pathString, function(mapLayer) {
			if(mapLayer.opacity == null) { mapLayer.opacity = 1; }
			var newOpac = mapLayer.opacity + CONFIGURATION.layer_controls.unfade.change_percent/100;
			if(newOpac > 1) { newOpac = 1; }
			mapLayer.setOpacity(newOpac);
		});
	}

	this.upLayer = function(pathString) {
		iterateThroughLayers(pathString, function(mapLayer) {
			mapLayer.map.raiseLayer(mapLayer, 1);
		});
	}

	this.downLayer = function(pathString) {
		iterateThroughLayers(pathString, function(mapLayer) {
			mapLayer.map.raiseLayer(mapLayer, -1);
		});
	}

	this.cycleLayer = function(pathString) {
	}


	var legendImages = new Array();

	function updateLegendURLs(pathString) {
		iterateThroughLayers(pathString, function(mapLayer,layerPath) {
			var legendURL = false;
			if(!legendImages[layerPath]) {
				return false;	// nothing to do, no image available
			}
			var lname = layerPath.split('/').pop();
			if(mapLayer instanceof OpenLayers.Layer.MapServer) {
				legendURL = mapLayer.getURL(Map.getExtent()).replace('mode=map','mode=legend');

				/* specify THIS layer */
				legendURL = legendURL.replace(/layers=[\+\_\%a-zA-Z0-9\/]*\&/, 'layers='+lname+'&');
			}
			if(mapLayer instanceof OpenLayers.Layer.WMS) {
				legendURL = mapLayer.getURL(Map.getExtent()).replace('REQUEST=GetMap', 'REQUEST=GetLegendGraphic');
				legendURL += '&LAYER=' + lname;
				legendURL += '&SCALE=' + Map.getScale();
			}
			if(legendURL) {
				document.getElementById(legendImages[layerPath]).setAttribute('src',legendURL);
			}
		});
	}

	this.legendLayer = function(pathString) {
		var id = this.id;
		var parentControl = this;
		var legendParent = document.getElementById(id+'-legend');

		if(legendParent.className.indexOf('Visible') >= 0) {
			legendParent.className = legendParent.className.replace('Visible','Hidden');
			while(legendParent.childNodes[0]) {
				legendParent.removeChild(legendParent.childNodes[0]);
			}
			iterateThroughLayers(pathString, function(mapLayer, layerPath) {
				legendImages[layerPath] = false;
			});
			parentControl.className = parentControl.className.replace('sprite-control-legend-visible', '');
		} else {
			legendParent.className = legendParent.className.replace('Hidden','Visible');
			if(parentControl.className.indexOf('sprite-control-legend-visible') < 0) {
				parentControl.className += ' sprite-control-legend-visible'; 
			}
			iterateThroughLayers(pathString, function(mapLayer, layerPath) {
				if(!legendImages[layerPath]) {
					var legendImg = document.createElement('img');
					legendImg.className = 'catalog-legend-image';
					legendImg.id = 'catalog-legend-'+getCatalogElementId();
					legendImages[layerPath] = legendImg.id;
					legendParent.appendChild(legendImg);
					legendImg.setAttribute('src','images/blank.gif'); /* Default to prevent display issues */
					legendImg = null;
				}
			});

			updateLegendURLs(pathString);
		}
	}


	this.setLayerVisibility = function(pathString, visibility) {
		var services = MyCatalog.getElementsByTagName('map-source');
		var paths = new String(pathString).split(':');

		var foundSomething = false;

		for(var i = 0; i < services.length; i++) {
			var root = services[i].getAttribute('name');
			var layers = services[i].getElementsByTagName('layer');
			var updateRequired = false;
			for(var l = 0; l < layers.length; l++) {
				var layerName = layers[l].getAttribute('name')
				for(var p = 0; p < paths.length; p++) {
					if(root+'/'+layerName == paths[p]) {
						foundSomething = true;
						var v = 'false';
						if(visibility) {
							v = 'true';
						}
						if(parseBoolean(visibility) != parseBoolean(layers[l].getAttribute('visible'), false)) {
							layers[l].setAttribute('visible', v);
							updateRequired = true;
						}
					}
				}
			}

			if(updateRequired) {
				var layersList = new Array();
				for(var l = 0; l < layers.length; l++) {
					if(parseBoolean(layers[l].getAttribute('visible'))) {
						layersList.push(layers[l].getAttribute('name'));
					}
				}
			
				var mapLayer = Map.getLayersByName(root)[0];
				if(mapLayer instanceof OpenLayers.Layer.MapServer) {
					mapLayer.params['layers'] = layersList.join(' ');
				} else if (mapLayer instanceof OpenLayers.Layer.WMS) {
					mapLayer.params['LAYERS'] = layersList.join(',');
				}
				if(layersList.length == 0) {
					mapLayer.setVisibility(false);
				} else {
					mapLayer.setVisibility(true);
				}
				if(MapbookLoaded) {
					mapLayer.redraw();
				}

			}
			

		}
		return foundSomething;
	}

	function multiSelectLayer() {
		MySelf.setLayerVisibility(this.value, this.checked);
	}

	function singleSelectLayer() {
		var p = this.parentNode.parentNode;
		var inputs = p.getElementsByTagName('input');
		for(var i = 0; i < inputs.length; i++) {
			if(inputs[i].name == this.name) {
				inputs[i].checked = false;
			}
			MySelf.setLayerVisibility(inputs[i].value, false);
		}
		this.checked = true;
		MySelf.setLayerVisibility(this.value, true);
	}

	function inScale(minscale, maxscale) {
		var scale = olMap.getScale();
		if(!maxscale && !minscale) { return true; }
		if(!maxscale && scale >= minscale) { return true; }
		if(!minscale && scale <= maxscale) { return true; }
		return (minscale <= scale && scale <= maxscale);
	}

	function renderLayer(groupElementId, layer) {
		var p = document.getElementById(groupElementId);
		var li = document.createElement('li');
		li.className = 'catalog-layer';
		p.appendChild(li);
		var cbox = document.createElement('input');
		cbox.id = 'catalog-'+layer.getAttribute('src');

		if(parseBoolean(layer.parentNode.getAttribute('multiple'),true)) {
			cbox.name = layer.parentNode.getAttribute('name');
			cbox.type = 'checkbox';
			cbox.value = layer.getAttribute('src');
			cbox.onclick = multiSelectLayer;
		} else {
			cbox.type = 'radio';
			cbox.value = layer.getAttribute('src');
			cbox.onclick = singleSelectLayer;
		}
		li.appendChild(cbox);

		var layerTitle = document.createElement('span');
		layerTitle.className = 'catalog-layer-title';
		li.appendChild(layerTitle);

		layerTitle.appendChild(document.createTextNode(layer.getAttribute('title')));

		if(layer.getAttribute('tip')) {
			layerTitle.title = layer.getAttribute('tip');
		}

		if(layer.getAttribute('minscale')) {
			layerTitle.minscale = parseFloat(layer.getAttribute('minscale'));
		}

		if(layer.getAttribute('maxscale')) {
			layerTitle.maxscale = parseFloat(layer.getAttribute('maxscale'));
		}

		if(inScale(layerTitle.minscale, layerTitle.maxscale)) {
			layerTitle.className += ' catalog-inscale';
		} else {
			layerTitle.className += ' catalog-outscale';
		}
		
		var controlSpan = document.createElement('span');
		controlSpan.className = 'catalog-controls-container';
		li.appendChild(controlSpan);
		
		var controlsId = getCatalogElementId();

		for(var control_name in CONFIGURATION.layer_controls) {
			var layerSwitch = CONFIGURATION.layer_controls[control_name].on;
			if(layer.getAttribute(control_name)) {
				layerSwitch = parseBoolean(layer.getAttribute(control_name));
			}
			if(layerSwitch) {
				var toolDiv = document.createElement('div');
				toolDiv.className = 'sprite-control sprite-control-'+control_name;
				toolDiv.value = layer.getAttribute('src');
				toolDiv.controlFn = eval("MySelf."+control_name+"Layer");
				toolDiv.id = controlsId;
				toolDiv.onclick = function () {
					this.controlFn(this.value);
				}

				var tooltip = CONFIGURATION.layer_controls[control_name].tip;
				if(tooltip) {
					tooltip = tooltip.replace('%LAYER%', layer.getAttribute('title'));
					toolDiv.title = tooltip;
				}
				controlSpan.appendChild(toolDiv);
			}
		}
		var legend = document.createElement('div');
		legend.className = 'catalog-legend Hidden';
		legend.id = controlsId+'-legend';
		// Leave the legend "blank" for the time being.
		//legend.src = 'images/blank.gif';
		li.appendChild(legend);

		/* check to see if the layer is "on" */
		if(parseBoolean(layer.getAttribute('status'))) {
			cbox.checked = true;
			cbox.onclick();
		}

		cbox = null;
		li = null;
		p = null;
	}

	function onRefreshMap () {
		var p = document.getElementById(parentDivId);
		var span = p.getElementsByTagName('span');
		for(var i = 0; i < span.length; i++) {
			if(span[i].className.indexOf('catalog-layer-title') >= 0) {
				var layerTitle = span[i];
				if(inScale(layerTitle.minscale, layerTitle.maxscale)) {
					layerTitle.className = layerTitle.className.replace('catalog-outscale', 'catalog-inscale');
				} else {
					layerTitle.className = layerTitle.className.replace('catalog-inscale', 'catalog-outscale');
				}
				layerTitle = null;
			}
		}

		for(var pathString in legendImages) {
			updateLegendURLs(pathString);
		}
	}

	function toggleTool(obj, tool) {
		var visClassName = 'sprite-control-'+tool+'-selected';

		/* so it's current visible ... so remove it */
		if(obj.className.indexOf(visClassName) >= 0) {
			obj.className = obj.className.replace(' '+visClassName, '');
			obj.className = obj.className.replace(visClassName, '');
		} else {
			obj.className = obj.className + ' ' + visClassName;
			onSelectTool.push(function() {
				toggleTool(obj, tool);
			});
		}

	}

	this.onLoadedMapbook = function(mapbookXML) {
		MyCatalog = mapbookXML;
		var catalog = mapbookXML.getElementsByTagName('catalog')[0];
		var layerControls = mapbookXML.getElementsByTagName('layer-control');
		for(var i = 0; i < layerControls.length; i++) {
			CONFIGURATION.layer_controls[layerControls[i].getAttribute('name')] = {'on' : parseBoolean(layerControls[i].getAttribute('on')), 'tip' : layerControls[i].getAttribute('tip')}	
			var funcString = "function(paths) { selectTool(); toggleTool(this, '%service_name%'); GeoMOOSE.startService('%service_name%', {'%input%' : paths}); }";
			funcString = funcString.replace(/%service_name%/g, layerControls[i].getAttribute('service-name'));
			funcString = funcString.replace('%input%', layerControls[i].getAttribute('layer-input'));


			eval("MySelf."+layerControls[i].getAttribute('name')+"Layer = "+funcString);
		}

		renderGroup(parentDivId, catalog);

		olMap.events.register('moveend', this, onRefreshMap);
		onRefreshMap();
		MapbookLoaded = true;
	}
}
/*
 * GeoMOOSE Site Configuration
 */

var CONFIGURATION = {
	'links_bar_html' : "",
	'mapserver_url' : "",
	'mapfile_root' : "",
	'fractional_zoom' : true,
	'scales' : [1,2,4,8,16,32,64,128,256,500,1000,5000],
	'max_extent' : [189783.560000,4816309.330000,761653.524114,5472346.500000],
	'initial_extent' : [410438.542057,5125011.551363637,540998.542057,5163644.278636363],
	'projection' : "EPSG:26915",
	'ground_units' : 'm',
	'coordinate_display' : {
		xy: true,	/* Ground Units */
		latlon: true,	/* Longitude and Latitude */
		usng: true	/* U.S. National Grid */
	},
	'tabs' : {
		'Catalog' : 'catalog-tab',
		'Search' : 'search-tab',
		'Services' : 'service-tab',
		'Results' : 'results-tab'
	},
	'default_tab' : 'Catalog',
	'catalog_name' : 'Catalog',
	'show_service_settings_in' : 'Services',
	'show_results_in' : 'Results',
	'zoomto' : {
/*		
		'Jump To:' : {
			'Dakota County' : [521238.614537864,4924218.86673578,473921.947801381,4974430.36885032],
			'Parcel Data' : [497205.409367,4923984.423582,477595.805945,4941970.52988],
			'Full State of MN' : [189783.560000,4816309.330000,761653.524114,5472346.500000]
		}
*/
	},
	'jumpto_scales' : {
		'1:12000' : 12000,
		'1:2400' : 2400,
		'1:1200' : 1200,
		'1:120' : 120
	},
	'startup_service' : false,
	'layer_controls' : {
		'up' : {on: true, tip: 'Move %LAYER% up on the stack'},
		'down' : {on: true, tip: 'Move %LAYER% down on the stack'},
		'fade' : {on: true, change_percent: 10, tip: 'Fade %LAYER%'},
		'unfade' : {on: true, change_percent: 10, tip: 'Unfade %LAYER%'},
		'refresh' : {on: false, tip: 'Manually refresh %LAYER%'},
		'cycle' : {on: false, tip: 'Refresh %LAYER% every 10 seconds', seconds: 10},
		'legend' : {on: true, tip: 'Show legend for %LAYER%'}
	},
	'measure_tool' : {
		'target_tab' : 'Results',
		'style' : {
			"Point" : {
				pointRadius: 4,
				graphicName: "square",
				fillColor: "white",
				fillOpacity: 1,
				strokeWidth: 1,
				strokeOpacity: 1,
				strokeColor: "#333333"
			},
			"Line" : {
				strokeWidth: 2,
				strokeColor: "#FF0000"
			},
			"Polygon" : {
				strokeWidth: 2,
				strokeColor: "#FF0000",
				fillColor: "#00FF00",
				fillOpacity: .5
			}
		},
		'line_units' : 'ft',
		'area_units' : 'acre'
	}
};
/*
 * This is the class that serves as the feedback for how to react
 * between services and javascript.
 */

/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

window.GeoMOOSE = {
	splitPaths : function(layerPaths) {
		return (new String(layerPaths)).split(':');
	},
	/* Layer Functions */
	changeLayerVisibility : function(layerPath, visibility) {
		var paths = this.splitPaths(layerPath);
		for(var p = 0; p < paths.length; p++) {
			var e = document.getElementById('catalog-'+paths[p]);
			if(!e && !Catalog.setLayerVisibility(paths[p], visibility)) {
				OpenLayers.Console.log('Layer '+paths[p]+' does not exist');
			} else if(e && e.checked != visibility) {
				e.checked = true;
				e.onclick();
			}
		}
	},

	turnLayerOn : function(layerPaths) {
		this.changeLayerVisibility(layerPaths, true);
	},

	turnLayerOff : function(layerPaths) {
		this.changeLayerVisibility(layerPaths, false);
	},

	refreshLayers : function(layerNames) {
		if(!(layerNames instanceof Array)) {
			layerNames = [layerNames];
		}
		Catalog.refreshLayer(layerNames.join(':'));
	},

	changeLayerUrl : function(layerName, url) {
		var layer = Map.getLayersByName(layerName)[0];
		layer.url = url;
	},

	updateLayerParameters : function(layerName, paramObject) {
		var layer = Map.getLayersByName(layerName)[0];
		for(var p in paramObject) {
			layer.params[p] = paramObject[p];
		}
	},

	/* Start a service with some given parameters */
	startService : function(serviceName, settingsObj, forceStart) {
		Services.startService(serviceName, settingsObj, forceStart);
	},

	/* Change to a different tab in the interface */
	changeTab : function(tabName) {
		Tabs.showTab(tabName);
	},

	/* Zoom to a point and a buffer */
	zoomToPoint : function(x,y,buffer) {
		Map.zoomToExtent(OpenLayers.Bounds.fromArray([x-buffer, y-buffer, x+buffer, y+buffer]));
	},

	/* Zoom to an extent */
	zoomToExtent : function(minx,miny,maxx,maxy) {
		Map.zoomToExtent(OpenLayers.Bounds.fromArray([minx,miny,maxx,maxy]));
	},

	/* Popup Functions */
	addPopup : function(x,y,w,h,html) {
		addPopup(x,y,w,h,html);
	},

	clearPopups : function() {
		while(Map.popups[0]) {
			Map.removePopup(Map.popups[0]);
		}
	}
};
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

function manageLayout () {
	var header = document.getElementById('header');
	var footer = document.getElementById('footer');
	var middle = document.getElementById('middle');

	middle.style.top = header.offsetHeight + 'px';
	middle.style.height = footer.offsetTop - header.offsetHeight + 'px';

	/* I'm not happy about having to have this code here, but if anyone has
		suggestions I'm totally willing to use it. */
	var controlPanel = document.getElementById('control-panel');
	var tabStrip = document.getElementById('tab-controls');
	var tabContainer = document.getElementById('tab-container');

	var cpHeight = controlPanel.offsetHeight;
	var tabStripPos = tabStrip.offsetTop;

	var p = tabStrip.offsetParent;
	while(p) {
		tabStripPos += p.offsetTop;
		p = p.offsetParent;
	}
	
	tabStripPos += tabStrip.offsetHeight;

	tabContainer.style.height = footer.offsetTop - tabStripPos + 'px';
	tabContainer.style.width = tabStrip.offsetWidth + 'px';

	if(Map instanceof OpenLayers.Map) {
		Map.updateSize();
	}
}
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*
 * main()
 * Start up script.
 */

var Map = false;
var ReferenceMap = false;
var Services = false; /* Service Manager */
var LatLongProjection = false;
var Tabs;
var Catalog = false;

var Tools = new Array();

function main() {
	/* This sets up the layout functionality in the interface */
	manageLayout();

	Proj4js.libPath = './proj4js/lib/';
	/*
	Proj4js.defs["EPSG:26915"] = "+title=NAD83 / UTM zone 15N +proj=utm +zone=15 +ellps=GRS80 +datum=NAD83 +units=m +no_defs";
	Proj4js.defs["EPSG:26914"] = "+title=NAD83 / UTM zone 14N +proj=utm +zone=14 +ellps=GRS80 +datum=NAD83 +units=m +no_defs";
	*/

	/* Capture onresize so that we can manage the layout as necessary */
	window._onresize = window.onresize;
	window.onresize = function () {
		manageLayout();
		if(window._onresize) {
			window._onresize();
		}
	}

	/* Load the Mapbook */
	OpenLayers.loadURL('php/getmapbook.php', {}, {}, onLoadedMapbook);
}

function configureMap () {
	CONFIGURATION.scales = CONFIGURATION.scales.sort().reverse();

	/* Setup the Map */	
	Map = new OpenLayers.Map('mapContainer', 
		{
			resolutions : CONFIGURATION.scales,
			maxExtent : OpenLayers.Bounds.fromArray(CONFIGURATION.max_extent),
			controls : [new OpenLayers.Control.PanZoomBar(), new OpenLayers.Control.ScaleJumper({target: 'scale-jumper'})],
			units: CONFIGURATION.ground_units,
			projection: new OpenLayers.Projection(CONFIGURATION.projection),
			displayProjection: new OpenLayers.Projection(CONFIGURATION.projection),
			fractionalZoom: CONFIGURATION.fractional_zoom
		}
	);

	//ReferenceMap = new OpenLayers.Control.OverviewMap();
	//Map.addControl(ReferenceMap);


	/* This is the only base layer and allows all of the rest of the layers to be selectively
		shown/hidden without effecting the navigation */
	var navigationLayer = new OpenLayers.Layer.Image('GeoMOOSE Navigation Layer',
		'./images/blank.gif',
		new OpenLayers.Bounds.fromArray(CONFIGURATION.max_extent),
		new OpenLayers.Size(500,500), {
			projection: new OpenLayers.Projection(CONFIGURATION.projection),
			resolutions: CONFIGURATION.scales
		});

	Map.addLayers([navigationLayer]);
	//ReferenceMap.maximizeControl();

	/* Setup the Built-in Tools */
	Tools['pan'] = new OpenLayers.Control.Navigation();
	Tools['zoomin'] = new OpenLayers.Control.ZoomBox();
	Tools['zoomout'] = new OpenLayers.Control.ZoomBox({out: true});

	var measureToolStyle = new OpenLayers.Style();
	measureToolStyle.addRules([
		new OpenLayers.Rule({symbolizer: CONFIGURATION.measure_tool.style})
	]);
	var styleMap = new OpenLayers.StyleMap({"default": measureToolStyle});

	var measureToolOptions = {
		handlerOptions: {
		    style: "default", // this forces default render intent
		    layerOptions: {styleMap: styleMap},
		    persist: true
		}
	};


	Tools['measure'] = new OpenLayers.Control.GeoMooseMeasure(OpenLayers.Handler.MeasurePath, measureToolOptions);
	Tools['measurearea'] = new OpenLayers.Control.GeoMooseMeasure(OpenLayers.Handler.Polygon, measureToolOptions);


	var showMeasureTab = function () { Tabs.showTab(CONFIGURATION.measure_tool.target_tab); };

	Tools['measure'].events.register('activate', Tools['measure'], startupMeasureLength);
	Tools['measure'].events.register('measuremove', Tools['measure'], measureToolLengthLog);
	Tools['measure'].events.register('measurepartial', Tools['measure'], measureToolPartial);

	Tools['measurearea'].events.register('activate', Tools['measurearea'], startupMeasureArea);
	Tools['measurearea'].events.register('measuremove', Tools['measurearea'], measureToolAreaLog);
	Tools['measurearea'].events.register('measurepartial', Tools['measurearea'], measureToolAreaPartial);

	var NavHistory = new OpenLayers.Control.NavigationHistory();
	Map.addControl(NavHistory);

	/* displayCoordinates not only formats the output but adds reprojection when available */
	var coordDisplay = new OpenLayers.Control.MousePosition({div: document.getElementById('coordinate-display')});
	coordDisplay.formatOutput = displayCoordinates;
	Map.addControl(coordDisplay);

	LatLongProjection = new OpenLayers.Projection('WGS84');

	for(var t in Tools) {
		Map.addControl(Tools[t]);
	}
	/* Wrapper objects for navigation history */
	var previous = { activate: function() { NavHistory.previous.trigger(); }, deactivate: function() { } };
	var next = { activate: function() { NavHistory.next.trigger(); }, deactivate: function() { } };

	var fullExtent = { activate: function() { Map.zoomToMaxExtent(); }, deactivate: function () { } };

	Tools['previous'] = previous;
	Tools['next'] = next;
	Tools['fullextent'] = fullExtent;

//	Map.zoomToMaxExtent(); /* Zoom to the initial extent for startup */

	Map.zoomToExtent(OpenLayers.Bounds.fromArray(CONFIGURATION.initial_extent));

}

function displayCoordinates(lonLat) {
        var digits = parseInt(this.numDigits);
	var html = '';
	if(CONFIGURATION.coordinate_display.xy) {
		html += '<span class="coordinate-type">X,Y: </span>';
		html += lonLat.lon.toFixed(digits) + ', ' + lonLat.lat.toFixed(digits);
	}
	var degrees = {'x': lonLat.lon, 'y' : lonLat.lat};
	OpenLayers.Projection.transform(degrees, 
		Map.getProjectionObject(),
		LatLongProjection);

	if(CONFIGURATION.coordinate_display.latlon) {
		html += '<span class="coordinate-type">Lat, Lon: </span>';
		html += degrees.x.toFixed(3) + ', ' + degrees.y.toFixed(3);
	}

	if(CONFIGURATION.coordinate_display.usng) {
		html += '<span class="coordinate-type">USNG: </span>';
		// Map.getResolution returns map units per pixel
        	var inches = OpenLayers.INCHES_PER_UNIT;
		/* Convert the map units to inches, and then inches to meters */
		var metersPerPx = Map.getResolution() * (inches[Map.getUnits()] * (1/inches['m']));
		var digits = 6;
		if(metersPerPx > 10000) {
			digits = 0;
		} else if(metersPerPx > 1000) {
			digits = 1;
		} else if(metersPerPx > 100) {
			digits = 2;
		} else if(metersPerPx > 10) {
			digits = 3;
		} else if(metersPerPx > 1) {
			digits = 4;
		} else if(metersPerPx > .1) {
			digits = 5; 
		}

		html += (new USNG()).fromLatLong(degrees, digits);
	}
/*        var newHtml =
            this.prefix +
            lonLat.lon.toFixed(digits) +
            this.separator + 
            lonLat.lat.toFixed(digits) +
            this.suffix;
*/
        return html;
}


var MENU_TOGGLE_ICON = '';

function displayMenu(rXML) {
	var menuBar = new Menubar();
	menuBar.setParent('menubar');
	menuBar.populateMenuBar(rXML.responseXML);
}

function loadMenu() {
	OpenLayers.loadURL('menu.xml', {}, {}, displayMenu);
}


function onLoadedMapbook(response) {
	var toolbarId = 'toolbar';
	var maxSelectedTool = null;
	if(response.responseXML) {
		/* check version */
		var version = parseFloat(response.responseXML.documentElement.getAttribute('version'));
		if(version < 2.0) {
			alert('Specified mapbook version '+version+' is older than 2.0. No promises this will work.');
		}

		/* Load the configuration bits */
		var configuration = response.responseXML.getElementsByTagName('configuration')[0];
		if(configuration && configuration.childNodes) {
			var params = configuration.getElementsByTagName('param');
			for(var p = 0; p < params.length; p++) {
				var param = params[p];
				var name = param.getAttribute('name');
				var value = OpenLayers.Util.getXmlNodeValue(param);

				/* this is a bit naughty... but it works quite well */
				var typeValue = eval('CONFIGURATION.'+name);
				var jsString = 'CONFIGURATION.'+name+' = ';
				if(typeValue instanceof Array) {
					if(value[0] == '[' && value[value.length-1] == ']') {
						value = value.substring(1,value.length-1);
					}
					jsString += '['+value+']';
				} else if(typeof(typeValue) == "string" || typeValue instanceof String) {
					jsString += 'value';
				} else if(typeValue == true || typeValue == false) {
					jsString += 'parseBoolean(value)';
				} else {
					value = '('+value+')';
					jsString += 'eval(value)';
				}
				//console.log(name, typeof(typeValue));
				//console.log(jsString);
				//console.log(eval(value));
				eval(jsString);
			}
		}

		var mandatory = ['mapfile_root', 'mapserver_url'];
		for(var i =0; i < mandatory.length; i++) {
			if(CONFIGURATION[mandatory[i]] == "") {
				alert(mandatory[i]+' must be configured in the mapbook'); 
			}
		}

		configureMap();

		var tools = response.responseXML.getElementsByTagName('tool');
		for(var i = 0; i < tools.length; i++) {
			addTool(toolbarId, tools[i]);
			if(parseBoolean(tools[i].getAttribute('selected'))) {
				maxSelectedTool = tools[i];
			}
		}
	
		var services = response.responseXML.getElementsByTagName('map-source');
		for(var i = services.length - 1; i >= 0; i--) {
			var type = services[i].getAttribute('type').toLowerCase();
			var layer = false;
			var params = services[i].getElementsByTagName('param');
			var paramHash = {};

			var url = OpenLayers.Util.getXmlNodeValue(services[i].getElementsByTagName('url')[0]);

			var tiled = !parseBoolean(services[i].getAttribute('tiled'), false);

			for(var p = 0; p < params.length; p++) {
				var param = params[p];
				paramHash[param.getAttribute('name')] = param.getAttribute('value');
			}

			if(type == 'wms') {
				layer = new OpenLayers.Layer.WMS(services[i].getAttribute('name'),
					url, paramHash, {singleTile : tiled, isBaseLayer: false});
			} else if(type == 'mapserver') {
				if(!url) {
					url = CONFIGURATION.mapserver_url;
				}

				var file = '';
				try {
					file = OpenLayers.Util.getXmlNodeValue(services[i].getElementsByTagName('file')[0]);
					if(file.substring(0,1) == '.') {
						file = CONFIGURATION.mapfile_root + file.substring(1);
					}
				} catch(e) {
					file = '';
				}
				paramHash['map'] = file;
				layer = new OpenLayers.Layer.MapServer(services[i].getAttribute('name'),
					url, paramHash, {singleTile : tiled, isBaseLayer: false});
			}


			if(layer) {
				if(layer.params['map_imagetype']) {
					delete layer.params['map_imagetype'];
				}
				layer.setVisibility(false);
				Map.addLayer(layer);
				if(parseBoolean(services[i].getAttribute('reference'))) {
					var ref_layer = layer.clone();
					//ReferenceMap.ovmap.addLayer(ref_layer);
					ref_layer.setVisibility(true);
				}
			}
		}

		/* Add the drawing tools */
		var drawingLayer = new OpenLayers.Layer.Vector('/drawinglayer');
		Map.addLayer(drawingLayer);

		Tools['point'] = new OpenLayers.Control.DrawFeature(drawingLayer, OpenLayers.Handler.Point);
		Tools['line'] = new OpenLayers.Control.DrawFeature(drawingLayer, OpenLayers.Handler.Path);
		Tools['polygon'] = new OpenLayers.Control.DrawFeature(drawingLayer, OpenLayers.Handler.Polygon);
		Tools['edit-polygon'] = new OpenLayers.Control.ModifyFeature(drawingLayer);
		var drawingtools = ['point','line','polygon','edit-polygon'];

		for(var d = 0; d < drawingtools.length; d++) {
			Map.addControl(Tools[drawingtools[d]]);
		}

		/* Add the layer for the popus */
		var popupsLayer = new OpenLayers.Layer.Markers('/popups');
		Map.addLayer(popupsLayer);

		configureUserInterface(response.responseXML);


		/* reload for the layers to update */
		Map.zoomToExtent(OpenLayers.Bounds.fromArray(CONFIGURATION.initial_extent));
	}

	document.getElementById('menubar').innerHTML = CONFIGURATION.links_bar_html;

	manageLayout();
	if(maxSelectedTool != null) {
		var name = maxSelectedTool.getAttribute('name');
		var tool = document.getElementById('tool-'+name);
		tool.onclick();
		tool = null;
	}


	var args = OpenLayers.Util.getParameters();
	if(args.call) {
		GeoMOOSE.startService(args.call, args, true);
	}
}

function changeExtentBySelect() {
	var options = this.getElementsByTagName('option');
	var selectedIndex = this.selectedIndex;

	/* reset to the "blank" option */
	for(var i = 0; i < options.length; i++) {
		options[i].selected = false;
	}
	options[0].selected = true;
	
	/* zoom to the extents */
	var arr = new String(options[selectedIndex].value).split(',');
	GeoMOOSE.zoomToExtent(arr[0],arr[1],arr[2],arr[3]);
}

function configureUserInterface(mapbook) {
	/* Configure The Zoom To's */
	var zoomToObject = CONFIGURATION.zoomto;
	var zoomToParent = document.getElementById('zoomto-boxes');
	for(var zoomToTitle in zoomToObject) {
		var zoomToContainer = document.createElement('div');
		zoomToParent.appendChild(zoomToContainer);
		zoomToContainer.className = 'zoomto-container';
		zoomToContainer.appendChild(document.createTextNode(zoomToTitle));

		var zoomToSelect = document.createElement('select');
		zoomToSelect.className = 'zoomto-select';
		zoomToContainer.appendChild(zoomToSelect);

		zoomToSelect.onchange = changeExtentBySelect;

		var blankOption = document.createElement('option');
		zoomToSelect.appendChild(blankOption);

		for(var extentTitle in zoomToObject[zoomToTitle]) {
			var option = document.createElement('option');
			option.value = zoomToObject[zoomToTitle][extentTitle].join(',');
			zoomToSelect.appendChild(option);
			option.appendChild(document.createTextNode(extentTitle));
		}
	}

	/* Tabs */
	Tabs = new GeomooseTabs('tab-controls');
	Tabs.initialize();

	/* Catalog */
	Catalog = new GeomooseCatalog(Tabs.getTab(CONFIGURATION.catalog_name), Map);
	Catalog.onLoadedMapbook(mapbook);

	/* Service Manager */
	Services = new ServiceManager(mapbook, Tabs.getTab(CONFIGURATION.show_service_settings_in));
	Services.initialize();

	Services.onStart = function (service) {
		if(parseBoolean(service.getAttribute('display'), true)) {
			Tabs.showTab(CONFIGURATION.show_service_settings_in);
		}
	}

	Services.onFinish = function () {
		document.getElementById(Tabs.getTab(CONFIGURATION.show_service_settings_in)).innerHTML = '';
	}

	Services.onServiceReturn = function (response) {
		clearPopups();
		var showResults = false;
		var contentType = new String(response.getResponseHeader('Content-type')).toLowerCase();
		if(contentType.indexOf('xml') > 0 && response.responseXML) {
			var xml = new OpenLayers.Format.XML();
			var scripts = response.responseXML.getElementsByTagName('script');
			var js = '';
			for(var s = 0; s < scripts.length; s++) {
				js += xml.concatChildValues(scripts[s]);
			}
			if(scripts.length > 0) { eval(js); }

			var texts = response.responseXML.getElementsByTagName('html');
			var html = '';
			for(var h = 0; h < texts.length; h++) {
				html += xml.concatChildValues(texts[h]);
			}
			document.getElementById('results-tab').innerHTML = html;
			if(html != '') {
				showResults = true;
			}


			var popups = response.responseXML.getElementsByTagName('popup');
			for(var p = 0; p < popups.length; p++) {
				var pp = popups[p];
				addPopup(parseFloat(pp.getAttribute('x')), parseFloat(pp.getAttribute('y')),
					parseFloat(pp.getAttribute('width')), parseFloat(pp.getAttribute('height')),
					xml.concatChildValues(pp));
			}
		} else if(response.responseText) {
			document.getElementById('results-tab').innerHTML = response.responseText;
			showResults = true;
		} else {
			alert('No Valid Response!');
		}
		if(showResults) {
			Tabs.showTab(CONFIGURATION.show_results_in);
		}
	}

}

var onSelectTool = new Array();
function selectTool(elm) {
	var p = document.getElementById('toolbar');
	var tools = p.getElementsByTagName('a');
	for(var i = 0; i < tools.length; i++) {
		if(tools[i].className.match(/Tool/)) {
			/* remove the tool specific selected styling */
			tools[i].className = tools[i].className.replace(/sprite\-control\-[A-Za-z]*\-selected/,'');
			/* remove the generic selected styling */
			tools[i].className = tools[i].className.replace(' selected', '');
		}
	}
	if(elm) {
		var toolName = elm.id.split('-')[1];
		toolName = 'sprite-control-'+toolName;

		var p = elm.parentNode;
		elm.className += ' '+toolName+'selected';
		elm.className += ' selected';
	}
	for(var i = 0; i < onSelectTool.length; i++) {
		onSelectTool[i]();
	}
	/* run 'em all and then get rid of 'em */
	onSelectTool = new Array();
}

function internalToolAction() {
	if(this.selectable) {
		selectTool(this);
		for(var t in Tools) {
			Tools[t].deactivate();
		}
	}
	var action = this.getAttribute('action');
	if(Tools[action]) {
		Tools[action].activate();
	}
}

function serviceToolAction() {
	if(this.selectable) {
		selectTool(this);
	}

	var serviceName = this.getAttribute('service');
	Services.startService(serviceName);
}

function addTool(parentId, toolXML) {
	var p = document.getElementById(parentId);
	var tool = document.createElement('a');
	var container = document.createElement('span');
	p.appendChild(tool);
	tool.className = 'Tool sprite-control sprite-control-'+toolXML.getAttribute('name');
	tool.id = 'tool-'+toolXML.getAttribute('name');
	var span = document.createElement('span');
	container.className = 'ToolContent';
	tool.appendChild(container);
	container.appendChild(span);
	span.className = 'ToolText';
	span.appendChild(document.createTextNode(toolXML.getAttribute('title')));

	tool.href = '#';
	tool.title = toolXML.getAttribute('title');
	tool.selectable = parseBoolean(toolXML.getAttribute('selectable'), true);

	var toolType = toolXML.getAttribute('type').toLowerCase();
	if(toolType == 'internal') {
		tool.setAttribute('action', toolXML.getAttribute('action'));
		tool.onclick = internalToolAction;
	} else if(toolType == 'service') {
		tool.setAttribute('service', toolXML.getAttribute('service'));
		tool.onclick = serviceToolAction;
	}

	container = null;
	span = null;
	tool = null;
	p = null;
}

function parseBoolean(bool, def) {
	if(!bool) { return def; }
	var boolString = new String(bool);
	if(boolString.match(/true/i)) { return true; }
	else if(boolString == '1') { return true; }
	else if(boolString.match(/on/i)) { return true; }
	return false;
}

function commifyNumber(number) {
	var numberOrig = new String(number);
	var numberArr = new String(number).split('.');
	var numberSign = number.substring(0,1);
	/* Oh, snap, it's negative */
	if(numberSign == '-') {
		number = new String(number).substring(1);
		numberArr = new String(number).split('.');
	} else {
		numberSign = '';
	}
	number = numberArr[0];
	number = '' + number;
	if (number.length > 3) {
		var mod = number.length % 3;
		var output = (mod > 0 ? (number.substring(0,mod)) : '');
		for (i=0 ; i < Math.floor(number.length / 3); i++) {
			if ((mod == 0) && (i == 0))
				output += number.substring(mod+ 3 * i, mod + 3 * i + 3);
			else
				output+= ',' + number.substring(mod + 3 * i, mod + 3 * i + 3);
		}
		} else {
		output=number;
	}
	if(numberOrig.match('.') && numberArr[1]) {
		output = output + '.' + numberArr[1];
	}
	return numberSign+output;
}

function stripCommas(v) {
	v = new String(v);
	while(v.match(/\,/)) {
		v = v.replace(',','');
	}
	return v;
}



function clearPopups() {
	while(Map.popups.length > 0) {
		Map.removePopup(Map.popups[0]);
	}
}

function addPopup(x,y,w,h,html) {
	var size = new OpenLayers.Size(w,h);
	var offset = new OpenLayers.Pixel(-1,-1);
	var icon = new OpenLayers.Icon('images/blank.gif', new OpenLayers.Size(1,1), offset);

	var modifiedHTML = '<div class="popupContainer" style="width: '+w+'px; height: '+h+'px">'+html+'</div>';
	var popup = new OpenLayers.Popup.FramedCloud('id0', new OpenLayers.LonLat(x,y),
			size, modifiedHTML, icon, true);

/*	popup.minSize = size.clone();*/
	popup.autoSize = false;

	Map.addPopup(popup);
}


/*
 * This generates a mapping request.
 * There exist so much data needed to request printing that I simply
 * put it in it's own script/function
 */

function getPrintRequest() {
	var layer_names = [], layer_urls = [], layer_opacity = [];
	for(var i in Map.layers) {
		var layer = Map.layers[i];
		if(layer.getVisibility()) {
			if(layer instanceof OpenLayers.Layer.WMS || layer instanceof OpenLayers.Layer.MapServer) {

				layer_names.push(layer.name);
				layer_urls.push(layer.getURL(OpenLayers.Bounds.fromArray([0,0,0,0])));

				var o = layer.opacity;
				if(o != null) { o = 1.0; }
				layer_opacity.push(o);
			}
		}
	}

	var x = {
		'layers' : layer_names.join(':'),
		'size' : '500,500',
		'extent' : Map.getExtent().toArray().join(',')
	};

	for(var i = 0; i < layer_names.length; i++) {
		x[layer_names[i]+'_url'] = layer_urls[i];
		x[layer_names[i]+'_opacity'] = layer_opacity[i];
	}

//	console.info(OpenLayers.Util.getParameterString(x));
//	window.open('php/print.php?' + OpenLayers.Util.getParameterString(x));
//	return '='+layer_names.join(':')+OpenLayers.Util.getParameterString(x);
	return x;
}
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/


function startupMeasureLength(event) {
	startupMeasureTool('length');
}

function startupMeasureArea(event) {
	startupMeasureTool('area');
}

function startupMeasureTool(mType) {
	Tabs.showTab(CONFIGURATION.measure_tool.target_tab);

	var trans = {'length' : 'Length', 'area' : 'Area' };

	var p = document.getElementById(Tabs.getTab(CONFIGURATION.measure_tool.target_tab));

	p.innerHTML = '';

	var title = document.createElement('div');
	p.appendChild(title);
	title.appendChild(document.createTextNode('Measure '+trans[mType]));

	p.appendChild(document.createElement('br'));

	var infoTable = document.createElement('table');
	var infoTbody = document.createElement('tbody');
	p.appendChild(infoTable);
	infoTable.appendChild(infoTbody);

	var totalRow = document.createElement('tr');
	var totalTitle = document.createElement('th');
	var totalCell = document.createElement('td');

	infoTbody.appendChild(totalRow);
	totalRow.appendChild(totalTitle);
	totalRow.appendChild(totalCell);

	var segmentRow = document.createElement('tr');
	var segmentTitle = document.createElement('th');
	var segmentCell = document.createElement('td');

	infoTbody.appendChild(segmentRow);
	segmentRow.appendChild(segmentTitle);
	segmentRow.appendChild(segmentCell);

	var unitsRow = document.createElement('tr');
	var unitsTitle = document.createElement('th');
	var unitsCell = document.createElement('td');

	infoTbody.appendChild(unitsRow);
	unitsRow.appendChild(unitsTitle);
	unitsRow.appendChild(unitsCell);

	totalTitle.appendChild(document.createTextNode('Total '+trans[mType]+':'));
	
	var totalInput = document.createElement('input');
	totalInput.size = 14;
	totalInput.id = 'measuretool-input-total';
	totalCell.appendChild(totalInput);


	segmentTitle.appendChild(document.createTextNode('Segment '+trans[mType]+':'));
	var segmentInput = document.createElement('input');
	segmentInput.size = 14;
	segmentInput.id = 'measuretool-input-segment';
	segmentCell.appendChild(segmentInput);

	unitsTitle.appendChild(document.createTextNode('Units:'));

	var unitsDropdown = document.createElement('select');
	var units = {'Miles' : 'mi', 'Feet' : 'ft', 'Meters' : 'm'};

	unitsDropdown.id = 'measuretool-units';
	unitsCell.appendChild(unitsDropdown);
	for(var u in units) {
		var opt = document.createElement('option');
		opt.value = units[u];
		unitsDropdown.appendChild(opt);
		opt.appendChild(document.createTextNode(u));
		if(units[u] == CONFIGURATION.measure_tool.units) {
			opt.selected = true;
		}
	}

	var clearRow = document.createElement('tr');
	var blankCell = document.createElement('td');
	var clearCell = document.createElement('td');

	infoTbody.appendChild(clearRow);
	clearRow.appendChild(blankCell);
	clearRow.appendChild(clearCell);

	var clearButton = document.createElement('input');
	clearButton.type = 'button';
	clearButton.value = 'Clear';
	clearButton.onclick = measureToolClear;
	clearCell.appendChild(clearButton);

	var measureTable = document.createElement('table');
	var measureTbody = document.createElement('tbody');
	measureTbody.id = 'measuretool-tbody';

	p.appendChild(measureTable);
	measureTable.appendChild(measureTbody);
}

function measureToolClear(event) {
	var measureTable = document.getElementById('measuretool-tbody');
	measureTable.innerHTML = '';

	var measureTools = ['measure','measurearea'];
	for(var m = 0; m < measureTools.length; m++) {
		var tool = measureTools[m];
		Tools[tool].measure(new OpenLayers.Geometry.Point(), 'measure');
		if(Tools[tool].handler.layer) {
			Tools[tool].handler.layer.removeFeatures(Tools[tool].handler.layer.features);
		}
	}
}

function measureToolPartial(event) {
	var units = document.getElementById('measuretool-units');
	units = units.getElementsByTagName('option')[units.selectedIndex].value;

	var length = this.getLength(event.geometry, units);
	var total = document.getElementById('measuretool-input-total');
	var segment = document.getElementById('measuretool-input-segment');

	var t = document.getElementById('measuretool-tbody');

	var totalValue = stripCommas(total.value);

	if(length < totalValue) {
		while(t.firstChild) {
			t.removeChild(t.firstChild);
		}
		total.value = 0;
		segment.value = 0;
	}

	if(length > 0) {
		var rows = t.getElementsByTagName('tr');
		segment.value = commifyNumber((length - totalValue).toFixed(2));
		total.value = commifyNumber(length.toFixed(2));

		var newRow = document.createElement('tr');
		if(rows.length < 1) {
			t.appendChild(newRow);
		} else {
			t.insertBefore(newRow, rows[0]);
		}
		var segmentTitle = document.createElement('th');
		newRow.appendChild(segmentTitle);
		segmentTitle.appendChild(document.createTextNode(rows.length));

		var segmentLength = document.createElement('td');
		newRow.appendChild(segmentLength);
		segmentLength.appendChild(document.createTextNode(commifyNumber(length.toFixed(2))+' '+units));
	}
}

function measureToolLengthLog(event) {
	var units = document.getElementById('measuretool-units');
	units = units.getElementsByTagName('option')[units.selectedIndex].value;
	var segment = document.getElementById('measuretool-input-segment');
	var total = document.getElementById('measuretool-input-total');
	var length = this.getLength(event.geometry, units);
	length -= stripCommas(total.value);
	segment.value = commifyNumber(length.toFixed(2));
}

function measureToolAreaLog(event) {
	var units = document.getElementById('measuretool-units');
	units = units.getElementsByTagName('option')[units.selectedIndex].value;
	var segment = document.getElementById('measuretool-input-segment');
	var total = document.getElementById('measuretool-input-total');
	var area = this.getArea(event.geometry, units);
	area -= stripCommas(total.value);
	segment.value = commifyNumber(area.toFixed(2));
}

function measureToolAreaPartial(event) {
	var units = document.getElementById('measuretool-units');
	units = units.getElementsByTagName('option')[units.selectedIndex].value;

	var length = this.getArea(event.geometry, units);
	var total = document.getElementById('measuretool-input-total');
	var segment = document.getElementById('measuretool-input-segment');

	var t = document.getElementById('measuretool-tbody');

	var totalValue = stripCommas(total.value);

	/* count the number of points in the polygon, if they are less than 3
		then reset the counters */

	if(countPoints(event.geometry) < 3) {
		while(t.firstChild) {
			t.removeChild(t.firstChild);
		}
		total.value = '0.00';
		segment.value = '0.00';
	}

	if(length > 0) {
		var rows = t.getElementsByTagName('tr');
		segment.value = commifyNumber((length - totalValue).toFixed(2));
		total.value = commifyNumber(length.toFixed(2));

		var newRow = document.createElement('tr');
		if(rows.length < 1) {
			t.appendChild(newRow);
		} else {
			t.insertBefore(newRow, rows[0]);
		}
		var segmentTitle = document.createElement('th');
		newRow.appendChild(segmentTitle);
		segmentTitle.appendChild(document.createTextNode(rows.length));

		var segmentLength = document.createElement('td');
		newRow.appendChild(segmentLength);
		segmentLength.appendChild(document.createTextNode(commifyNumber(length.toFixed(2))+' '+units));
	}
}

function countPoints(g) {
	var points = 0;
	if(g.components) {
		for(var i = 0; i < g.components.length; i++) {
			if(g.components[i] instanceof OpenLayers.Geometry.Point) {
				points += 1;
			} else {
				points += countPoints(g.components[i]);
			}
		}
	}
	return points;

}
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

OpenLayers.Handler.MeasurePath = OpenLayers.Class(OpenLayers.Handler.Path, {
	initialize: function(control, callbacks, options) {
		OpenLayers.Handler.Path.prototype.initialize.apply(this, arguments);
	},

	mousemove: function(evt) {
		if(this.drawing) { 
			var lonlat = this.map.getLonLatFromPixel(evt.xy);
			this.point.geometry.x = lonlat.lon;
			this.point.geometry.y = lonlat.lat;
			this.point.geometry.clearBounds();
			if(this.mouseDown && this.freehandMode(evt)) {
				this.addPoint();
			} else {
				this.modifyFeature();
			}
			this.callback("mousemove", [this.point.geometry, this.getGeometry()]);
			this.drawFeature();
		}
		return true;
	}
});
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Control.js
 * @requires OpenLayers/Feature/Vector.js
 */

/**
 * Class: OpenLayers.Control.Measure
 * Allows for drawing of features for measurements.
 *
 * Inherits from:
 *  - <OpenLayers.Control>
 */
OpenLayers.Control.GeoMooseMeasure = OpenLayers.Class(OpenLayers.Control, {

    /**
     * Constant: EVENT_TYPES
     * {Array(String)} Supported application event types.  Register a listener
     *     for a particular event with the following syntax:
     * (code)
     * control.events.register(type, obj, listener);
     * (end)
     *
     * Listeners will be called with a reference to an event object.  The
     *     properties of this event depends on exactly what happened.
     *
     * Supported control event types (in addition to those from <OpenLayers.Control>):
     *  - *measure* Triggered when a measurement sketch is complete.  Listeners
     *      will receive an event with measure, units, order, and geometry
     *      properties.
     *  - *measurepartial* Triggered when a new point is added to the
     *      measurement sketch.  Listeners receive an event with measure,
     *      units, order, and geometry.
     */
    EVENT_TYPES: ['measure', 'measurepartial','measuremove'],

    /**
     * APIProperty: handlerOptions
     * {Object} Used to set non-default properties on the control's handler
     */
    handlerOptions: null,
    
    /**
     * Property: callbacks
     * {Object} The functions that are sent to the handler for callback
     */
    callbacks: null,
    
    /**
     * Property: displaySystem
     * {String} Display system for output measurements.  Supported values
     *     are 'english', 'metric', and 'geographic'.  Default is 'metric'.
     */
    displaySystem: 'metric',
    
    /**
     * Property: displaySystemUnits
     * {Object} Units for various measurement systems.  Values are arrays
     *     of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing
     *     order of length.
     */
    displaySystemUnits: {
        geographic: ['dd'],
        english: ['mi', 'ft', 'in'],
        metric: ['km', 'm']
    },

    /**
     * Constructor: OpenLayers.Control.Measure
     * 
     * Parameters:
     * handler - {<OpenLayers.Handler>} 
     * options - {Object} 
     */
    initialize: function(handler, options) {
        // concatenate events specific to measure with those from the base
        this.EVENT_TYPES =
            OpenLayers.Control.GeoMooseMeasure.prototype.EVENT_TYPES.concat(
            OpenLayers.Control.prototype.EVENT_TYPES
        );
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.callbacks = OpenLayers.Util.extend(
            {done: this.measureComplete, point: this.measurePartial, mousemove: this.measureMove},
            this.callbacks
        );
        this.handler = new handler(this, this.callbacks, this.handlerOptions);
    },
    
    /**
     * Method: updateHandler
     *
     * Parameters:
     * handler - {Function} One of the sketch handler constructors.
     * options - {Object} Options for the handler.
     */
    updateHandler: function(handler, options) {
        var active = this.active;
        if(active) {
            this.deactivate();
        }
        this.handler = new handler(this, this.callbacks, options);
        if(active) {
            this.activate();
        }
    },

    /**
     * Method: measureComplete
     * Called when the measurement sketch is done.
     *
     * Parameters:
     * geometry - {<OpenLayers.Geometry>}
     */
    measureComplete: function(geometry) {
        this.measure(geometry, "measure");
    },
    
    /**
     * Method: measurePartial
     * Called each time a new point is added to the measurement sketch.
     *
     * Parameters:
     * point - {<OpenLayers.Geometry.Point>} The last point added.
     * geometry - {<OpenLayers.Geometry>} The sketch geometry.
     */
    measurePartial: function(point, geometry) {
        this.measure(geometry, "measurepartial");
    },

    measureMove: function(point, geometry) {
    	this.measure(geometry, "measuremove");
    },

    /**
     * Method: measure
     *
     * Parameters:
     * geometry - {<OpenLayers.Geometry>}
     * eventType - {String}
     */
    measure: function(geometry, eventType) {
        var stat, order;
        if(geometry.CLASS_NAME.indexOf('LineString') > -1) {
            stat = this.getBestLength(geometry);
            order = 1;
        } else {
            stat = this.getBestArea(geometry);
            order = 2;
        }
        this.events.triggerEvent(eventType, {
            measure: stat[0],
            units: stat[1],
            order: order,
            geometry: geometry
        });
    },
    
    /**
     * Method: getBestArea
     * Based on the <displaySystem> returns the area of a geometry.
     *
     * Parameters:
     * geometry - {<OpenLayers.Geometry>}
     *
     * Returns:
     * {Array([Float, String])}  Returns a two item array containing the
     *     area and the units abbreviation.
     */
    getBestArea: function(geometry) {
        var units = this.displaySystemUnits[this.displaySystem];
        var unit, area;
        for(var i=0, len=units.length; i<len; ++i) {
            unit = units[i];
            area = this.getArea(geometry, unit);
            if(area > 1) {
                break;
            }
        }
        return [area, unit];
    },
    
    /**
     * Method: getArea
     *
     * Parameters:
     * geometry - {<OpenLayers.Geometry>}
     * units - {String} Unit abbreviation
     *
     * Returns:
     * {Float} The geometry area in the given units.
     */
    getArea: function(geometry, units) {
        var area = geometry.getArea();
        var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
        if(inPerDisplayUnit) {
            var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[this.map.getUnits()];
            area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2);
        }
        return area;
    },
    
    /**
     * Method: getBestLength
     * Based on the <displaySystem> returns the length of a geometry.
     *
     * Parameters:
     * geometry - {<OpenLayers.Geometry>}
     *
     * Returns:
     * {Array([Float, String])}  Returns a two item array containing the
     *     length and the units abbreviation.
     */
    getBestLength: function(geometry) {
        var units = this.displaySystemUnits[this.displaySystem];
        var unit, length;
        for(var i=0, len=units.length; i<len; ++i) {
            unit = units[i];
            length = this.getLength(geometry, unit);
            if(length > 1) {
                break;
            }
        }
        return [length, unit];
    },

    /**
     * Method: getLength
     *
     * Parameters:
     * geometry - {<OpenLayers.Geometry>}
     * units - {String} Unit abbreviation
     *
     * Returns:
     * {Float} The geometry length in the given units.
     */
    getLength: function(geometry, units) {
        var length = geometry.getLength();
        var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
        if(inPerDisplayUnit) {
            var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[this.map.getUnits()];
            length *= (inPerMapUnit / inPerDisplayUnit);
        }
        return length;
    },

    CLASS_NAME: "OpenLayers.Control.Measure"
});
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

function showMenu(parent,submenu) {
	submenu.style.visibility = 'visible';
	submenu.style.left = parent.offsetLeft + 'px';
	if(document.all) {
		var trueTop = 0;
		var sumNode = parent;
		while(sumNode.offsetParent) {
			trueTop += sumNode.offsetTop;
			sumNode = sumNode.offsetParent;
		}
		submenu.style.top = trueTop + parent.offsetHeight + 'px';
	} else {
		submenu.style.top = parent.offsetTop + parent.offsetHeight + 'px';
	}
}

function menuIsVisible(submenu) {
	if(submenu.style.visibility == 'visible') return true;
	return false;
}

function showSubMenu(parent, submenu) {
	submenu.style.visibility = 'visible';
	submenu.style.left = parent.offsetLeft + parent.offsetWidth + 'px';
	submenu.style.top = parent.offsetTop + 'px';
}

function onoverShowSubMenu() {
	showSubMenu(this, this.getElementsByTagName('ul')[0]);
}

function hideMenu(submenu) {
	if(!submenu) { submenu = this.submenu; }
	if(submenu) {
		submenu.style.visibility = 'hidden';
	}
}

function toggleCheckMark() {
	var checkMark = this.checkMark;
	if(checkMark.style.width == '0px') {
		checkMark.style.width = 'auto';
	} else {
		checkMark.style.width = '0px';
	}
}

function hideDoubleParent() {
	hideMenu(this.parentNode.parentNode);
}

function hideFirstUL() {
	hideMenu(this.getElementsByTagName('ul')[0]);
}

var MENUBAR_INSTANCE = 0;
function Menubar() {
	var Tree;
	var Parent;
	var MenuId = 'Menu'+MENUBAR_INSTANCE;
	MENUBAR_INSTANCE++;

	this.createBranch = function(xml) {
		var items = xml.getElementsByTagName('item');	
		var branch = document.createElement('ul');
		branch.className = 'submenu';
		for(var i = 0; i < items.length; i++) {
			if(items[i].parentNode == xml) {
				var item = document.createElement('li');
				var itemLink = document.createElement('a');

				branch.appendChild(item);

				if(items[i].getAttribute('href')) {
					itemLink.href = items[i].getAttribute('href');
				} else {
					itemLink.href = '#';
				}

				if(items[i].getAttribute('target')) {
					itemLink.target = items[i].getAttribute('target');
				}

				if(items[i].getAttribute('id')) {
					itemLink.id = items[i].getAttribute('id');
				}
				itemLink.onclick = hideDoubleParent;
				itemLink.appendChild(document.createTextNode(items[i].getAttribute('title')));
				item.appendChild(itemLink);
				itemLink.style.marginLeft = '22px';
				if(items[i].getAttribute('toggle') && items[i].getAttribute('toggle').match(/true/i)) {
					/*var checkBox = document.createElement('input');
					checkBox.type = 'checkbox';
					checkBox.disabled = true;
					checkBox.style.position = 'absolute';
					checkBox.style.right = '2px';
					itemLink.appendChild(checkBox);
					if(items[i].getAttribute('default') && items[i].getAttribute('default').match(/true/i)) {
						checkBox.defaultChecked = true;
					} else {
						checkBox.defaultChecked = false;
					}
					itemLink.onclick = function () {
						checkBox.checked = !checkBox.checked;
					}*/
					var checkMark = document.createElement('img');
					checkMark.src = MENU_TOGGLE_ICON;
					checkMark.style.verticalAlign = 'middle';
					checkMark.style.position = 'absolute';
					checkMark.style.left = '2px';
					//checkMark.style.marginTop = '4px';
					if(items[i].getAttribute('default') && items[i].getAttribute('default').match(/true/i)) {
						checkMark.style.width = 'auto';;
					} else {
						checkMark.style.width = '0px';
					}
					itemLink.checkMark = checkMark;
					itemLink.onclick = toggleCheckMark;
					itemLink.appendChild(checkMark);
				}

				
				var submenus = items[i].getElementsByTagName('item');
				for(var sb = 0; sb <  submenus.length; sb++) {
					var subBranch = this.createBranch(items[i]);
					item.appendChild(subBranch);
					
/*					item.onmouseover = function() {
						showSubMenu(this, this.getElementsByTagName('ul')[0]);
					}
					item.onmouseout = function() {
						hideMenu(this.getElementsByTagName('ul')[0]);
					}*/
					item.onmouseover = onoverShowSubMenu;
					item.onmouseout = hideFirstUL;
				}
			
				if(document.all) {
					//menuElements[menuElements.length] = item;
				}
			}
		}
		return branch;

	}

	//var menuElements = new Array();

	var MySelf = this;

	function rootHideAll(event) {
		if(window.event) { event = window.event; }
		var allMenus = this.getElementsByTagName('ul');
		for(var m = 0; m < allMenus.length; m++) {
			hideMenu(allMenus[m]);
		}

	}

	this.populateMenuBar = function(xml) {
		var root = document.createElement('ul');
		root.className = 'menubar';
		root.hideAll = rootHideAll;
		root.setAttribute('id',MenuId);

		var menus = xml.getElementsByTagName('menu');
		for(var m = 0; m < menus.length; m++) {
			var menu = document.createElement('li');
			root.appendChild(menu);
			menu.className = 'menu';

			var menuLink = document.createElement('a');
			menu.appendChild(menuLink);
			menuLink.appendChild(document.createTextNode(menus[m].getAttribute('title')));

			if(menus[m].getAttribute('href')) {
				menuLink.href = menus[m].getAttribute('href');
			} else {
				menuLink.href = '#';
			}
			
			if(menus[m].getAttribute('target')) {
				menuLink.target = menus[m].getAttribute('target');
			}

			if(menus[m].getAttribute('id')) {
				menuLink.id = menus[m].getAttribute('id');
			}

			var branch = this.createBranch(menus[m]);
			menu.appendChild(branch);
			branch = null;
			function focusFunction(event) {
				if(window.event) { event = window.event; }
				if(this.getElementsByTagName('ul')[0]) {
					var subItems = this.getElementsByTagName('ul')[0].getElementsByTagName('li');
					if(subItems.length > 0) {
						showMenu(this, this.getElementsByTagName('ul')[0]);
					}
				}
			}

			menu.onfocus = focusFunction;
			menu.onblur = hideFirstUL; 
			
			if(document.all) {
				function f() {
					this.parentNode.hideAll();
					this.onfocus();
				}
				menu.onclick = f;
				//menuElements[menuElements.length] = menu;
			}
			menu = null;


		}

		if(document.all) {
			document.attachEvent('onclick',IEonBlurSim);
		}
		if(Parent) {
			document.getElementById(Parent).appendChild(root);
		}
		root = null;
	}
	
	function IEonBlurSim(event) {
		if(window.event) { event=  window.event; }
		var menuItem = event.srcElement.parentNode;
		var menuElements = document.getElementById(Parent).getElementsByTagName('li');
		for(var i = 0; i < menuElements.length; i++) {
			if(menuItem != menuElements[i]) {
				if(menuElements[i].onblur) {
					menuElements[i].onblur();
				}
			}
		}
	}
	
	this.setParent = function(p) {
		Parent = p;
		if(Tree) {
			document.getElementById(Parent).appendChild(Tree);
		}
	}
}
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

OpenLayers.Control.ScaleJumper = OpenLayers.Class(OpenLayers.Control, {
    
    element: null,

    initialize: function(options) {
    	if(options.target) {
		this.element = document.getElementById(options.target);
		this.div = this.element;
	}
        OpenLayers.Control.prototype.initialize.apply(this, arguments);
    },

    destroy: function() {
         if (this.map) {
             this.map.events.unregister('moveend', this, this.redraw);
         }
         OpenLayers.Control.prototype.destroy.apply(this, arguments);
     },

    draw: function() {
        OpenLayers.Control.prototype.draw.apply(this, arguments);

        if (!this.element) {
            this.element = this.div;
        }

	var span = document.createElement('span');
	span.className = 'scale-jumper-text';
	this.element.appendChild(span);
	span.appendChild(document.createTextNode('Scale: '));

	var select = document.createElement('select');
	this.element.appendChild(select);

	select.appendChild(document.createElement('option'));
	var enter = document.createElement('option');
	enter.value = 'enter-scale';
	select.appendChild(enter);
	enter.appendChild(document.createTextNode('Enter Scale...'));
	for(var e in CONFIGURATION.jumpto_scales) {
		var opt = document.createElement('option');
		opt.value = CONFIGURATION.jumpto_scales[e];
		select.appendChild(opt);
		opt.appendChild(document.createTextNode(e));
	}

	select.map = this.map;
	select.className = 'scale-jumper-select';
	select.onchange = function () {
		var opt = this.options[this.selectedIndex].value;
		if(opt == 'enter-scale') {
			var scale = prompt('Enter a scale:', this.map.getScale());
			this.map.zoomToScale(parseInt(scale), !CONFIGURATION.fractional_zoom);
		} else if(opt == 'current-scale') {
			// Do nothing ... no need to move.
		} else {
			this.map.zoomToScale(parseInt(opt), !CONFIGURATION.fractional_zoom);
		}
		for(var i = 0; i < this.options.length; i++) {
			this.options[i].selected = false;
		}
		this.options[0].selected = true;
	}
        
        this.redraw();
        return this.div;
    },

    /**
     * Method: redraw  
     */
    redraw: function(evt) {
	var opt = this.element.getElementsByTagName('option')[0];
	opt.innerHTML = '1:'+parseInt(this.map.getScale());
    },

    /** 
     * Method: setMap
     */
    setMap: function() {
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
        this.map.events.register( 'moveend', this, this.redraw);
    },     

    CLASS_NAME: "OpenLayers.Control.ScaleJumper"
});
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/


function ServiceManager(Catalog, ParentId) {
	var MySelf = this;
	
	function getService(serviceName) {
		var services = Catalog.getElementsByTagName('service');
		for(var i = 0; i < services.length; i++) {
			if(services[i].getAttribute('name') == serviceName) {
				return services[i];
			}
		}
		return null;
	}

	function renderInputStep(step, parentId, settingsObj) {
		var inputs = step.getElementsByTagName('input');
		var nUserInputs = 0;

		var headers = step.getElementsByTagName('header');
		var p = document.getElementById(parentId);

		for(var i = 0; i < headers.length; i++) {	
			var span = document.createElement('span');
			p.appendChild(span);
			span.className = 'service-header';
			span.innerHTML = combineTextNodes(headers[i]);
		}

		for(var i = 0; i < inputs.length; i++) {
			var inputType = new String(inputs[i].getAttribute('type')).toLowerCase();
			var inputName = new String(inputs[i].getAttribute('name'));
			if(InputTypes[inputType]) {
				if(settingsObj) {
					nUserInputs += InputTypes[inputType](parentId, inputs[i], settingsObj[inputName]);
				} else {
					nUserInputs += InputTypes[inputType](parentId, inputs[i], undefined);
				}
			}
		}

		var footnotes = step.getElementsByTagName('footnote');
		var p = document.getElementById(parentId);
		for(var i = 0; i < footnotes.length; i++) {	
			var span = document.createElement('span');
			p.appendChild(span);
			span.className = 'service-footnote';
			span.innerHTML = combineTextNodes(footnotes[i]);
		}
		return nUserInputs;
	}

	function onAddFeature(f) {
		/* Clear the layer */
		while(this.layer.features.length > 0) {
			this.layer.removeFeatures(this.layer.features[0]);
		}
		this.layer.addFeatures(f);

		/* Store the WKT of the feature */
		var parser = new OpenLayers.Format.WKT();
		var str = parser.write(f);
		this.xml.setAttribute('wkt', str);

		var OutputFormat = OpenLayers.Format.WKT;
		var outputType = new String(this.xml.getAttribute('format')).toLowerCase();
		if(outputType == 'kml') {
			OutputFormat = OpenLayers.Format.KML;
		} else if(outputType == 'wfs') {
			OutputFormat = OpenLayers.Format.WFS;
		} else if(outputType == 'json') {
			OutputFormat = OpenLayers.Format.JSON;
		} else if(outputType == 'delim') {
			OutputFormat = OpenLayers.Format.Text;
		}
		var output = new OutputFormat();

		var inputs = this.xml.getElementsByTagName('input');

		/* Remove the old input */
		var stepName = this.xml.getAttribute('name');
		for(var i = 0; i < inputs.length; i++) {
			if(inputs[i].getAttribute('name') == stepName) {
				this.xml.removeChild(inputs[i]);
			}
		}

		var input = Catalog.createElement('input');
		input.setAttribute('name', stepName);
		input.appendChild(Catalog.createCDATASection(output.write(f)));
		this.xml.appendChild(input);

		if(parseBoolean(this.xml.getAttribute('jump-start'), false)) {
			MySelf.callService(this.xml.parentNode.getAttribute('name'));
		}
	}

	function changeDrawingTool() {
		/* This code is needed because IE is stupid */
		if(this.type == 'radio') {
			var inputs = this.parentNode.getElementsByTagName('input');
			for(var i = 0; i < inputs.length; i++) {
				if(inputs[i].name == this.name) {
					inputs[i].checked = false;
				}
			}
			this.checked = true;
		}
		if(this.value) {
			for(var t in Tools) {
				Tools[t].deactivate();
			}
			if(Tools[this.value]) {
				Tools[this.value].activate();
				if(Tools[this.value].featureAdded) {
					Tools[this.value].featureAdded = onAddFeature;
				} else {
					Tools[this.value].onModificationEnd = onAddFeature;
				}
				Tools[this.value].xml = this.xml;
			}	
		}
	}

	function renderSpatialStep(step, parentId, settingsObj) {
		/* Restore preview drawing */
		var wkt = false;
		var wktFormat = false;
		if(settingsObj && settingsObj[step.getAttribute('name')]) {
			wkt = settingsObj[step.getAttribute('name')];
			wktFormat = true;
		} else if(step.getAttribute('wkt')) {
			wkt = step.getAttribute('wkt');
			if(!step.getAttribute('format') || step.getAttribute('format').toLowerCase() == 'wkt') {
				wktFormat = true;
			}
		}


		var parser = new OpenLayers.Format.WKT();
		if(wkt) {
			Map.getLayersByName('/drawinglayer')[0].addFeatures(parser.read(wkt));

			var inputs = step.getElementsByTagName('input');
			var input = false;
			for(var i = 0; i < inputs.length; i++) {
				if(inputs[i].getAttribute('name') == step.getAttribute('name')) {
					input = inputs[i];
				}
			}
			if(wktFormat) {
				if(input) {
					step.removeChild(input);
				}
				var input = Catalog.createElement('input');
				input.setAttribute('name', step.getAttribute('name'));
				input.appendChild(Catalog.createCDATASection(wkt));
				step.appendChild(input);
			}
		}
		var p = document.getElementById(parentId);
		p.appendChild(document.createTextNode('Available Tools: '));
		p.appendChild(document.createElement("br"));

		/* Maybe I should move this into configuration ... maybe ... */
		var tools = {
			'pan' : {
				'status' : true,
				'title': 'Navigate'
			}, 
			'edit-polygon' : {
				'status' : false,
				'title' : 'Edit Polygon'
			},
			'point' : {
				'status' : true,
				'title' : 'Draw Point'
			}, 
			'line' : {
				'status' : true,
				'title' : 'Draw Line'
			}, 
			'polygon' : {
				'status' : true,
				'title' : 'Draw Polygon'
			}
		};
		for(var v in tools) {
			if(parseBoolean(step.getAttribute(v), tools[v]['status'])) {
				var radio = document.createElement('input');
				radio.name = 'drawing-tools';
				radio.type = 'radio';
				radio.value = v;
				radio.onclick = changeDrawingTool;
				radio.xml = step;
				p.appendChild(radio);
				p.appendChild(document.createTextNode(tools[v].title));
				p.appendChild(document.createElement('br'));
			}
		}

		if(step.getAttribute('default')) {
			var def = step.getAttribute('default');
			var inputs = p.getElementsByTagName('input');
			for(var input = 0; input < inputs.length; input++) {
				if(inputs[input].name == 'drawing-tools' && inputs[input].value == def) {
					inputs[input].onclick();
				}
			}
		}

		p.appendChild(document.createElement('br'));
		/* return the number of inputs, since the spatial step is one,
			include it in the cound */
		return 1+renderInputStep(step, parentId, settingsObj);
	}

	this.onStart = function(service) {
		/* Override */
	}

	this.onFinish = function() {
		/* Override */
	}

	function changeStep() {
		var panel = document.getElementById(this.step);
		var panels = document.getElementsByTagName('div');
		for(var i = 0; i < panels.length; i++) {
			if(panels[i].className == 'service-step-visible') {
				panels[i].className = 'service-step-hidden';
			}
		}
		panel.className = 'service-step-visible';

		cleanupService();
	}

	function cleanupService() {
		for(var t in Tools) {
			Tools[t].deactivate();
		}

		var drawingLayer = Map.getLayersByName('/drawinglayer')[0];
		while(drawingLayer.features.length > 0) {
			drawingLayer.removeFeatures(drawingLayer.features[0]);
		}

	}

	function cancelService() {
		/* Clear out Service HTML I*/
		var p = document.getElementById(ParentId);	
		p.innerHTML = '';

		cleanupService();
		Tabs.showTab(CONFIGURATION.default_tab);
	}

	this.startService = function(serviceName, settingsObj, forceStart) {
		var service = getService(serviceName);
		if(service) {
			this.onStart(service);
			var p = document.getElementById(ParentId);
			p.innerHTML = '';

			var titleSpan = document.createElement('span');
			titleSpan.className = 'service-title';
			if(service.getAttribute('title')) {
				titleSpan.innerHTML = service.getAttribute('title');
				p.appendChild(titleSpan);
			}

			var steps = service.getElementsByTagName('step');
			/* No "steps" */

			var nInputs = 0;
			var submitParent = ParentId;
			if(steps.length == 0) {
				nInputs += renderInputStep(service, ParentId, settingsObj);
			} else {
				var rootName = 'service-';
				for(var i = 0; i < steps.length; i++) {
					var stepType = new String(steps[i].getAttribute('type')).toLowerCase();
					var div = document.createElement('div');
					if(i > 0) {
						div.className = 'service-step-hidden';
					} else {
						div.className = 'service-step-visible';
					}
					div.id = rootName + i;
					p.appendChild(div);

					if(stepType == 'input') {
						nInputs += renderInputStep(steps[i], div.id, settingsObj);
					} else if(stepType == 'select' || stepType == 'spatial') {
						nInputs += renderSpatialStep(steps[i], div.id, settingsObj);
					}
					var table = document.createElement('table');
					table.width = '95%';
					var tbody = document.createElement('tbody');
					div.appendChild(table);
					table.appendChild(tbody);

					var tr = document.createElement('tr');
					tbody.appendChild(tr);

					var left = document.createElement('td');
					left.align = 'left';
					tr.appendChild(left);

					var right = document.createElement('td');
					right.align = 'right';
					tr.appendChild(right);

					right.id = rootName + '-right-' + i;

					if(i > 0) {
						var prevButton = document.createElement('input');
						prevButton.value = 'Back';
						prevButton.type = 'button';
						left.appendChild(prevButton);
						prevButton.className = 'service-button-back';

						prevButton.step = rootName + (i-1);
						prevButton.onclick = changeStep;
					} else {
						var cancelButton = document.createElement('input');
						cancelButton.type = 'button';
						cancelButton.value = 'Cancel';
						left.appendChild(cancelButton);
						cancelButton.className = 'service-button-back';
						cancelButton.onclick = cancelService;
					}
					if(i < steps.length - 1) {
						var nextButton = document.createElement('button');
						nextButton.innerHTML = 'Next';
						right.appendChild(nextButton);
						nextButton.className = 'service-button-next';

						nextButton.step = rootName + (i+1);
						nextButton.onclick = changeStep;
					}
				}
				submitParent = rootName + '-right-' + (steps.length - 1);
			}
			var buttonTitle = service.getAttribute('submit');
			if(!buttonTitle) {
				buttonTitle = 'Go!';
			}

			var button = document.createElement('button');
			button.id = 'submit-service';
			button.setAttribute('service-name', serviceName);
			button.innerHTML = buttonTitle;
			button.onclick = function () {
				MySelf.callService(this.getAttribute('service-name'));	
			}
			var buttonParent = document.getElementById(submitParent);
			buttonParent.appendChild(button);
			if(nInputs <= 0 || forceStart) {
				button.onclick();
			}


		} else {
			alert('Service with the name '+serviceName+' cannot be found');
		}
	}

	this.callService = function(serviceName, values) {
		var service = getService(serviceName);
		var inputs = service.getElementsByTagName('input');
		var url = combineTextNodes(service.getElementsByTagName('url')[0]);
		var params = '?';
		for(var i = 0; i < inputs.length; i++) {
			var name = inputs[i].getAttribute('name');
			var v = '';
			if(inputs[i].getAttribute('value')) {
				v = inputs[i].getAttribute('value');
			} else {
				var testV = combineTextNodes(inputs[i]);
				if(testV != undefined) {
					v = escape(testV);
				}
			}
			if(values && values[name]) {
				v = values[name];
			}
			params += '&' + name + '=' + v;
		}

		/** Clear out the old spatial stuff **/
		var drawingTools = ['point','line','polygon'];
		for(var d = 0; d < drawingTools.length; d++) {
	//		Tools[drawingTools[d]].deactivate();
		}

		var drawingLayer = Map.getLayersByName('/drawinglayer')[0];
		while(drawingLayer.features.length > 0) {
			drawingLayer.removeFeatures(drawingLayer.features[0]);
		}
		
		OpenLayers.loadURL(url, params, MySelf, MySelf.onServiceReturn);	
		MySelf.onFinish();
	}

	this.onServiceReturn = function (response) {
		/* Override */
		if(response.responseText) {
			document.getElementById('results-tab').innerHTML = response.responseText;
		}
	}

	this.initialize = function() {
		if(CONFIGURATION.startup_service) {
			this.startService(CONFIGURATION.startup_service);
		}
	}

	var InputTypes = new Array();

	function combineTextNodes(node) {
/*		var s = new String();
		for(var i = 0; i < node.childNodes.length; i++) {
			if(node.childNodes[i].nodeName == '#text'
				|| node.childNodes[i].nodeName == '#cdata-section') {
				s += node.childNodes[i].nodeValue;
			}
		}*/
		return OpenLayers.Util.getXmlNodeValue(node);
	}

	function clearChildren(node) {
		while(node.childNodes.length > 0) {
			node.removeChild(node.childNodes[0]);
		}
	}

	function updateServiceSetting() {
		var node = this.xml;
		var currentValue = combineTextNodes(node);

		clearChildren(node);
		node.appendChild(Catalog.createCDATASection(this.value));
	}

	function keyCallService(event) {
		if(window.event) { event = window.event; }
		var keyCode = null;
		if(event.which) {
			keyCode = event.which;
		} else if(event.keyCode) {
			keyCode = event.keyCode;
		}
		if(keyCode == 13) {
			this.onchange();
			document.getElementById('submit-service').onclick();
		}
	}

	InputTypes['user'] = function(inputParent, input, value) {
		var p = document.getElementById(inputParent);
		var inputParent = document.createElement('span');
		inputParent.className = 'service-input-parent';
		p.appendChild(inputParent);

		var i = document.createElement('input');
		i.className = 'service-input';
		i.xml = input;
		i.id = 'service-input-'+input.getAttribute('name');
		
		var xmlValue = combineTextNodes(input);
		if(xmlValue != undefined) {
			i.value = xmlValue;
		}
		if(value != undefined) {
			i.value = value;
		/*	input.setAttribute('value', value);*/
			clearChildren(input);
			input.appendChild(Catalog.createCDATASection(value));
		}
		i.onchange = updateServiceSetting;
		i.onkeypress = keyCallService;

		var title = document.createElement('span');
		title.className = 'service-input-title';
		inputParent.appendChild(title);
		title.innerHTML = input.getAttribute('title');
		inputParent.appendChild(i);
		return 1;	/* 1 = requires user input */

	}

	InputTypes['hidden'] = function(inputParent, input, value) {
		if(value != undefined) {
			clearChildren(input);
			input.appendChild(Catalog.createCDATASection(value));
		}
		return 0;
	}

	InputTypes['visiblelayers'] = function(inputParent, input, value) {
		var services = Catalog.getElementsByTagName('map-source');
		var layersList = new Array();
		for(var i = 0; i < services.length; i++) {
			var root = services[i].getAttribute('name');
			var layers = services[i].getElementsByTagName('layer');
			for(var l = 0; l < layers.length; l++) {
				if(parseBoolean(layers[l].getAttribute('visible'))) {
					var n = layers[l].getAttribute('name');
					layersList.push(root+'/'+n);
				}
			}
		}
		var delim = ':';
		if(input.getAttribute('delim')) {
			delim = input.getAttribute('delim');
		}
		clearChildren(input);
		input.appendChild(Catalog.createCDATASection(layersList.join(delim)));
		return 0; /* 0 = no user input required */
	}

	InputTypes['print_info'] = function(inputParent, input, value) {
		//input.appendChild(Catalog.createCDATASection(getPrintRequest()));
		var info = getPrintRequest(); /* returns an object with all the inputs needed for a print */
		var inputs = input.parentNode.getElementsByTagName('input');
		var p = input.parentNode;
		
		for(var i = inputs.length -1; i >= 0; i--) {
			if(inputs[i] != input) {
				p.removeChild(inputs[i]);
			}
		}

		for(var i in info) {
			var ipt = Catalog.createElement('input');
			p.appendChild(ipt);
			ipt.setAttribute('name', i);
			ipt.setAttribute('type', 'hidden');
			ipt.appendChild(Catalog.createCDATASection(info[i]));
			//console.log(i, info[i]);
		}
		return 0;
	}

	InputTypes['select'] = function(inputParent, input, value) {
		var p = document.getElementById(inputParent);
		var inputParent = document.createElement('span');
		inputParent.className = 'service-input-parent';
		p.appendChild(inputParent);

		var i = document.createElement('select');
		i.xml = input;

		var title = document.createElement('span');
		title.className = 'service-input-title';
		inputParent.appendChild(title);
		title.innerHTML = input.getAttribute('title');
		inputParent.appendChild(i);

		var opts = input.getElementsByTagName('option');
		var selIndex = 0;
		var selectValue =  input.getAttribute('value');

		if(value != undefined) { selectValue = value; }
		for(var o = 0; o < opts.length; o++) {
			var opt = document.createElement('option');
			opt.value = opts[o].getAttribute('value');
			i.appendChild(opt);
			if(opt.value == selectValue) {
				opt.selected = true;
				selIndex = 0;
			}
			var labelValue = combineTextNodes(opts[o]);
			if(labelValue) {
				opt.appendChild(document.createTextNode(labelValue));
			}
		}


		i.onchange = function() {
			var opts = this.getElementsByTagName('option');
		/*	clearChildren(this.xml);
			this.xml.appendChild(Catalog.createCDATASection(opts[this.selectedIndex].value));*/
			this.xml.setAttribute('value', opts[this.selectedIndex].value);
		}

		i.onchange();

		return 1;
	}

}
/*
Copyright (c) 2009, Dan "Ducky" Little & GeoMOOSE.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*
 * GeoMOOSE 2.0 Tab Manager
 */

function GeomooseTabs(tabStrip) {
	var elementCounter = 0;

	function getElementId() {
		elementCounter++;
		return 'tabs-'+elementCounter;
	}

	function onTabClick() {
		var p = document.getElementById(tabStrip);
		var tabs = p.getElementsByTagName('span');
		for(var i = 0; i < tabs.length; i++) {
			if(tabs[i].className.match(/tab/)) {
				tabs[i].className = 'tab';
				var e = document.getElementById(tabs[i].value);
				e.className = e.className.replace('tab-visible','tab-hidden');
			}
		}
		this.className = 'tab tab-selected';

		var e = document.getElementById(this.value);
		e.className = e.className.replace('tab-hidden','tab-visible');
	}


	this.initialize = function() {
		var p = document.getElementById(tabStrip);
		p.className += ' tab-strip';
		for(var v in CONFIGURATION.tabs) {
			var span = document.createElement('span');
			span.className = 'tab';
			p.appendChild(span);
			span.id = 'tab-'+v;
			span.appendChild(document.createTextNode(v));
			span.onclick = onTabClick;
			span.value = CONFIGURATION.tabs[v];

			p.appendChild(document.createTextNode(' '));
			var tab = document.getElementById(CONFIGURATION.tabs[v]);
			tab.className += ' tab-hidden';
		}
		if(CONFIGURATION.default_tab) {
			document.getElementById('tab-'+CONFIGURATION.default_tab).onclick();
		}
	}


	this.showTab = function(tabName) {
		var tab = document.getElementById('tab-'+tabName);
		tab.onclick();
	}

	this.getTab = function(tabName) {
		return CONFIGURATION.tabs[tabName];
	}

}
// Library to convert between NAD83 Lat/Lon and US National Grid
// Based on the FGDC-STS-011-2001 spec at http://www.fgdc.gov/standards/projects/FGDC-standards-projects/usng/fgdc_std_011_2001_usng.pdf
// Also based on the UTM library already in GeoMOOSE
// By Jim Klassen 4/2008
// (c)2008 City of Saint Paul released under the City of Saint Paul Open Source License

function UTM() {
	
	// Functions to convert between lat,lon and utm. Derived from visual basic
	// routines from Craig Perault. This assumes a NAD83 datum.
	
	// constants
	var MajorAxis = 6378137.0;
	var MinorAxis = 6356752.3;
	var Ecc = (MajorAxis * MajorAxis - MinorAxis * MinorAxis) / (MajorAxis * MajorAxis);
	var Ecc2 = Ecc / (1.0 - Ecc);
	var K0 = 0.9996;
	var E4 = Ecc * Ecc;
	var E6 = Ecc * E4;
	var degrees2radians = Math.PI / 180.0;
	
	// Computes the meridian distance for the GRS-80 Spheroid.
	// See equation 3-22, USGS Professional Paper 1395.
	function meridianDist(lat) {
		var c1 = MajorAxis * (1 - Ecc / 4 - 3 * E4 / 64 - 5 * E6 / 256);
		var c2 = -MajorAxis * (3 * Ecc / 8 + 3 * E4 / 32 + 45 * E6 / 1024);
		var c3 = MajorAxis * (15 * E4 / 256 + 45 * E6 / 1024);
		var c4 = -MajorAxis * 35 * E6 / 3072;
		
		return(c1 * lat + c2 * Math.sin(lat * 2) + c3 * Math.sin(lat * 4) + c4 * Math.sin(lat * 6));
	}
	
	// Convert lat/lon (given in decimal degrees) to UTM, given a particular UTM zone.
	this.fromLatLong = function(zone, latlon) {
		var utm = new OpenLayers.Geometry.Point();
		
		var centeralMeridian = -((30 - zone) * 6 + 3) * degrees2radians;
		
		var lat = latlon.y * degrees2radians;
		var lon = latlon.x * degrees2radians;
		
		var latSin = Math.sin(lat);
		var latCos = Math.cos(lat);
		var latTan = latSin / latCos;
		var latTan2 = latTan * latTan;
		var latTan4 = latTan2 * latTan2;
		
		var N = MajorAxis / Math.sqrt(1 - Ecc * (latSin*latSin));
		var c = Ecc2 * latCos*latCos;
		var a = latCos * (lon - centeralMeridian);
		var m = meridianDist(lat);
		
		var temp5 = 1.0 - latTan2 + c;
		var temp6 = 5.0 - 18.0 * latTan2 + latTan4 + 72.0 * c - 58.0 * Ecc2;
		var temp11 = Math.pow(a, 5);
		
		utm.x = K0 * N * (a + (temp5 * Math.pow(a, 3)) / 6.0 + temp6 * temp11 / 120.0) + 500000;
		
		var temp7 = (5.0 - latTan2 + 9.0 * c + 4.0 * (c*c)) * Math.pow(a,4) / 24.0;
		var temp8 = 61.0 - 58.0 * latTan2 + latTan4 + 600.0 * c - 330.0 * Ecc2;
		var temp9 = temp11 * a / 720.0;
		
		utm.y = K0 * (m + N * latTan * ((a * a) / 2.0 + temp7 + temp8 * temp9))
			
			return(utm);
	}
	
	function CSq(value) {
		return value*value;
	}
	
	// Convert UTM coordinates (given in meters) to Lat/Lon (in decimal degrees), given a particular UTM zone.
	this.toLatLong = function(zone, utm) {
		var latlon = new Point();
		
		var centeralMeridian = -((30 - zone) * 6 + 3) * degrees2radians;
		
		var temp1 = Math.sqrt(1.0 - Ecc);
		var ecc1 = (1.0 - temp1) / (1.0 + temp1);
		var ecc12 = ecc1 * ecc1;
		var ecc13 = ecc1 * ecc12;
		var ecc14 = ecc12 * ecc12;
		
		utm.x = utm.x - 500000.0;
		
		var m = utm.y / K0;
		var um = m / (MajorAxis * (1.0 - (Ecc / 4.0) - 3.0 * (E4 / 64.0) - 5.0 * (E6 / 256.0)));
		
		var temp8 = (1.5 * ecc1) - (27.0 / 32.0) * ecc13;
		var temp9 = ((21.0 / 16.0) * ecc12) - ((55.0 / 32.0) * ecc14);
		
		var latrad1 = um + temp8 * Math.sin(2 * um) + temp9 * Math.sin(4 * um) + (151.0 * ecc13 / 96.0) * Math.sin(6.0 * um);
		
		var latsin1 = Math.sin(latrad1);
		var latcos1 = Math.cos(latrad1);
		var lattan1 = latsin1 / latcos1;
		var n1 = MajorAxis / Math.sqrt(1.0 - Ecc * CSq(latsin1));
		var t2 = CSq(lattan1);
		var c1 = Ecc2 * CSq(latcos1);
		
		var temp20 = (1.0 - Ecc * CSq(latsin1));
		var r1 = MajorAxis * (1.0 - Ecc) / Math.sqrt(CSq(temp20) * temp20);
		
		var d1 = utm.x / (n1*K0);
		var d2 = CSq(d1);
		var d3 = d1 * d2;
		var d4 = CSq(d2);
		var d5 = d1 * d4;
		var d6 = CSq(d3);
		
		var t12 = CSq(t2);
		var c12 = CSq(c1);
		
		temp1 = n1 * lattan1 / r1;
		temp2 = 5.0 + 3.0 * t2 + 10.0 * c1 - 4.0 * c12 - 9.0 * Ecc2;
		temp4 = 61.0 + 90.0 * t2 + 298.0 * c1 + 45.0 * t12 - 252.0 * Ecc2 - 3.0 * c12;
		temp5 = (1.0 + 2.0 * t2 + c1) * d3 / 6.0;
		temp6 = 5.0 - 2.0 * c1 + 28.0 * t2 - 3.0 * c12 + 8.0 * Ecc2 + 24.0 * t12;
		
		latlon.y = (latrad1 - temp1 * (d2 / 2.0 - temp2 * (d4 / 24.0) + temp4 * d6 / 720.0)) * 180 / Math.PI;
		latlon.x = (centeralMeridian + (d1 - temp5 + temp6 * d5 / 120.0) / latcos1) * 180 / Math.PI;
		utm.x = utm.x + 500000.0;
		
		return (latlon);
	}
	
}

function USNG() {
	
	// Converts a lat, lon point (NAD83) into a USNG coordinate string
	// of precision where precision indicates the number of digits used
	// per coordinate (0 = 100,000m, 1 = 10km, 2 = 1km, 3 = 100m, 4 = 10m, ...)
	this.fromLatLong = function(latlong, precision) {
		usng_string = new String();
		var lon = latlong.x;
		var lat = latlong.y;
		
		//
		// Find Grid Zone Designation
		//
		var GZnumber;
		var GZletter;
		
		while(lon < -180) {
			lon += 180;
		}
		while(lon > 180) {
			lon -= 180;
		}
		// -180 = 180W is grid 1... increment every 6 degrees going east
		// Note [-180, -174) is in grid 1, [-174,-168) is 2, [174, 180) is 60 
		GZnumber = Math.floor((lon - (-180.0)) / 6.0) + 1;
		
		if(! ((lat > -90) && (lat < 90) )) {
			return('error lat'+lat +' must be between in (-90,90)... no playing at the poles, yet');
		} else {
			a = new Array();
			a = ['C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X'];
			GZletter = a[Math.floor((lat - (-80.0)) / 8)]; 
		}
		
		//
		// Find the correct UTM Zone (ok... this is sneaky... it = GZnumber N or S)
		//
		
		var utm = new UTM();
		utm_pt = utm.fromLatLong(GZnumber, latlong);
		
		//
		// Now need to figure out which 100,000m grid square were in
		//
		var GridSq='';
		
		var GridSqSet = (GZnumber % 6);
		if(GridSqSet == 0) GridSqSet = 6;
	//	alert(GridSqSet);
		var NSLetters135 = ['A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V'];
		var NSLetters246 = ['F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','A','B','C','D','E'];
		
		var EWLetters14 = ['A','B','C','D','E','F','G','H'];
		var EWLetters25 = ['J','K','L','M','N','P','Q','R'];
		var EWLetters36 = ['S','T','U','V','W','X','Y','Z'];
		
		var GridEIdx = Math.floor(utm_pt.x / 100000) - 1; //(should be [100000,9000000])
		var GridNIdx = Math.floor((utm_pt.y%2000000) / 100000);
	//	alert(utm_pt.x +','+ utm_pt.y)
	//	alert(GridEIdx + ','+ GridNIdx);
		switch(GridSqSet) {
			case 1:
				GridSq = EWLetters14[GridEIdx] + NSLetters135[GridNIdx];
				break;
			case 2:
				GridSq = EWLetters25[GridEIdx] + NSLetters246[GridNIdx];
				break;
			case 3:
				GridSq = EWLetters36[GridEIdx] + NSLetters135[GridNIdx];
				break;
			case 4:
				GridSq = EWLetters14[GridEIdx] + NSLetters246[GridNIdx];
				break;
			case 5:
				GridSq = EWLetters25[GridEIdx] + NSLetters135[GridNIdx];
				break;
			case 6:
				GridSq = EWLetters36[GridEIdx] + NSLetters246[GridNIdx];
				break;
			default:
				alert("shouldn't get here");
		}

		
		// Calc Easting and Northing integer to 100,000s place
		var Easting = Math.floor(utm_pt.x % 100000).toString();
		var Northing = Math.floor(utm_pt.y % 100000).toString();
		
		while(Easting.length < 5) Easting = '0' + Easting;
		while(Northing.length < 5) Northing = '0' + Northing;
		
		// Add on any fractional digits, no '.'... this is flaky yet use toFixed(precision-6)?
		//Easting = Easting + ((utm_pt.x % 100000) - Math.floor(utm_pt.x % 100000)).toString();
		//Northing = Northing + ((utm_pt.y % 100000) - Math.floor(utm_pt.y % 100000)).toString();
		
		Easting = Easting.substr(0, precision);
		Northing = Northing.substr(0, precision);
		
		//usng_string = "UTM " + utm_pt.x + "," + utm_pt.y + "   " + String(GZnumber) + GZletter + GridSq + Easting + ' '+ Northing; 
		usng_string = String(GZnumber) + GZletter + GridSq + Easting + Northing; 
		return(usng_string);
	}
	
	
}

