/*
 * Cross browser compatibility utility fuctions.
 */
function otmAttachEvent(elm, eventType, fn) {
	if(elm.attachEvent) {
		elm.attachEvent('on'+eventType, fn);
	} else if(elm.addEventListener) {
		elm.addEventListener(eventType, fn, false);
	}
}

function otmRemoveEvent(elm, eventType, fn) {
	if(elm.detachEvent) {
		elm.detachEvent('on'+eventType, fn);
	} else if (elm.removeEventListener) {
		elm.removeEventListener(eventType, fn, false);
	}
}
 function lineLength(a,b) {
    	var lenX = a.x - b.x;
	var lenY = a.y - b.y;
	return Math.sqrt(Math.pow(lenX,2) + Math.pow(lenY,2));
    }


var Colors = ['#ff0000','#00ff00','#0000ff','#ff00ff','#ff0','#0ff'];
var CurrentColor = 0;
var CurrentBorderColor = 0;

function getColor() {
	var color = Colors[CurrentColor];
	CurrentColor++; 
	if(CurrentColor >= Colors.length) {
		CurrentColor = 0;
		CurrentBorderColor++;
	}
	return color;
}

function getBorderColor() {
//	CurrentBorderColor++;
	if(CurrentBorderColor >= Colors.length) {
		CurrentBorderColor = 0;
	}
	var color = Colors[CurrentBorderColor];
	return color;
}


function addClass(object, newClassName) {
	var classNameString = new String(object.className);
	if(!classNameString.match(newClassName)) {
		classNameString+=' '+newClassName;
		object.className = classNameString;
	}
}

function removeClass(object, oldClassName) {
	if(object.className) {
		var classNameString = new String(object.className);
		classNameString = classNameString.replace(' '+oldClassName,'','g');
		classNameString = classNameString.replace(oldClassName,'','g');
		object.className = classNameString;
	}
}


function parseBoolean(s,undefined) {
	if (!undefined) undefined = false;
	if (!s) return undefined;
	s = s.toString().toLowerCase();
	return s == "true" || s == "yes" || parseInt(s) > 0;
}

function getSelectValue(id) {
	var select = document.getElementById(id);
	var values = new Array(); /* Create a CSV if more than one is selected */
	var opts = select.getElementsByTagName('option');
	for(var o = 0; o < opts.length; o++) {
		if(opts[o].selected) {
			values.push(opts[o].value);
		}
	}
	if(values.length > 1) {
		return values.join(",");
	} else {
		return values[0];
	}
}
function colorFeature(f,border,color) {
	var newStyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
	f.style = newStyle;
	if(border) {
		f.style['strokeColor'] = border;
	} else {
		f.style['strokeColor'] = getBorderColor();
	}
	if(color) {
		f.style['fillColor'] = color;
	} else {
		f.style['fillColor'] = getColor();
	}
	f.style['strokeWidth'] = '3px';
	if(f.layer) {
		f.layer.drawFeature(f);
	}
}


function Queue(length) {
	var q = new Array();

	this.setLength = function(l) {
		length = l;
	}

	this.getLength = function() {
		return length;
	}

	this.add = function(a) {
		q.push(a);
		if(q.length > length) {
			q.shift();
		}
	}

	this.get = function(i) {
		return q[i];
	}

	this.getAll = function() {
		return q;
	}

	this.bump = function(idx) {
		var newQ = new Array();
		for(var i = 0; i < q.length; i++) {
			if(i != idx) {
				newQ.push(q[i]);
			}
		}
		newQ.push(q[idx]);
		q = newQ;
	}
}

function openURL(uri, params, caller, onComplete, onFailure) {
	var success = (onComplete) ? OpenLayers.Function.bind(onComplete, caller)
				: OpenLayers.nullHandler;

	var failure = (onFailure) ? OpenLayers.Function.bind(onFailure, caller)
			   : OpenLayers.nullHandler;
	var req = null;
	if(params.length > 2000) {
		 req = new OpenLayers.Ajax.Request(uri, 
				     {   method: 'post',
					 /*parameters: params,*/
					 postBody: params,
					 onComplete: success, 
					 onFailure: failure,
					 contentType: 'application/x-www-form-urlencoded'
				      }
				     );
	} else {
		 req = new OpenLayers.Ajax.Request(uri+'?'+params, 
				     {   method: 'get',
					 parameters: params,
					 onComplete: success, 
					 onFailure: failure
				      }
				     );
	}
	return req;
}

/**
 * @requires Point.js
 * @requires OpenLayers/Geometry/Point.js
 * @requires OpenLayers/Geometry/LineString.js
 */

/**
 * Class: IncrementalPath
 * Handler to draw a path on the map, but does not draw it seamlessly, breaks
 * it up into smaller chunks.
 *
 * Inherits from:
 *  - <Path>
 */
OpenLayers.Handler.IncrementalPath = OpenLayers.Class(OpenLayers.Handler.Path, {
       
    /**
     * Method: addPoint
     * Add point to geometry.  Send the point index to override
     * the behavior of LinearRing that disregards adding duplicate points.
     */
    lastPoint: false,
    
    addPoint: function() {
        var startPoint = new OpenLayers.LonLat(this.lastPoint.x, this.lastPoint.y);
	var endPoint = new OpenLayers.LonLat(this.point.geometry.x, this.point.geometry.y);
	startPoint = this.map.getPixelFromLonLat(startPoint);
	endPoint = this.map.getPixelFromLonLat(endPoint);

    	if(!this.lastPoint || lineLength(startPoint, endPoint) > 20) {
		this.line.geometry.addComponent(this.point.geometry.clone(),
						this.line.geometry.components.length);
		this.callback("point", [this.point.geometry]);
		this.lastPoint = this.point.geometry.clone();
	}
    },
      
    CLASS_NAME: "OpenLayers.Handler.IncrementalPath"
});

/**
 * @requires Path.js
 * @requires OpenLayers/Geometry/Polygon.js
 */

/**
 * Class: IncrementalPolygon
 *
 * Inherits from:
 *  - IncrementalPath
 *  - <Path>
 *  - <
 */
OpenLayers.Handler.IncrementalPolygon = OpenLayers.Class(OpenLayers.Handler.IncrementalPath, {
    
    /**
     * Parameter: polygon
     * {<OpenLayers.Feature.Vector>}
     */
    polygon: null,

    /**
     * Constructor: Polygon
     * Create a Polygon Handler.
     *
     * Parameters:
     * control - {<OpenLayers.Control>} 
     * callbacks - {Object} An object with a 'done' property whos value is
     *                          a function to be called when the path drawing is
     *                          finished. The callback should expect to recieve a
     *                          single argument, the polygon geometry.
     *                          If the callbacks object contains a 'point'
     *                          property, this function will be sent each point
     *                          as they are added.  If the callbacks object contains
     *                          a 'cancel' property, this function will be called when
     *                          the handler is deactivated while drawing.  The cancel
     *                          should expect to receive a geometry.
     * options - {Object} 
     */
    initialize: function(control, callbacks, options) {
        OpenLayers.Handler.IncrementalPath.prototype.initialize.apply(this, arguments);
    },
    
    /**
     * Method: createFeature
     * Add temporary geometries
     */
    createFeature: function() {
        this.polygon = new OpenLayers.Feature.Vector(
                                        new OpenLayers.Geometry.Polygon());
        this.line = new OpenLayers.Feature.Vector(
                                        new OpenLayers.Geometry.LinearRing());
        this.polygon.geometry.addComponent(this.line.geometry);
        this.point = new OpenLayers.Feature.Vector(
                                        new OpenLayers.Geometry.Point());
    },

    /**
     * Method: destroyFeature
     * Destroy temporary geometries
     */
    destroyFeature: function() {
        OpenLayers.Handler.IncrementalPath.prototype.destroyFeature.apply(this);
        if(this.polygon) {
            this.polygon.destroy();
        }
        this.polygon = null;
    },

    /**
     * Method: modifyFeature
     * Modify the existing geometry given the new point
     * 
     */
    modifyFeature: function() {
        var index = this.line.geometry.components.length - 2;
        this.line.geometry.components[index].x = this.point.geometry.x;
        this.line.geometry.components[index].y = this.point.geometry.y;
        this.line.geometry.components[index].clearBounds();
    },

    /**
     * Method: drawFeature
     * Render geometries on the temporary layer.
     */
    drawFeature: function() {
        this.layer.drawFeature(this.polygon, this.style);
        this.layer.drawFeature(this.point, this.style);
    },

    /**
     * Method: geometryClone
     * Return a clone of the relevant geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.Polygon>}
     */
    geometryClone: function() {
        return this.polygon.geometry.clone();
    },

    /**
     * Method: dblclick
     * Handle double-clicks.  Finish the geometry and send it back
     * to the control.
     * 
     * Parameters:
     * evt - {Event} 
     */
    dblclick: function(evt) {
        if(!this.freehandMode(evt)) {
            // remove the penultimate point
            var index = this.line.geometry.components.length - 2;
            this.line.geometry.removeComponent(this.line.geometry.components[index]);
            this.finalize();
        }
        return false;
    },

    CLASS_NAME: "OpenLayers.Handler.IncrementalPolygon"
});



var NORTH_ARROW_INSTANCE = 0;
var NORTH_ARROW_CGI = './cgi-bin/northArrow.py'

function NorthArrow(arrowMap, parentId) {
	var myId = 'NorthArrow-'+NORTH_ARROW_INSTANCE;

	NORTH_ARROW_INSTANCE++;

	this.onNavigate = function() {
		var arrow = document.getElementById(myId+'-image');
		var mapext = arrowMap.getExtent();
		var extString = [mapext.left, mapext.bottom, mapext.right, mapext.top].join(' ');
		arrow.setAttribute('src',  NORTH_ARROW_CGI + '?mapext=' + extString);
	}

	this.init = function () {
		var p = document.getElementById(parentId);
		var img = document.createElement('img');
		img.id = myId+'-image';
		img.setAttribute('src',BLANK_IMAGE);
		img.setAttribute('width', 130);
		img.setAttribute('height', 130);
		p.appendChild(img);

		arrowMap.events.register('moveend', {}, this.onNavigate);
	}
}


var SCALEBAR_INSTANCE = 0;
var SCALEBAR_CGI = './cgi-bin/mapserv'
var SCALEBAR_MAP = '../../mapfiles/scalebar.map'

function Scalebar(scaleMap, parentId) {
	var myId = 'ScaleBar-'+SCALEBAR_INSTANCE;

	SCALEBAR_INSTANCE++;

	this.onNavigate = function() {
		var scalebar = document.getElementById(myId+'-image');
		var mapext = scaleMap.getExtent();
		var extString = [mapext.left, mapext.bottom, mapext.right, mapext.top].join(' ');
		scalebar.src =  SCALEBAR_CGI + '?mapext=' + extString 
			+ '&mapsize=' + scaleMap.size.w + ' ' + scaleMap.size.h 
			+ '&mode=scalebar'
			+ '&map=' + SCALEBAR_MAP;
	}

	this.init = function () {
		var p = document.getElementById(parentId);
		var img = document.createElement('img');
		img.id = myId+'-image';
		/*img.setAttribute('src',BLANK_IMAGE);*/
		p.appendChild(img);
		img.src = BLANK_IMAGE;

		scaleMap.events.register('zoomend', {}, this.onNavigate);
		scaleMap.events.register('moveend', {}, this.onNavigate);
	}
}

function GRINavigatorHistory(navMap) {

	var extents = new Array();
	var logExtent = true;
	
	function onMove() {
		if(logExtent && navMap.getExtent()) {
			var length = extents.push(navMap.getExtent());
			if(length >= NAVIGATION_HISTORY_MAX) {
				extents.shift();
			}
		}
		logExtent = true;
	}

	navMap.events.register('movestart', this, onMove);

	this.previousExtent = function () {
		logExtent = false;
		if(extents[0]) { /* So long as 1 is defined we can pop it */
			navMap.zoomToExtent(extents.pop());
		}
	}

}


/*
 * Manages the layers 
 */

function GRILayers(layerMap, layersListParentId, legendsParentId) {
	var layers = {}; /*new Array();*/

	var CheckboxPrefix = 'LayerList-';
	var LegendPrefix = 'LayerLegend-';

	var MySelf = this;

	this.onNavigate = function() {
	}

	/* Adds layer to the map, layer list */
	this.addLayer = function(layerXML) {
		
	}

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

	var titleControls = {};

	this.getLayer = function(layerName) {
		return layers[layerName];
	}

	this.getActiveLayers = function() {
		var activeLayers = new Array();
		for(var l in layers) {
			if(layers[l].active) {
				activeLayers.push(l);		
			}
		}
		return activeLayers;
	}

	this.renderLayerList = function(layersXML) {
		var p = document.getElementById(layersListParentId);
		var layersTable = document.createElement('table');
		layersTable.width = '100%';
		layersTable.setAttribute('cellspacing','0');
		layersTable.setAttribute('border','0');


		var layersTBody = document.createElement('tbody');

		p.appendChild(layersTable);
		layersTable.appendChild(layersTBody);

		var layerDisplay = layersXML.getElementsByTagName('layer-display')[0];
		var columnNames = layerDisplay.getElementsByTagName('column-names')[0];

		var columns = columnNames.getElementsByTagName('column');

		var titleRow = document.createElement('tr');
		layersTBody.appendChild(titleRow);

		for(var i = 0; i < columns.length; i++) {
			var th = document.createElement('th');
			th.id = 'LayerColumnTitles' + i;
			titleRow.appendChild(th);
			th.appendChild(document.createTextNode(columns[i].getAttribute('title')));
			if(columns[i].getAttribute('help')) {
				createHelpLink(th.id, columns[i].getAttribute('help'));
			}
		}

		var rowWidth = columns.length;

		var entry = layerDisplay.getElementsByTagName('list-entry');

		for(var i = 0; i < entry.length; i++) {
			var entryRow = document.createElement('tr');
			if(parseBoolean(entry[i].getAttribute('break'))) {
				/*var breakRow = document.createElement('tr');
				breakRow.className = 'BreakRow';

				var breakCell = document.createElement('td');
				layersTBody.appendChild(breakRow);
				breakRow.appendChild(breakCell);
				breakCell.appendChild(document.createElement('hr'));
				breakCell.setAttribute('colspan', rowWidth);*/
				entryRow.className = 'BreakRow';
			}
			if(entry[i].getAttribute('css')) {
				entryRow.style.cssText = entry[i].getAttribute('css');
			}
			layersTBody.appendChild(entryRow);

			var iconCell = document.createElement('td');
			entryRow.appendChild(iconCell);
			iconCell.innerHTML = '&nbsp;'; /* Place holder */

			
			var title = entry[i].getAttribute('title');
			var titleCell = document.createElement('td');
						titleCell.id = 'TitleCell-'+title;

			var titleObj = {
				'title' : title,
				'titleCell' : titleCell.id,
				'minscale' : 100000000,
				'maxscale' : 0
			}

			titleControls[title] = titleObj;


			entryRow.appendChild(titleCell);
			if(entry[i].getAttribute('href')) {
				var entryLink = document.createElement('a');
				titleCell.appendChild(entryLink);
				entryLink.appendChild(document.createTextNode(title));
				entryLink.setAttribute('href', entry[i].getAttribute('href'));
				entryLink.setAttribute('target', '_blank');
			} else {
				titleCell.appendChild(document.createTextNode(title));
			}

			var entryLayers = entry[i].getElementsByTagName('layer');
			for(var l = 0; l < entryLayers.length; l++) {
				var layerName = entryLayers[l].getAttribute('name');
				if(layers[layerName]) {
					if(layers[layerName].minscale < titleControls[title].minscale) {
						titleControls[title].minscale = layers[layerName].minscale;
					}

					if(layers[layerName].maxscale > titleControls[title].maxscale) {
						titleControls[title].maxscale = layers[layerName].maxscale;
					}
				}

				var layerCell = document.createElement('td');
				entryRow.appendChild(layerCell);
				var layerInput = document.createElement('input');
				layerInput.type = 'checkbox';
				layerCell.appendChild(layerInput);
				layerInput.value = layerName;

				var disabled = parseBoolean(entryLayers[l].getAttribute('locked'), false);

				var active = layers[layerInput.value] && layers[layerInput.value].active;

				/* XML Over-ride */
				if(entryLayers[l].getAttribute('active')) {
					active = parseBoolean(entryLayers[l].getAttribute('active'), false);
				}

				layerInput.checked = active;
				layerInput.disabled = disabled;
				layerInput.onclick = onLayerClick;
				/*layerInput.id = 'LayerTreeCheckbox-'+layerInput.value;*/
				layerInput.id = CheckboxPrefix+layerInput.value;

				if(layerInput.checked) {
					updateLegendImage(layerInput.value);
				}
			}
			if(titleControls[title].minscale > titleControls[title].maxscale) {
				var min = titleControls[title].minscale;
				titleControls[title].minscale = titleControls[title].maxscale;
				titleControls[title].maxscale = min;
			}

			try {
				var mscale = layerMap.getScale();
				if(mscale > titleControls[title].minscale 
					&& mscale < titleControls[title].maxscale) {

					titleCell.className = 'VisibleLayer';
				} else {
					titleCell.className = 'NonVisibleLayer';
				}
			} catch(e) {
				titleCell.className = 'VisibleLayer';
			}

		}

		/* Display a helper message about the layers below */
		p.appendChild(document.createElement('br'));
		var metadataCenter = document.createElement('center');
		p.appendChild(metadataCenter);
		var metadataLink = document.createElement('a');
		metadataCenter.appendChild(metadataLink);
		metadataLink.appendChild(document.createTextNode('OnTheMap Version 3 Geographic Sources'));
		metadataLink.href = '#';
		metadataLink.setAttribute('value', 'geo');
		metadataLink.onclick = openHelp;

		p.appendChild(document.createElement('br'));
		var italics = document.createElement('i');
		p.appendChild(italics);
		italics.appendChild(document.createTextNode('When a layer name is grayed and italicized, it is unavailable at the current zoom level.'));
	}

	this.showDrawingLayer = function () {
		this.DrawingLayer.setVisibility(true);
		
	}

	var AnimationId = 0;
	
	function animateOverlay(animationFrames, currentFrame) {
		for(var i = 0; i < animationFrames.length; i++) {
			var cell = animationFrames[i].length;
			for(var j = 0; j < cell; j++) {
				MySelf.setLayerVisibility(animationFrames[i][j], i == currentFrame);
			}
		}
		currentFrame++;
		if(currentFrame >= animationFrames.length) {
			currentFrame = 0;
		}
		AnimationId = setTimeout(function () {animateOverlay(animationFrames, currentFrame); }, ANIMATION_INTERVAL);
	}

	function stopOverlayAnimation() {
		clearTimeout(AnimationId);
	}

	this.stopAnimation = function () {
		stopOverlayAnimation();
	}
	
	this.animateOverlays = function() {
		var list = new Array();
		var first = document.getElementById(arguments[3]);
		var animate = true;
		if(first.disabled == true) {
			animate = false;
		}

		var animateButton = document.getElementById(arguments[0]);

		for(var i = 3; i < arguments.length; i++) {
			var box = document.getElementById(arguments[i]);
			box.disabled = animate;
			if(box.checked && animate) {
				list.push(box.value.split(','));
			}
		}
		if(animate) {
			animateButton.value = arguments[2];
			var animationFrames = list[0].length;
			var anim = new Array();
			for(var i = 0; i < animationFrames; i++) {
				var cell = new Array();
				for(var j = 0; j < list.length; j++) {
					cell.push(list[j][i]);
				}
				anim.push(cell);
			}
			AnimationId = setTimeout(function () {animateOverlay(anim, 0); }, ANIMATION_INTERVAL);
		} else {
			animateButton.value = arguments[1];
			stopOverlayAnimation();
		}
	}

	this.hideDrawingLayer = function () {
		this.DrawingLayer.setVisibility(false);

		var drawingTools = ['Draw Polygon', 'Draw Line', 'Draw Point', 'Modify Area', 'Draw Multipoint'];
		for(var i = 0; i < drawingTools.length; i++) {
			MapControls[drawingTools[i]].deactivate();
		}
		MySelf.clearDrawingLayerFeatures();
	}

	this.getDrawingLayer = function() {
		return this.DrawingLayer;
	}

	this.clearDrawingLayerFeatures = function () {
		this.DrawingLayer.removeFeatures(this.DrawingLayer.features);
	}

	this.setupDrawingLayer = function() {
		OpenLayers.Feature.Vector.style['default']['strokeWidth'] = '3';
	/*	OpenLayers.Feature.Vector.style['default']['strokeColor'] = '#FF0000';
		OpenLayers.Feature.Vector.style['default']['fillColor'] = '#440000';*/
		this.DrawingLayer = new OpenLayers.Layer.Vector('Drawing Layer');
		this.DrawingLayer.setVisibility(false); /* Not visible until drawing starts */
		layerMap.addLayer(this.DrawingLayer);

		/* Setup the drawing tools */
		MapControls['Modify Area'] = new OpenLayers.Control.ModifyFeature(this.DrawingLayer);
		MapControls['Drag Area'] = new OpenLayers.Control.DragFeature(this.DrawingLayer);
		MapControls['Remove Area'] = new OpenLayers.Control.SelectFeature(this.DrawingLayer);
		MapControls['Select Area'] = new OpenLayers.Control.SelectFeature(this.DrawingLayer);

		/* This needs to unselect the feature before it's removed,
			but I want the feature to be selected before the User clicks 'ok' */
		MapControls['Remove Area'].onSelect = function (feature) {
			if(confirm('Are you sure you want to remove this feature?')) {
				MapControls['Remove Area'].unselect(feature);
				this.DrawingLayer.removeFeatures([feature]);
			} else {
				MapControls['Remove Area'].unselect(feature);
			}
		}
		MapControls['Draw Polygon'] = new OpenLayers.Control.DrawFeature( this.DrawingLayer, 
				OpenLayers.Handler.IncrementalPolygon, {handlerOptions: {freehand: true}});

		MapControls['Draw Box'] = new OpenLayers.Control.DrawFeature(this.DrawingLayer, 
			OpenLayers.Handler.RegularPolygon,{handlerOptions: {sides: 4, irregular: true}});
			
		MapControls['Draw Line'] = new OpenLayers.Control.DrawFeature(this.DrawingLayer, 
			OpenLayers.Handler.IncrementalPath, {handlerOptions: {freehand: true}});

		MapControls['MultiPolyon'] = new OpenLayers.Control.SelectFeature(this.DrawingLayer, 
			{multiple: true});

		MapControls['Draw Point'] = new OpenLayers.Control.DrawFeature(this.DrawingLayer, 
			OpenLayers.Handler.Point);

		MapControls['Draw Multipoint'] = new OpenLayers.Control.DrawFeature(this.DrawingLayer, 
			OpenLayers.Handler.Point);
/*
		MapControls['Draw Multipoint'].events.register('activate', MapControls['Draw Multipoint'], function () { this.points = new Array(); });
		MapControls['Draw Multipoint'].events.register('deactivate', MapControls['Draw Multipoint'], function () { this.points = new Array(); });
*/		
		for(var c in MapControls) {
			layerMap.addControl(MapControls[c]);
		}
	}

	this.getOverlayLayers = function() {
		var overlayLayers = Array();
		for(var l in layers) {
			if(layers[l].overlay) {
				overlayLayers.push(l);
			}
		}
		return overlayLayers;
	}

	this.getInternalLayer = function(layerName) {
		return layers[layerName].mapLayer;
	}

	this.clearOverlays = function() {
		var overlayLayerNames = MySelf.getOverlayLayers();
		for(var i = 0; i < overlayLayerNames.length; i++) {
			MySelf.setLayerVisibility(overlayLayerNames[i], false);
		}

		/* This should clear any check boxes from a report return */
		var overlays = document.getElementById('OverlayControl');
		if(overlays) {
			var inputs = overlays.getElementsByTagName('input');
			for(var i = 0; i <inputs.length; i++) {
				if(inputs[i].type == 'checkbox') {
					inputs[i].checked = false;
				}
			}
		}
	}


	function createLegendImage(layerName) {
		if(layerName.indexOf(',') >= 0) {
			var layerNames = layerName.split(',');
			for(var i = 0; i < layerNames.length; i++) {
				if(layerNames[i]) {
					createLegendImage(layerNames[i]);
				}
			}
			return false;
		}

		var id = LegendPrefix+layerName;
		var elm = document.getElementById(id);
		if(!elm) {
			var p = document.getElementById(legendsParentId);
			var img = document.createElement('img');
			/*img.setAttribute('src', BLANK_IMAGE);*/
			if(p.firstChild) {
				p.insertBefore(img, p.firstChild);
			} else {
				p.appendChild(img);
			}
/*			img.onload = function () {
				if(this.clientWidth > 30 || this.naturalWidth > 30) {
					this.className = 'LegendImage';
				} else {
					this.className = 'LegendImageHidden';
				}
			}*/
			img.id = id;
			img.src = BLANK_IMAGE;
			img.className = 'LegendImageHidden';
		}
		return id;
	}

	function removeLegendImage(layerName) {
		if(layerName.indexOf(',') >= 0) {
			var layerNames = layerName.split(',');
			for(var i = 0; i < layerNames.length; i++) {
				if(layerNames[i]) {
					removeLegendImage(layerNames[i]);
				}
			}
			return false;
		}

		var img = document.getElementById(LegendPrefix+layerName);
		/*img.setAttribute('src', BLANK_IMAGE);*/
		img.src = BLANK_IMAGE;
		img.className = 'LegendImageHidden';
	}
	
	function updateLegendImage(layerName) {
		var layerNames = [layerName];
		if(layerName.indexOf(',') >= 0) {
			layerNames = layerName.split(',');
		}	
		for(var i = 0; i < layerNames.length; i++) {
			var img = document.getElementById(LegendPrefix+layerNames[i]);
			if(img && (!layerNames[i].match(/label/i) || SHOW_LABEL_LEGENDS)) {
				var map = layers[layerName].mapLayer;
				if(map instanceof OpenLayers.Layer.WMS) {
					var url = map.getFullRequestString();
					url = url.replace('REQUEST=GetMap','');
					url += '&REQUEST=GetLegendGraphic';
					url += '&LAYER=' + layerNames[i];
					url += '&SCALE=' + map.map.getScale(); 
					img.className = 'LegendImage';
					/*img.setAttribute('src', url);*/
					img.src = url;
				}
				
				if(map instanceof OpenLayers.Layer.MapServer) {
					var url = map.getURL(map.map.getExtent());
					url = url.replace('mode=map','mode=legend');
					url = url.replace(/layers=[A-Za-z0-9_ %]*&/,'layers='+layerNames[i]+'&');
					/*img.setAttribute('src', url);*/
					img.src = url;
					img.className = 'LegendImage';
				}
			}
		}
	}

	
	this.getLegendURLs = function() {
		var urls = new Array();
		for(var layerName in layers) {
			var img = document.getElementById(LegendPrefix+layerName);
			if(img && !img.src.match(BLANK_IMAGE)) {
				urls.push(img.src);
			}
			
		}
		return urls;
	}

	this.addLayerToMap = function(mapXML) {
		var mapLayers = mapXML.getElementsByTagName('layer');
		var layerType = mapXML.getAttribute('type').toLowerCase();
		var tiled = parseBoolean(mapXML.getAttribute('tile'));
		var active = parseBoolean(mapXML.getAttribute('active'), true);
		var basemap = parseBoolean(mapXML.getAttribute('isbasemap'));

		var overlay = parseBoolean(mapXML.getAttribute('overlay'), false);
		var overlayYear = parseInt(mapXML.getAttribute('overlay-year'));


		var layer = false;

		var defaultLayers = new Array();

		var layerOptions = {
			'units' : 'm'
		};

		var legendsToUpdate = new Array();

		for(var i = 0; i < mapLayers.length; i++) {
			var layerActive = active;
			if(active) {
				layerActive = parseBoolean(mapLayers[i].getAttribute('active'));
				if(layerActive) {
					var name = mapLayers[i].getAttribute('name');
					defaultLayers.push(name);
					legendsToUpdate.push(name);
				}
			}
		}

		/* add the layer parameters */
		var params = mapXML.getElementsByTagName('param');
		for(var i = 0; i < params.length; i++) {
			var name = params[i].getAttribute('name');
			var value = params[i].getAttribute('value');
			layerOptions[name] = value;
		}


		if(layerType == 'mapserver') {
			/* Allow the layer entry to specify a different mapserver
				than default. */
			var url = mapXML.getAttribute('url');
			layerOptions["layers"] = defaultLayers.join(' ');
			if(!url) {
				url = MAPSERVER_URL;
			}
			layer = new OpenLayers.Layer.MapServer(mapXML.getAttribute('title'),
				url,
				layerOptions,
				{reproject: false, isBaseLayer: basemap, singleTile: true, units: 'm'});
		} else if(layerType == 'wms') {
			//layerOptions["format"] = 'image/png';
			layerOptions["format"] = ImageType;
			layerOptions["layers"] = defaultLayers.join(',');
			layer = new OpenLayers.Layer.WMS(mapXML.getAttribute('title'),
				mapXML.getAttribute('url'),
				layerOptions,
				{reproject: false, isBaseLayer: basemap, singleTile: !tiled, units: 'm'});
		}


		var layerExists = false;
		var oldLayer = null;


		/* Check to see if we have a "single layer" layer */		
		if(mapLayers.length == 0) {
			var name = mapXML.getAttribute('name');

			var minscale = parseInt(mapXML.getAttribute('minscale'));
			var maxscale = parseInt(mapXML.getAttribute('maxscale'));
			var l = {
				'active' : active,
				'mapLayer' : layer,
				'singleLayer' : true,
				'overlay' : overlay,
				'year' : overlayYear,
				'minscale' : 0,
				'maxscale' : 1000000000
			};
			if(layers[name] && layers[name].mapLayer) {
				layerExists = true;
				oldLayer = layers[name].mapLayer
			}
			if(!isNaN(minscale)) { l.minscale = minscale;  }
			if(!isNaN(maxscale)) { l.maxscale = maxscale;  }
			layers[name] = l;
			createLegendImage(name);
			if(l.active) {
				legendsToUpdate.push(name);
			}
		} else {
			for(var i = 0; i < mapLayers.length; i++) {
				var layerActive = parseBoolean(mapLayers[i].getAttribute('active'), active);

				var minscale = parseInt(mapLayers[i].getAttribute('minscale'));
				var maxscale = parseInt(mapLayers[i].getAttribute('maxscale'));

				
				var name = mapLayers[i].getAttribute('name');
				var l = {
					'active' : layerActive,
					'mapLayer':  layer,
					'parent' : mapXML.getAttribute('name'),
					'singleLayer': false,
					'overlay' : overlay,
					'year' : overlayYear,
					'minscale' : 0,
					'maxscale' : 1000000000,
					'layerName' : name,
					'order' : i
				}
				if(!isNaN(minscale)) { l.minscale = minscale;  }
				if(!isNaN(maxscale)) { l.maxscale = maxscale;  }

				if(layers[name] && layers[name].mapLayer 
					&& layers[name].mapLayer.map && layers[name].parent == l.parent) {
					layerExists = true;
					oldLayer = layers[name].mapLayer
				}
				layers[name] = l;
				createLegendImage(name);
			}
			active = defaultLayers.length > 0;
		}

		if(mapXML.getAttribute('opacity')) {
			layer.setOpacity(parseFloat(mapXML.getAttribute('opacity')));
		}  

		if(layerExists) {
			var zindex = layerMap.getLayerIndex(oldLayer);
			layerMap.removeLayer(oldLayer);
			layerMap.addLayer(layer);
			layerMap.setLayerIndex(layer, zindex);
		} else {
			layerMap.addLayer(layer);
		}
		layer.setVisibility(active);
		for(var i = 0; i < legendsToUpdate.length; i++) {
			updateLegendImage(legendsToUpdate[i]);
		}
	}

	this.refreshLayerParameters = function(refreshLayerName) {
		var layer = layers[refreshLayerName];
		var change = false;
		if(layer.singleLayer) {
			change = layer.mapLayer.setVisibility(layer.active);
		} else {
			var delim = ',';
			var layersAttribute = 'LAYERS';
			if(layer.mapLayer instanceof OpenLayers.Layer.MapServer) {
				delim = ' ';
				layersAttribute = 'layers';
			}

			/* find all the layers with a matching "parent" */
			var siblings = new Array();
			for(var l in layers) {
				if(layers[l].parent == layer.parent) {
					siblings.push(layers[l]);
				}
			}
			/* Sort by visible order */
			for(var i = 0; i < siblings.length; i++) {
				for(j = i; j < siblings.length; j++) {
					if(siblings[i].order > siblings[j].order) {
						var t = siblings[j];
						siblings[j] = siblings[i];
						siblings[i] = t;
					}
				}
			}
			
			/* Build the new layers list */
			var activeSiblings = new Array();
			for(var i = 0; i < siblings.length; i++) {
				if(siblings[i].active) {
					activeSiblings.push(siblings[i].layerName);
				}
			}
			
			var newLayerList = activeSiblings.join(delim);

			change = (newLayerList != layer.mapLayer.params[layersAttribute]);
			if(change) {
				layer.mapLayer.params[layersAttribute] = newLayerList;
			}
		}
		return change;
	}

	function updateMap(map) {
		var ucLayers = map.params['LAYERS'];
		var lcLayers = map.params['layers'];
		if(ucLayers || lcLayers) {
			map.setVisibility(true);
			map.display();
			map.redraw();
		} else {
			map.setVisibility(false);
		}

	}

	this.refreshAllLayerParameters = function () {
		var mapsToUpdate = new Array();
		for(var l in layers) {
			if(this.refreshLayerParameters(l)) {
				mapsToUpdate[layers[l].mapLayer.name] = layers[l].mapLayer;
			}
		}

		for(var m in mapsToUpdate) {
			updateMap(m);
		}
	}

	this.addLayersToMap = function(layersXML) {
		var maps = layersXML.getElementsByTagName('map');
		var basemaps = new Array();
		var others = new Array();
		
		for(var m = 0; m < maps.length; m++) {
			/*this.addLayerToMap(maps[m]);*/
			var basemap = parseBoolean(maps[m].getAttribute('isbasemap'));
			if(basemap) {
				basemaps.push(maps[m]);
			} else {
				others.push(maps[m]);
			}
		}

		for(var i = 0; i < basemaps.length; i++) {
			this.addLayerToMap(basemaps[i]);
		}

		/* These need to be added "backwards" to correct the display order */
		for(var i = others.length - 1; i >= 0; i--) {
			this.addLayerToMap(others[i]);
		}

	}

	this.onLoaded = function () { }

	this.onLoadedLayers = function(req) {
		this.addLayersToMap(req.responseXML);
		this.renderLayerList(req.responseXML);
		this.setupDrawingLayer();

		this.onLoaded();
	}


	this.loadLayers = function(url) {
		OpenLayers.loadURL(url, "", this, this.onLoadedLayers);
	}

	this.setLayerVisibility = function(layerName, visibility) {
		layers[layerName].active = visibility;

		if(this.refreshLayerParameters(layerName)) {
			updateMap(layers[layerName].mapLayer);
		}

		if(visibility) {
			updateLegendImage(layerName);
		} else {
			removeLegendImage(layerName);
		}

		var checkbox = document.getElementById(CheckboxPrefix+layerName);
		if(checkbox) {
			checkbox.checked = visibility;
		}
	}

	this.updateAllLegends = function () {
		for(var l in layers) {
			if(layers[l].active) {
				updateLegendImage(l);
			}
		}
	}

	this.updateAllTitles = function () {
		var scale = layerMap.getScale();
		for(var t in titleControls) {
			var elm = document.getElementById(titleControls[t].titleCell);
			if(scale > titleControls[t].minscale &&
				scale < titleControls[t].maxscale) {
				elm.className = 'VisibleLayer';
			} else {
				elm.className = 'NonVisibleLayer';
			}	
		}
	}

	this.init = function() {
		Map.events.register('moveend', {}, this.updateAllLegends);
		Map.events.register('zoomend', {}, this.updateAllLegends);
		Map.events.register('zoomend', {}, this.updateAllTitles);
	}
}


var PREVIEW_MAP_INSTANCE = 0;

function PreviewMap(previewParent, previewShape) {
	var id = 'PreviewMap-'+PREVIEW_MAP_INSTANCE;
	var previewMap;
	var previewLayer;
	var MySelf = this;

	PREVIEW_MAP_INSTANCE++;

	this.updateObject = function(shapeObject) {
		previewShape = shapeObject;
		var length = 0;
		for(var p in shapeObject) {
			length += new String(p).length+new String(shapeObject[p]).length+2
		}

		if(length < 4000) {
			for(var p in shapeObject) {
				previewLayer.params[p] = shapeObject[p];
			}
		} else {
			previewLayer.params['wkt'] = '';

		}
		updateLayerToMeters();
		updateExtent();
	}

	function zoomToBounds(req) {
		var text = new String(req.responseText);
		text = text.replace(/\n/, '');
		previewShape.bounds = new String(text);
		text = text.split(',');
		for(var i = 0; i < text.length; i++) {
			text[i] = parseFloat(text[i]);
		}
		try {
			previewMap.updateSize();
			previewMap.zoomToExtent(OpenLayers.Bounds.fromArray(text));
		} catch (e) {
			/* Maybe add a diagnostic message as necessary */
		}

		try {
			previewLayer.redraw();
		} catch (e) {
			/* Ditto about the diagnostics and what-not */
		}

		MySelf.onFinishBoundsRequest();
	}

	function updateExtent() {
		if(previewLayer) {
			if(previewShape && previewShape.bounds) {
				var fakeObject = {'responseText' : previewShape.bounds };
				zoomToBounds(fakeObject);
			} else if(previewShape && previewShape.wkt) {
				previewLayer.params['mode'] = 'bounds';
				var boundsUrl = previewLayer.getFullRequestString();
				previewLayer.params['mode'] = 'map';
				MySelf.onStartBoundsRequest();
				/*OpenLayers.loadURL(boundsUrl, null, null, zoomToBounds, null);*/
				var boundsArr = boundsUrl.split('?');
				openURL(boundsArr[0], boundsArr[1], null, zoomToBounds, null);
			} else {
				/* Don't bother doing anything */
			}
		}
	}

	function updateLayerToMeters(obj) {
		var attributes = {'inner' : 1, 'outer': 1, 'buffer': 1, 'start': 1, 'end': 1};
		for(var attr in attributes) {
			if(!isNaN(parseFloat(previewLayer.params[attr]))) {
				previewLayer.params[attr] = parseFloat(previewLayer.params[attr]) * 1609.3;
			}
		}
		return obj;	
	}
	
	this.init = function () {
		var p = document.getElementById(previewParent);

		var containerDiv = document.createElement('div');
		containerDiv.id = this.getContainerId();
		p.appendChild(containerDiv);

		var mapDiv = document.createElement('div');
		mapDiv.id = id+'map';
		mapDiv.className = 'PreviewMap';
		containerDiv.appendChild(mapDiv);
		
		previewMap = new OpenLayers.Map(mapDiv.id, {projection: PROJECTION_STRING,
			/*resolutions: MAP_RESOLUTIONS,*/
			minResolution: 1, maxResolution: 25000,
			maxExtent : OpenLayers.Bounds.fromArray(MAP_MAXEXTENT), controls: []});

		if(previewShape) {
			previewLayer = new OpenLayers.Layer.MapServer(
				'Selection Display',
				'cgi-bin/displaySelection.py',
				{},
				{reproject: false, isBaseLayer: true, singleTile: true}
			);
			previewMap.addLayer(previewLayer);

			this.updateObject(previewShape);

			updateLayerToMeters();
			updateExtent();
		} else {
			previewMap.zoomToMaxExtent();
		}
	}

	this.redrawMap = function() {
		updateExtent();
		previewLayer.redraw();
	}

	this.clearShape = function() {
		if(previewLayer) {
			previewLayer.params['wkt'] = '';
			previewShape = {};
			previewLayer.redraw();
		}
	}

	this.getContainerId = function () {
		return id+'container';
	}

	this.onStartBoundsRequest = function () {
	}

	this.onFinishBoundsRequest = function () {
	}

}


var SELECTION_STEP_ID = 0;


var NAVIGATION_TOOL_NAME = 'Navigation';

function SelectStep(stepXML, onStepChange, taskManager, previousShapes) {
	var id = 'Select'+SELECTION_STEP_ID;
	SELECTION_STEP_ID++;
	var SelectionTools = {
		/* JS Requires this be set manually */
		'Navigation' : {
			'notes' : "This tool allows the user to switch between working with polygons and navigating on the map",
			'tools' : {'Navigate' : ''},
			'ignoreSettings' : true,
			'className' : 'NavigationHeader',
			'help' : 'navigation'
		},
		'Layer' : {
			'notes' : "Select a layer from the drop-down list. Choose the Point(s) or Line method for selecting features in the map viewer. Features in only the chosen layer will be included in the selection. Use the Point(s) method to select one or more features by clicking once inside each boundary. Use the Line method to select one or more contiguous features by drawing the line through those features.<br/>",
			'tools' : {'Point(s)' : 'Draw Multipoint', 'Line' : 'Draw Line',
					'Modify Line' : 'Modify Area'},
			'layerSelect' : true, /* Have a layer input available */
			'help' : 'layer_select'
		},

		'Freehand' : {
			'notes' : "Draw a freehand polygon by dragging your mouse on the map.<br/>",
			'tools' : {'Polygon' : 'Draw Polygon', 'Edit Shape (Click on the polygon to begin and end editing.)' : 'Modify Area'},
			'help' : 'freehand_select'
		},
		'Ring/Buffer' : {
			'notes' : "This tool defines a circle (point) or a corridor (line) with a fixed radius.  Choose the ring type and radius then click or drag a line on the map to set the location.<br/>",
			'tools' : {'Point' : 'Draw Point', 'Line' : 'Draw Line',
					'Modify Line' : 'Modify Area'},
			'inputs' : {
				'Radius: ' : { 'suffix' : 'Miles', 'attribute' : 'buffer' }
			},
			'help' : 'buffer_select'
		},
		'Donut' : {
			'notes' : "This tool defines a selection area with a minimum and maximum distance (radius) from a selected location point.<br/>",
			'tools' : {'Point': 'Draw Point'},
			'inputs' : {
				'Inner: ' : { 'suffix' : 'Miles', 'attribute' : 'inner' },
				'Outer: ' : { 'suffix' : 'Miles', 'attribute' : 'outer' }
			},
			'help' : 'donut_select'
		},
		'Plume' : {
			'notes' : "This tool defines a corridor (plume coverage area) that expands in size from beginning to end.  Set the starting and ending radii and drag a line on the map.<br/>",
			'tools' : {'Line' : 'Draw Line', 'Modify Line' : 'Modify Area' },
			'inputs' : {
				'Start: ' : { 'suffix' : 'Miles', 'attribute' : 'start' },
				'End: ' : { 'suffix' : 'Miles', 'attribute' : 'end' }
			},
			'help' : 'plume_select'
		}
	};

	var CLEAR_SHAPE_NOTES = "Are you sure you want to clear this selection area?<br/>";
	var PREVIOUS_SHAPES_NOTES = "Choose a previous selection by clicking the text under the shape.<br/>";

	/* This is an array used to store the previewMap object references 
		so they can be refreshed later. */
	var previewMaps = new Array();

	/* This function determines the type of selection tool to use 
		based on the properties of the XML object */
	function getSelectionType() {
		var stepCheck = {'wkt' : false, 'buffer' : false, 
				'inner' : false, 'outer' : false, 'layer' : false,
				'start' : false, 'end': false};

		for(attr in stepCheck) {
			stepCheck[attr] = (stepXML.getAttribute(attr) != null
				&& stepXML.getAttribute(attr) != '');
		}
		/* default to 'navigate' */
		var selectionType = NAVIGATION_TOOL_NAME;

		var layerSelectShape = false;
		if(stepCheck.wkt) {
			var wkt = stepXML.getAttribute('wkt');
			layerSelectShape = wkt.match(/POINT/) || wkt.match(/LINE/);
		}

		if(stepCheck.wkt && stepCheck.buffer) {
			selectionType = 'Ring/Buffer';
		} else if(stepCheck.wkt && stepCheck.inner && stepCheck.outer) {
			selectionType = 'Donut';
		} else if(stepCheck.wkt && stepCheck.start && stepCheck.end) {
			selectionType = 'Plume';
		} else if(stepCheck.wkt && stepCheck.layer && layerSelectShape) {
			selectionType = 'Layer';
		} else if(stepCheck.wkt) {
			selectionType = 'Freehand';
		}
		return selectionType;
	}

	/* The Right Drawing Tool to used based on Shape, this is a "rough"
		function to help select the right drawing tool */
	function getShapeType() {
		var wkt = new String(stepXML.getAttribute('wkt')).toUpperCase();
		if(wkt.indexOf('LINE') >= 0) {
			return 'Draw Line';
		} else if(wkt.indexOf('MULTIPOINT') >= 0) {
			return 'Draw Multipoint';
		} else if(wkt.indexOf('POINT') >= 0) {
			return 'Draw Point';
		}
		return 'Draw Polygon';
	}
	
	

	/* Gets the list of editable attributes */
	function getAttributeList() {
		var attributes = new Array();
		attributes['layer'] = 1;
		for(var tool in SelectionTools) {
			for(var input in SelectionTools[tool].inputs) {
				attributes[SelectionTools[tool].inputs[input].attribute] = 1;
			}
		}
		return attributes;
	}

	function accordianHeaderAction() {
		var parent = this.parentNode;
		var divs = parent.getElementsByTagName('div');
		for(var d = 0; d < divs.length; d++) {
			if(divs[d].className == 'VisibleContent') {
				divs[d].className = 'HiddenContent';
			}
		}

		var child = document.getElementById(this.id+'-content');
		child.className = 'VisibleContent';

		if(this.innerHTML == NAVIGATION_TOOL_NAME) {
			var input = child.getElementsByTagName('input')[0];
/*			input.checked = true;*/
			input.onclick();
		}

		if(this.innerHTML == PREVIOUS_SHAPES_TOOL_NAME) {
			for(var p = 0; p < previewMaps.length; p++) {
				previewMaps[p].redrawMap();
			}
		}
		
		if(this.innerHTML != PREVIOUS_SHAPES_TOOL_NAME
			&& this.innerHTML != CLEAR_TOOL_NAME
			&& this.innerHTML != NAVIGATION_TOOL_NAME) {
			var attributes = getAttributeList();

			var inputs = child.getElementsByTagName('input');
			for(var attr in attributes) {
				var setInput = false;
				for(var i = 0; i < inputs.length; i++) {
					if(inputs[i].type != 'radio' && inputs[i].name == attr) {
						var value = stepXML.getAttribute(inputs[i].name);
						inputs[i].value = value;
						setInput = true;
					}
				}
				/* if it's not used for this step, then nix it */
				if(!setInput && attr != 'layer') {
					stepXML.setAttribute(attr, '');
				}
			}
			MapControls['Draw Multipoint'].points = new Array();

			var shape = getShapeType();
			var firstRadioIndex = -1;
			var foundDrawTool = false;
			for(var i = 0; i < inputs.length; i++) {
				if(inputs[i].type == 'radio') {
					if(firstRadioIndex < 0) { firstRadioIndex = i; }
					
					inputs[i].checked = false;
					if(inputs[i].value == shape) {
						inputs[i].checked = true;
						foundDrawTool = true;
						inputs[i].onclick();
					}
				}
			}

			/*
			 * This means there is either no shape, or the shape is not compatible
			 * with this particular tool, so the wkt is cleared out
			 */
			if(!foundDrawTool && firstRadioIndex >= 0) {
				inputs[firstRadioIndex].checked = true;
				inputs[firstRadioIndex].onclick();
				stepXML.setAttribute('wkt', '');
				onStepChange(taskManager.getShapeObject(stepXML));
			}

			/* A very poor way of resolving a layer select option */
			var select = child.getElementsByTagName('select');
			if(select.length > 0) {
				var layer = stepXML.getAttribute('layer');
				if(!layer) {
					var opts = select[0].getElementsByTagName('option');
					stepXML.setAttribute('layer',opts[0].value);
					for(var o = 0; o < opts.length; o++) {
						opts[o].selected = false;
					}
					opts[0].selected = true;
				}
			} else {
				stepXML.setAttribute('layer','');
			}
		}
	}

	function selectDrawingToolByValue() {
		/* Do something */
		activateMapTool(this.value);

		/* Update the display */
		var p = this.parentNode;
		var inputs = p.getElementsByTagName('input');
		for(var i = 0; i < inputs.length; i++) {
			if(inputs[i].name == this.name) { inputs[i].checked = false; }
		}
		this.checked = true;
	}


	function setShapeFromObject(obj) {
		var attributes = getAttributeList();
		attributes['wkt'] = 1;
		for(var attr in attributes) {
			if(obj[attr]) {
				stepXML.setAttribute(attr, obj[attr]);
			} else {
				stepXML.setAttribute(attr, '');
			}
		}

		var feature = (new OpenLayers.Format.WKT()).read(obj.wkt);
		MapControls['Draw Polygon'].drawFeature(feature.geometry);
	}

	function loadSelectionTool() {
		var selectType = getSelectionType();
		var typeHeader = document.getElementById(id+selectType);
		typeHeader.onclick();
	}

	/* Renders the selection accordian */

	var RenderInstance = 0;

	this.renderTools = function(parentId) {
		var p = document.getElementById(parentId);
				var selectedHeader = null;

		/* Clear Selection */
		var center = document.createElement('center');
		center.id = parentId+'-centerClear';
		p.appendChild(center);
		var clearButton = document.createElement('button');
		center.appendChild(clearButton);
		clearButton.innerHTML = 'Clear Selection';
		clearButton.onclick = function () {
			stepXML.setAttribute('wkt','');
			MapControls['Draw Multipoint'].points = new Array();
			MapControls['Draw Polygon'].featureAdded(null, MapControls['Draw Polygon'].layer);
			loadSelectionTool();
		}

		createHelpLink(center.id, 'clear_selection');

		var accordian = document.createElement('div');
		accordian.className = 'Accordian'
		accordian.id = parentId+'-selectAccordian';
		p.appendChild(accordian);
		
		for(var select in SelectionTools) {
			var header = document.createElement('div');
			accordian.appendChild(header);
			
			header.className = 'AccordianHeader';
			if(SelectionTools[select].className) {
				header.className += ' ' + SelectionTools[select].className
			}
			header.appendChild(document.createTextNode(select));
			header.id = id+select;

			createHelpLink(header.id, SelectionTools[select].help);

			var content = document.createElement('div');
			content.id = id+select+'-content';
			accordian.appendChild(content);
			content.className = 'HiddenContent';

			header.onclick = accordianHeaderAction;

			/* Add everything to the content */
			var toolNotes = document.createElement('div');
			toolNotes.className = 'SelectionToolNotes';
			content.appendChild(toolNotes);
			toolNotes.innerHTML = SelectionTools[select].notes;

			if(SelectionTools[select].layerSelect) {
				var label = document.createElement('span');
				label.className = 'LayerLabel';
				content.appendChild(label);

				label.appendChild(document.createTextNode('Layer:'));

				var selectObj = document.createElement('select');
				selectObj.style.width = '200px';
				content.appendChild(selectObj);

				/* I'm doing it this way, and not proper DOM because
					of some quirks with IE */
				var layerValue = stepXML.getAttribute('layer');
				for(var layer in SelectLayers) {
					/*var opt = document.createElement('option');
					selectObj.appendChild(opt);
					opt.appendChild(document.createTextNode(SelectLayers[layer]));
					opt.value = layer;*/
					selectObj.options[selectObj.options.length] = new Option(SelectLayers[layer], layer);
				}
				
				var opts = selectObj.getElementsByTagName('option');

				var foundIndex = 0;
				for(var o = 0; o < opts.length; o++) {
					opts[o].selected = false;
					if(opts[o].value == layerValue) {
						foundIndex = o;
					}
				}

				selectObj.onchange = function () {
					var options = this.getElementsByTagName('option');
					stepXML.setAttribute('layer', options[this.selectedIndex].value);
					onStepChange(taskManager.getShapeObject(stepXML));
				}

				opts[foundIndex].selected = true;
				content.appendChild(document.createElement('br'));
			}

			
			var i = 0;
			for(var name in SelectionTools[select].tools) {
				var input = document.createElement('input');
				input.type = 'radio';
				input.name = content.id+'-tool';
				input.value = SelectionTools[select].tools[name];
				content.appendChild(input);

				input.onclick = selectDrawingToolByValue;

				if(i==0) {
					input.checked = true;
				}

				/* Label the radio button */
				content.appendChild(document.createTextNode(name));
				content.appendChild(document.createElement('br'));
				i++;
			}

			for(var name in SelectionTools[select].inputs) {
				content.appendChild(document.createTextNode(name));
				var input = document.createElement('input');
				content.appendChild(input);
				
				var xmlName = SelectionTools[select].inputs[name].attribute;
				input.name = xmlName;
				input.value = stepXML.getAttribute(xmlName);
				input.onchange = function () {
					stepXML.setAttribute(this.name, this.value);
					onStepChange(taskManager.getShapeObject(stepXML));
				}
				content.appendChild(document.createTextNode(SelectionTools[select].inputs[name].suffix));
				content.appendChild(document.createElement('br'));
			}
		}

		/* Previous Shapes */
		var header = document.createElement('div');
		accordian.appendChild(header);
		
		header.className = 'AccordianHeader';
		header.appendChild(document.createTextNode(PREVIOUS_SHAPES_TOOL_NAME));
		header.id = id+'PreviousShapes';

		createHelpLink(header.id, 'previous_shapes');

		var content = document.createElement('div');
		content.id = header.id+'-content';
		accordian.appendChild(content);
		content.className = 'HiddenContent';
		header.onclick = accordianHeaderAction;

		var previousNotes = document.createElement('div');
		previousNotes.className = 'SelectionToolNotes';
		previousNotes.innerHTML = PREVIOUS_SHAPES_NOTES;

		var centerMap = document.createElement('center');
		centerMap.id = 'MyCenterId' + RenderInstance;
		RenderInstance++;
		content.appendChild(centerMap);

		var shapes = previousShapes;
		if(shapes.length == 0) {
			content.innerHTML = '<i>No shapes have been drawn.</i>';
		}
		
		previewMaps = new Array();
		for(var i = 0; i < shapes.length; i++) {
			var previewMap = new PreviewMap(centerMap.id, shapes[i]);
			previewMap.init();

			previewMaps.push(previewMap);

			var cont = document.getElementById(previewMap.getContainerId());

			var useLink = document.createElement('a');
			cont.appendChild(useLink);
			useLink.shapeObj = shapes[i];
			useLink.appendChild(document.createTextNode('Select this Shape'));
			useLink.href = "#";
			useLink.onclick  = function() {
				setShapeFromObject(this.shapeObj);
				loadSelectionTool();
			}

		}

		/* Add the dummy bar and hope it looks nice. */
		var dummy = document.createElement('div');
		dummy.className = 'AccordianHeader AccordianHeaderDummy';
		accordian.appendChild(dummy);
		dummy.innerHTML = '&nbsp;';

		/* Load the right selection tool */
		loadSelectionTool();
	}
}

/*
 * This file contains all the necessary code for communicating with
 * the print service.
 */

var PRINT_SERVICE_URL = './cgi-bin/print.py';

function onPrintError() {
	alert('There was an error printing the map!');
	document.getElementById('print-waiting').className = 'Hidden';
}

function showMap(req) {
	if(req.responseText) {
		var id = eval(req.responseText);
		window.open('./cgi-bin/showPrint.py?id='+id);
	}
	document.getElementById('print-waiting').className = 'Hidden';
}

function printMap(dialogId, titleId, qualityId, sizeId, legendsId) {
	/* This could probably be done more efficently but it is simple for now */
	var mapTitle = document.getElementById(titleId).value;

	var dropdownValues = {'quality' : qualityId, 'size' : sizeId, 'legends' : legendsId };

	for(var name in dropdownValues) {
		var dd = document.getElementById(dropdownValues[name]);
		var opts = dd.getElementsByTagName('option');

		dropdownValues[name] = opts[dd.selectedIndex].value;
	}

	/* Build an XML representation of the request */
	extent = Map.getExtent();
	extentString = (new Array(extent.left, extent.bottom, extent.right, extent.top)).join(',');
	xmlString = '<print extent="'+extentString+'" quality="'+dropdownValues.quality+'" size="'+dropdownValues.size+'" legends="'+dropdownValues.legends+'" title="'+mapTitle+'">\n';
	for(var i = 0; i < Map.layers.length; i++) {
		var mapLayer = Map.layers[i];
		if(mapLayer.getVisibility()) {
/*			xmlString += '<map title="'+mapLayer.name+'" src="'+mapLayer.params['MAP']+'" layers="'+mapLayer.params['LAYERS']+'" mime="'+mapLayer.params['FORMAT']+'"/>\n';*/
			var layerType = 'MS';
			if(mapLayer instanceof OpenLayers.Layer.WMS) {
				layerType = 'WMS';
			}
			xmlString += '<map title="'+mapLayer.name+'" type="'+layerType+'">';
			xmlString += '<![CDATA['+mapLayer.getFullRequestString()+']]>';
			xmlString += '</map>';
		}
	}

	var legends = LayerManager.getLegendURLs();
	for(var i = 0; i < legends.length; i++) {
		xmlString += '<legend><![CDATA['+legends[i]+']]></legend>\n';
	}
	xmlString += '</print>';
	/* Change the dialogs */
	document.getElementById(dialogId).className = 'Hidden';
	document.getElementById('print-waiting').className = 'Visible';

	new OpenLayers.Ajax.Request(PRINT_SERVICE_URL, 
	{   method: 'post', 
		postBody: xmlString,
		onComplete: showMap,
		onFailure: onPrintError
	}
	);

}

/*
 * Implements searching functionality
 * (c) 2008, Dan "Ducky" Little, GRI Technologies
 */

var SEARCHES = {
	"All Place Names": {
		'url': './cgi-bin/placeNameSearch.py',
		'key': 'placename',
		'handler': placenameSearchHandler
	}
};

for(var search = 0; search < SEARCHABLE_LAYERS.length; search++) {
	var name = SEARCHABLE_LAYERS[search];
	var obj = {
		'url': './cgi-bin/placeNameSearch.py',
		'key' : 'placename',
		'handler' : placenameSearchHandler,
		'params': { 'table': name }
	}

	SEARCHES[name] = obj;
}


var PlaceNameChildCounter = 0;

function populateSearchDropdown(id) {
	var select = document.getElementById(id);
	for(var v in SEARCHES) {
		var opt = document.createElement('option');
		opt.setAttribute("value", v);
		select.appendChild(opt);
		opt.appendChild(document.createTextNode(v));
	}
}

function zoomToBoundString() {
	for(var i = 0; i < this.layerNames.length; i++) {
		LayerManager.setLayerVisibility(this.layerNames[i], true);
	}
	Map.zoomToExtent(OpenLayers.Bounds.fromString(this.getAttribute('boundstring')));
}

function placenameSearchRenderArea(node, parentId, lastItem, searchString) {
	var p = document.getElementById(parentId);
	var pdiv;
	if(node.tagName == 'area') {
		pdiv = document.createElement('div');
		pdiv.id = 'PNS_Result_'+PlaceNameChildCounter;
		pdiv.className = 'ResultsTree';
		if(lastItem) {
			pdiv.className += ' ResultsTreeLastItem';
		}

		PlaceNameChildCounter++;

		p.appendChild(pdiv);
		var pa = document.createElement('a');
		pdiv.appendChild(pa);

		/* This should be the top-most results node */
		if(node.parentNode.tagName != 'area') {
			createHelpLink(pdiv.id, 'search_results');
		}


/*
		pa.appendChild(document.createTextNode(node.getAttribute('name')));
		pa.innerHTML = new String(pa.innerHTML).replace(searchString, '<b>'+searchString+'</b>');
		var capitalized = searchString.substring(0,1).toUpperCase()+searchString.substring(1);
		pa.innerHTML = new String(pa.innerHTML).replace(capitalized, '<b>'+capitalized+'</b>');
		position = name.upper().find(searchString.upper())
		length = len(searchString)
		name = name[0:position] + '<b>' + name[position:position+length] + '</b>' + name[position+length:]
		return '<a href="%s">%s</a>' % (createBoundsLink(area.getAttribute('bounds')), name)
*/

		var name = new String(node.getAttribute('name'));
		var position = name.toUpperCase().search(searchString.toUpperCase());
		var length = searchString.length;
		if(position >= 0) {
			name = name.substring(0,position) + '<b>' + name.substring(position, position+length) + '</b>' + name.substring(position+length);
		}
		pa.innerHTML = name.replace('&apos;', "'");

		if(node.getAttribute('bounds')) {
			pa.setAttribute('href','#');
			pa.setAttribute('boundstring', node.getAttribute('bounds'));
			var layers = node.getElementsByTagName('layer');
			var layerNames = new Array();
			for(var i = 0; i < layers.length; i++) {
				layerNames.push(layers[i].getAttribute('name'));
			}
			pa.layerNames = layerNames;
			pa.onclick = zoomToBoundString;
		}
	} else {
		pdiv = p;
	}
	var areas = new Array();
	for(var i = 0; i < node.childNodes.length; i++) {
		if(node.childNodes[i].tagName == 'area') {
			areas.push(node.childNodes[i]);
		}
	}
	for(var i = 0; i < areas.length - 1; i++) {
		placenameSearchRenderArea(areas[i], pdiv.id, false, searchString);
	}
	if(areas.length > 0) {
		placenameSearchRenderArea(areas[areas.length-1], pdiv.id, true, searchString);
	}
}

function clearContent(id) {
	document.getElementById(id).innerHTML = '';
}

function placenameSearchHandler(req) {
	var xml = req.responseXML;
	var html = req.responseText;
	if(!xml && !html) {
		alert("Place Name service did not return valid content.");
		return false;
	}

	/* Clear the parent out before rendering the results */
	var p = document.getElementById(this.parent);
	p.innerHTML = '';

	var clearCenter = document.createElement('center');
	var clearButton = document.createElement('a');

	p.appendChild(clearCenter);
	clearCenter.appendChild(clearButton);
	clearButton.appendChild(document.createTextNode('(clear results)'));
	clearButton.setAttribute('href', 'javascript:clearContent("'+this.parent+'");');
	clearButton.className  = 'ClearButton';

	clearCenter.appendChild(document.createElement('br'));
	clearCenter.appendChild(document.createTextNode('Click on any result to see that area in the map window.'));
	

	if(xml) {
		var root =  xml.documentElement;
		/*
		var layers = root.getElementsByTagName('layer');
		for(var i = 0; i < layers.length; i++) {
			LayerManager.setLayerVisibility(layers[i].getAttribute('name'),true);
		}*/
		placenameSearchRenderArea(root, this.parent, false, this.search);
	} else {
		p.innerHTML = html;
	}

}

function clearResults() {
	document.getElementById('SearchResults').innerHTML = '<font color="red">Error loading search.</font>';
}

function callSearch(searchName,searchValue,targetDiv,waitingDiv) {
	var searchRec = SEARCHES[searchName];
	if(!searchRec) { alert('Invalid search name! ('+searchName+')'); return false; }

	var parentRec = { 'parent': targetDiv, 'search' : searchValue };
	var searchParams = searchRec['params'];
	var paramString = '?'+searchRec['key']+'='+escape(searchValue);
	for(var k in searchParams) {
		paramString += '&'+k+'='+escape(searchParams[k]);
	}

	/* Show the waiting div */
	if(waitingDiv) {
		document.getElementById(targetDiv).innerHTML =
			document.getElementById(waitingDiv).innerHTML;
	}
	OpenLayers.loadURL(searchRec['url']+paramString, "", parentRec, searchRec['handler'], clearResults);
}





function GRITaskManager() {
	var idStub = 'TaskManager';
	var idCounter = 0;
	var Tasks = new Array();
	var ActiveAjaxRequests = new Array();
	var ShapeQueue = new Queue(5);

	var CurrentQuery = false; /* changes to the query id when available */

	/* Sorta like "environment variables" */
	var Variables = {};

	this.setQueryId = function(qid) {
		CurentQuery = qid;
	}

	this.getQueryId = function() {
		return CurrentQuery;
	}


	this.onCancel = function() {
	}

	this.abortTasks = function() {
		while(ActiveAjaxRequests.length > 0) {
			try {
				req = ActiveAjaxRequests.pop();
				req.transport.abort();
			} catch(e) {
			}
		}
		MySelf.onCancel();
	}

	function getId() {
		idCounter++;
		return idStub+idCounter;
	}



	function setTaskVariables(variString) {
		var pairs = variString.split(',');
		for(var i = 0; i < pairs.length; i++) {
			var key_value = pairs[i].split('=');
			Variables[key_value[0]] = key_value[1].replace(/%comma/g,',');
		}
	}

	function getTokens(s) {
	    var tokens = new Array();
	    var inToken = false;
	    var tokenName = '';
	    for(var i = 0; i < s.length; i++) {
	    	var c = s.substring(i,i+1);
		if(c == '[') {
		    inToken = true;
		} else if(inToken && c == ']') {
		    tokens.push(tokenName);
		    tokenName = '';
		    inToken = false;
		} else if(inToken) {
		    tokenName += c;
		}
	    }
	    return tokens;
	}

	function countKnownTokens(s) {
		var tokens = getTokens(s);
		var knownTokens = 0;
		for(var i = 0; i < tokens.length; i++) {
			if(typeof(Variables[tokens[i]]) != undefined) {
				knownTokens++;
			}
		}
		return knownTokens;
	}

	function substituteVariables(inString) {
		inString = new String(inString);
		while(countKnownTokens(inString) > 0) {
			for(var p in Variables) {
				var regex = new RegExp('\\['+p+'\\]', 'g');
				inString = inString.replace(regex, Variables[p]);
			}
		}
		return inString;
	}

	var fieldRenderers = new Array();

	function createFieldset(parentId, title, notes, help) {
		var parent = document.getElementById(parentId);
		var holder = document.createElement('fieldset');
		parent.appendChild(holder);
		holder.className = 'StepFieldset';
		var legend = document.createElement('legend');
		holder.appendChild(legend);
		legend.appendChild(document.createTextNode(substituteVariables(title)));
		legend.id = getId();
		if(notes) {
			var noteSpan = document.createElement('span');
			noteSpan.className = 'FieldNote';
			holder.appendChild(noteSpan);
			noteSpan.innerHTML = substituteVariables(notes);
		}
		if(help) {
			/*var helpLink = document.createElement('a');
			helpLink.setAttribute('target','help');
			helpLink.setAttribute('href',help);
			helpLink.className = 'HelpLink';
			legend.appendChild(helpLink);

			var helpImg = document.createElement('img');
			helpImg.setAttribute('alt','Help');
			helpImg.setAttribute('title','Click this link for more information');
			helpImg.setAttribute('src',HELP_ICON);
			helpLink.appendChild(helpImg);*/

			createHelpLink(legend.id, help);
		}

		holder.id = getId();
		return holder.id;

	}

	function createFieldsetUsingXML(parentId, fieldXML) {
		return createFieldset(parentId, fieldXML.getAttribute('title'),fieldXML.getAttribute('notes'),fieldXML.getAttribute('help'));
	}

	function renderSingleSelectionItem(parentId, fieldXML, type) {
		var parent = document.getElementById(parentId);
		var span = document.createElement('span');
		parent.appendChild(span);

		var checkbox = document.createElement('input');
		checkbox.type = type;
		checkbox.name = fieldXML.getAttribute('name');
		checkbox.value = fieldXML.getAttribute('value');
		var selected = new String(fieldXML.getAttribute('selected'));
		var disabled = new String(fieldXML.getAttribute('disabled'));
		span.appendChild(checkbox);


		//span.setAttribute("style", fieldXML.getAttribute('style'));
		span.style.cssText = fieldXML.getAttribute('style');

		if(disabled.match(/true/i)) {
			checkbox.disabled = true;
		}

		if(selected.match(/true/i)) {
			checkbox.checked = true;
			if(fieldXML.getAttribute('variables')) {
				setTaskVariables(new String(fieldXML.getAttribute('variables')));
			}
		}
		if(type == 'checkbox') {
			checkbox.onclick = function () { /* IE Supports onclick better than onchange */
				fieldXML.setAttribute('selected', new String(this.checked));
			}
		} else { /* Radio Button */
			checkbox.updateValue = function() {
				fieldXML.setAttribute('selected', new String(this.checked));
				if(fieldXML.getAttribute('variables') && this.checked) {
					setTaskVariables(new String(fieldXML.getAttribute('variables')));
				}
			}
			checkbox.onclick = function () { /* Radio Buttons need to unset others */
				this.checked = true;
				this.updateValue();
				/* This should go to the parent DIV, so it can find any inputs with a similar name */
				var inputs = parent.parentNode.getElementsByTagName('input');
				for(var i = 0; i < inputs.length; i++) {
					if(inputs[i].name == this.name && inputs[i] != this) {
						inputs[i].checked = false;
						inputs[i].updateValue();
				//		inputs[i].onclick(); /* This updates the XML Object */
					}
				}
			}
		}
		/*span.appendChild(document.createTextNode(substituteVariables(fieldXML.getAttribute('title'))));*/
		var label = document.createElement('span');
		span.appendChild(label);
		label.className = 'field-title'; 
		label.innerHTML = substituteVariables(fieldXML.getAttribute('title'));
		span.appendChild(document.createElement('br'));

	}

	fieldRenderers['checkbox'] = function(parentId, fieldXML) {
		renderSingleSelectionItem(parentId, fieldXML, 'checkbox');	
	}

	fieldRenderers['radio'] = function(parentId, fieldXML) {
		renderSingleSelectionItem(parentId, fieldXML, 'radio');	
	}

	function createOption(value, title) {
		var opt = document.createElement('option');
		opt.value = value;
		opt.appendChild(document.createTextNode(substituteVariables(title)));
		return opt;
	}
	
	fieldRenderers['dropdown'] = function(parentId, fieldXML) {
		var p = document.getElementById(parentId);
		var div = document.createElement('div');
		p.appendChild(div);

		var select = document.createElement('select');
		div.appendChild(document.createTextNode(fieldXML.getAttribute('title')))
		div.appendChild(select);
		var maxSelected = 0;
		
		select.appendChild(createOption('',''));

		var options = fieldXML.getElementsByTagName('option');
		for(var o  = 0; o < options.length; o++) {
			select.appendChild(createOption(options[o].getAttribute('value'), options[o].getAttribute('title')));

			var selected = new String(options[o].getAttribute('selected'));
			if(selected.match(/true/i)) {
				maxSelected = o+1;
			}
		}
		select.getElementsByTagName('option')[maxSelected].selected = true;
	}
	
	function renderSelectField(parentId, fieldXML, type) {
		var fieldSetId = createFieldsetUsingXML(parentId, fieldXML);
		/*var fieldset = document.getElmenetById(fieldSetId);*/
		var options = fieldXML.getElementsByTagName('option');
		var fieldName = fieldXML.getAttribute('name');
		for(var o  = 0; o < options.length; o++) {
			options[o].setAttribute('name', fieldName);
			fieldRenderers[type](fieldSetId, options[o]);
		}
		return fieldSetId;
	}
	
	/* select = select many */
	fieldRenderers['select'] = function(parentId, fieldXML) {
		renderSelectField(parentId, fieldXML, 'checkbox');
	}

	fieldRenderers['select1'] = function(parentId, fieldXML) {
		/* Set on the last "selected" to "selected" */
		var maxSelected = -1; /* Condition for if nothing is selected */
		var options = fieldXML.getElementsByTagName('option');
		for(var i = 0; i < options.length; i++) {
			if(new String(options[i].getAttribute('selected')).match(/true/i)) {
				maxSelected = i;
				options[i].setAttribute('selected','false');
			}
		}
		if(maxSelected >= 0) {
			options[maxSelected].setAttribute('selected','true');
		}
		renderSelectField(parentId, fieldXML, 'radio');
	}

	fieldRenderers['text'] = function(parentId, fieldXML) {
		var fieldSetId = createFieldsetUsingXML(parentId, fieldXML);
		var input = document.createElement('input');
		input.name = fieldXML.getAttribute('name');
		if(fieldXML.getAttribute('value')) { /* Prevents IE from rendering "null" */
			input.value = fieldXML.getAttribute('value');
		}
		input.onchange = function () {
			fieldXML.setAttribute('value',this.value);
		}
		var fset = document.getElementById(fieldSetId);
		fset.appendChild(input);

	}
	
	fieldRenderers['error'] = function(parentId, errorText) {
		var p = document.getElementById(parentId);
		var font = document.createElement('font');
		font.className = 'TaskErrorMessage';
		p.appendChild(font);
		font.appendChild(document.createTextNode(errorText));
	}

	fieldRenderers['hidden'] = function() { }

	fieldRenderers['extent'] = function() { }
	
	function renderField(parentId, fieldXML) {
		var renderer = null;
		var render = true;
		try {
			renderer = fieldRenderers[fieldXML.getAttribute('type').toLowerCase()];
		} catch(e) {
			/* Aw... meng, that one don't exist */
			fieldRenderers['error'](parentId, 'No Renderer Found\n'+e.name+'\n'+e.message);
		}

		if(fieldXML.getAttribute('eval')) {
			var evalString = fieldXML.getAttribute('eval');
			evalString = substituteVariables(evalString);
			render = eval(evalString);
		}
		if(renderer && render) {
			renderer(parentId, fieldXML);
		} else if(render) {
			fieldRenderers['error'](parentId, 'No Renderer Found for Type: '+fieldXML.getAttribute('type'));
		}
	}

	function createDrawingToolLink(parentId, toolName) {
		var parent = document.getElementById(parentId);
		var a = document.createElement('a');
		parent.appendChild(a);
		a.className = 'NormalToolBarButton IconZoomPan';
		a.appendChild(document.createTextNode(toolName));
		a.toolType = toolName;
		a.onclick = function () {
			for(var t in DrawingTools) {
				DrawingTools[t].deactivate();
			}
			DrawingTools[this.toolType].activate();
			selectToolbarButton(this);
		}
		a.href = '#';
	}

	function previewFeature(f, localVectorLayer) {
		if(!localVectorLayer) {
			localVectorLayer= this.targetVectorLayer;
		}
		var f2 = f.clone();
		localVectorLayer.removeFeatures(localVectorLayer.features);
		localVectorLayer.addFeatures([f2]);
		localVectorLayer.drawFeature(f2);
		localVectorLayer.map.zoomToExtent(f2.geometry.getBounds());
		if(f.layer) { /* If the feature was created from XML, there won't be a layer */
			f.layer.drawFeature(f);
		}
	}

	function colorFeature(f,border,color) {
		var newStyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
		f.style = newStyle;
		if(border) {
			f.style['strokeColor'] = border;
		} else {
			f.style['strokeColor'] = getBorderColor();
		}
		if(color) {
			f.style['fillColor'] = color;
		} else {
			f.style['fillColor'] = getColor();
		}
		f.style['strokeWidth'] = '3px';
	}

	function previewAndColorFeature(f) {
		colorFeature(f);
		previewFeature(f, this.targetVectorLayer);
	}

	this.renderStep = function(parentId, taskXMLObj, step) {
		var allSteps = taskXMLObj.getElementsByTagName('step');
		var stepXMLObj = allSteps[step];
		var messages = stepXMLObj.getElementsByTagName('message');
		var fields = stepXMLObj.getElementsByTagName('field');
		var xmlParser = new OpenLayers.Format.XML();
		
		var parent = document.getElementById(parentId);

		var messageHTML = '';		
		for(var i = 0; i < messages.length; i++) {
			if(messages[i].parentNode == stepXMLObj) {
				messageHTML += xmlParser.concatChildValues(messages[i]);
			}
		}
		parent.innerHTML = ''; /* Clear out the old steps */

		var destroyPreviewLayer = false;
		var stepFunction = function() {
			var wkt = stepXMLObj.getAttribute('wkt');
			if(wkt) {
				/* Log object into array */
				var shape = MySelf.getShapeObject(stepXMLObj);

				/* Check for a valid selection combination */
				if(!wkt.match(/POLYGON/)) {
					var attr = ['inner', 'outer', 'buffer', 'start', 'end','layer'];
					var valid = false;
					for(var a = 0; a < attr.length && !valid; a++) {
						if(stepXMLObj.getAttribute(attr[a])) {
							valid = true;
						}
					}
					if(!valid) {
						alert("Error with selection options, please verify that you have selected a layer or buffer values as appropriate.");
						return false;
					}
				}

				/* Check to see if it's already in the history */

				var others = ShapeQueue.getAll();
				var found = -1;
				var i = 0;
				while(found < 0 && i < others.length) {
					if(MySelf.shapeObjectsEqual(shape, others[i])) {
						found = i;
					}
					i++;
				}

				if(found < 0) {
					ShapeQueue.add(shape);
				} else {
					ShapeQueue.bump(found);
				}
				MapControls['Draw Multipoint'].points = new Array();
			}
			/*Layers['VectorDrawing'].setVisibility(false);*/
			
			/* Deactivate all the drawing tools */
			/*for(var i in DrawingTools) {
				if(DrawingTools[i]) {
					DrawingTools[i].deactivate();
				}
			}*/
			/* Clear out the features */
			/*Layers['VectorDrawing'].removeFeatures(Layers['VectorDrawing'].features);*/

			if(destroyPreviewLayer) {
				destroyPreviewLayer();
			}
			LayerManager.hideDrawingLayer();
			var jumpStep = this.value;
			if(this.step || this.step == 0) { jumpStep = this.step; }
			MySelf.renderStep(parentId, taskXMLObj, jumpStep);
			parent.scrollTop = 0;

			
		}

		var fixedPositionBox = document.createElement('div');
		fixedPositionBox.className = 'TaskControlPanel';
		parent.appendChild(fixedPositionBox);
		

		var stepDropDown = document.createElement('select');
		stepDropDown.onchange = function() {
			if(destroyPreviewLayer) {
				destroyPreviewLayer();
			}
			MySelf.renderStep(parentId, taskXMLObj, this.selectedIndex);
		}

		stepDropDown.className = 'StepDropDown';

		for(var i = 0; i < allSteps.length; i++) {
			var option = document.createElement('option');
			option.value = i;
			stepDropDown.appendChild(option);

			var optTitle = i+1+'. '+allSteps[i].getAttribute('title');
			option.appendChild(document.createTextNode(optTitle));
			if(i == step) {
				option.selected = true;
			} else {
				option.selected = false;
			}
			
		}

		var backBtn = createButton('Back');
		var nextBtn = createButton('Next');
		var cancelBtn = createButton('Cancel');
		backBtn.className = 'BackButton';
		nextBtn.className = 'NextButton';
		cancelBtn.className = 'CancelButton';

		fixedPositionBox.appendChild(backBtn);
		fixedPositionBox.appendChild(stepDropDown);
		parent.appendChild(cancelBtn);
		fixedPositionBox.appendChild(nextBtn);

		var spacer = document.createElement('div');
		spacer.className = 'MessageSpacer';
		parent.appendChild(spacer);
		spacer.innerHTML = '&nbsp;';

		var message = document.createElement('div');
		message.className = 'TaskMessage';
		
		parent.appendChild(message);
		message.innerHTML = substituteVariables(messageHTML);
		
		var stepType = stepXMLObj.getAttribute('type');
		if(stepType && stepType.match(/select/i)) {
			/* Render the fields before the map */
			var actionFields = stepXMLObj.getElementsByTagName('field');
			for(var f = 0; f < actionFields.length; f++) {
				renderField(parentId, actionFields[f]);
			}


			/*Layers['VectorDrawing'].setVisibility(true);*/
			LayerManager.showDrawingLayer();

			var centerMap = document.createElement('center');
			centerMap.id = 'stepPreviewMap';
			parent.appendChild(centerMap);
			/*
			var taskMapTitle = document.createElement('div');
			taskMapTitle.style.width = '100px';
			taskMapTitle.style.fontSize = '8pt';
			taskMapTitle.style.textAlign = 'left';
			centerMap.appendChild(taskMapTitle);
			taskMapTitle.appendChild(document.createTextNode('Selection Preview:'));
			*/

				
			var previewMap = new PreviewMap(centerMap.id, MySelf.getShapeObject(stepXMLObj));

			previewMap.onStartBoundsRequest = function () {
				nextBtn.disabled = true;
			}

			previewMap.onFinishBoundsRequest = function () {
				nextBtn.disabled = false;
			}

			previewMap.init();
			
			var cont = document.getElementById(previewMap.getContainerId());
			var areaNoteDiv = document.createElement('div');
			cont.insertBefore(areaNoteDiv, cont.firstChild);
			areaNoteDiv.style.width = '100px';
			areaNoteDiv.style.fontSize = '8pt';
			areaNoteDiv.style.textAlign = 'left';
			areaNoteDiv.appendChild(document.createTextNode('Area Shape:'));

			/* Put the preview image of the selection on the main map */
			var shapeObj = MySelf.getShapeObject(stepXMLObj);
			if(new String(shapeObj.wkt).length > 3000) {
				shapeObj = {}
			}
			var previewLayer = new OpenLayers.Layer.MapServer(
				'Task Manager Preview Layer',
				'cgi-bin/displaySelection.py',
				shapeObj,
				{reproject: false, isBaseLayer: true, singleTile: true}
				);

			Map.addLayer(previewLayer);
			previewLayer.setVisibility(true);
			var z = LayerManager.getDrawingLayer().div.style.zIndex;
			Map.setLayerZIndex(previewLayer, z); 
			Map.setLayerZIndex(LayerManager.getDrawingLayer(), z+1);

			var updatePreviewLayer = function(shapeObject) {
				var length = 0;
				for(var p in shapeObject) {
					length += 2+new String(p).length+new String(shapeObject[p]).length;
				}
				for(var p in shapeObject) {
					previewLayer.params[p] = shapeObject[p];
				}

				if(length > 3000) {
					previewLayer.params['wkt'] = '';
				}
				var attributes = {'inner' : 1, 'outer': 1, 'buffer': 1, 'start': 1, 'end': 1};
				for(var attr in attributes) {
					if(!isNaN(parseFloat(previewLayer.params[attr]))) {
						previewLayer.params[attr] = parseFloat(previewLayer.params[attr]) * 1609.3;
					}
				}
				previewLayer.redraw();
				previewMap.updateObject(MySelf.getShapeObject(stepXMLObj));
			}

			Map.events.register('moveend', {}, updatePreviewLayer);
			Map.events.register('zoomend', {}, updatePreviewLayer);

			destroyPreviewLayer = function() {
				Map.removeLayer(previewLayer);
				Map.events.unregister('moveend', {}, updatePreviewLayer);
				Map.events.unregister('zoomend', {}, updatePreviewLayer);

			}


			var parser = new OpenLayers.Format.WKT();

			/* When a new feature is inserted, remove the ole ones, and select it for our step */
			var onFeatureAdded = function(f,layer) {
				if(!layer) { layer = this.layer; }
				while(layer.features[0]) {
					layer.removeFeatures(layer.features[layer.features.length-1]);
				}
				if(f) {
					layer.addFeatures(f);

					var wkt = parser.write(f);
					stepXMLObj.setAttribute('wkt', wkt);
					previewMap.updateObject(MySelf.getShapeObject(stepXMLObj));
				} else {
					previewMap.clearShape();
				}
				updatePreviewLayer(MySelf.getShapeObject(stepXMLObj));
			}

			var onMultipointAdded = function(f, layer) {
				if(!layer) { layer = this.layer; }
				while(layer.features[0]) {
					layer.removeFeatures(layer.features[layer.features.length-1]);
				}
				if(f) {
					var pointObjects = new Array();
					if(f.geometry instanceof OpenLayers.Geometry.MultiPoint) {
						pointObjects = f.geometry.components;
					} else if(f.geometry instanceof OpenLayers.Geometry.Point) {
						pointObjects = [f.geometry];
					}

					for(var i = 0; i < pointObjects.length; i++) {
						/* it should be a point! */
						var x = pointObjects[i].x;
						var y = pointObjects[i].y;
						MapControls['Draw Multipoint'].points.push(x+' '+y);
					}
					
					var pointsString = 'MULTIPOINT('+MapControls['Draw Multipoint'].points.join(',')+')';
					stepXMLObj.setAttribute('wkt', pointsString);

					var wkt = new OpenLayers.Format.WKT();
					layer.addFeatures(wkt.read(pointsString));

					
					previewMap.updateObject(MySelf.getShapeObject(stepXMLObj));
				} else {
					MapControls['Draw Multipoint'].points = new Array();
					previewMap.clearShape();
				}
				updatePreviewLayer(MySelf.getShapeObject(stepXMLObj));
			}
			/* Clear out this one */
			MapControls['Draw Multipoint'].points = new Array();

			MapControls['Draw Polygon'].featureAdded = onFeatureAdded;
			MapControls['Draw Line'].featureAdded = onFeatureAdded;
			MapControls['Draw Point'].featureAdded = onFeatureAdded;
			MapControls['Draw Multipoint'].featureAdded = onMultipointAdded;
			MapControls['Modify Area'].onModificationEnd = onFeatureAdded;
			

			var defaultTab = 'Freehand';
			var wkt = stepXMLObj.getAttribute('wkt');
			if(wkt) { /* Previously selected shape! */
				var wktParser = new OpenLayers.Format.WKT();
				var f = wktParser.read(wkt);
				
				var buffer = parseFloat(stepXMLObj.getAttribute('buffer'));
				if(buffer) {
					defaultTab = 'Buffer';
				}

				var layer = stepXMLObj.getAttribute('layer');
				if(layer) {
					defaultTab = 'Layer';
				}

				if(!buffer && buffer > 0 && !layer && !(f.geometry instanceof OpenLayers.Geometry.Polygon)) {
					/* reset everything, for we have reached an inclusive state */
					stepXMLObj.setAttribute('wkt','');
				} else {
					/*Layers['VectorDrawing'].addFeatures(f);*/
					LayerManager.getDrawingLayer().addFeatures(f);
					if(f.geometry instanceof OpenLayers.Geometry.MultiPoint) {
						onMultipointAdded(f, LayerManager.getDrawingLayer());
					} else {
						onFeatureAdded(f, LayerManager.getDrawingLayer());
					}
				}
			}

			parent.appendChild(document.createElement('br'));
			var stepControl = new SelectStep(stepXMLObj, updatePreviewLayer, MySelf, ShapeQueue.getAll());
			stepControl.renderTools(parentId);
		} else if(stepType && stepType.match(/action/i)) {
			var rootFields = stepXMLObj.childNodes;
/*			for(var f = 0; f < rootFields.length; f++) {
				if(rootFields[f].tagName == 'field') {
					renderField(parentId, rootFields[f]);
				}
			}*/
			var actions = stepXMLObj.getElementsByTagName('action');
			actions = stepXMLObj.childNodes;
			var currentAction = stepXMLObj.parentNode.getAttribute('action');
			for(var a = 0; a < actions.length; a++) {
				if(actions[a].tagName == 'field') {
					renderField(parentId, actions[a]);
				} else if(actions[a].tagName == 'action') {
					var actionTitle = actions[a].getAttribute('title');
					var id = actionTitle+a;
					
					var fieldset = document.createElement('fieldset');
					parent.appendChild(fieldset);
					fieldset.id = id;


					
					var legend = document.createElement('legend');
					fieldset.appendChild(legend);
					legend.id = getId();

					var radio = document.createElement('input');
					radio.type = 'radio';
					radio.value = actions[a].getAttribute('url');
					legend.appendChild(radio);
					radio.className = 'ActionRadio';
					radio.onclick = function () {
						var p = this.parentNode.parentNode.parentNode;
						var inputs = p.getElementsByTagName('input');
						for(var input = 0; input < inputs.length; input++) {
							if(inputs[input].className == 'ActionRadio') {
								inputs[input].checked = false;
							}
						}

						stepXMLObj.parentNode.setAttribute('action', this.value);
						this.checked = true;
					}
					if((!currentAction && a==0) || currentAction == actions[a].getAttribute('url')) { radio.onclick(); }

					legend.appendChild(document.createTextNode(substituteVariables(actionTitle)));
					if(actions[a].getAttribute('help')) {
						createHelpLink(legend.id, actions[a].getAttribute('help'));
					}
					
					var messageDiv = document.createElement('div');
					fieldset.appendChild(messageDiv);

					var actionMessages = actions[a].getElementsByTagName('message');
					var messageHTML = '';		
					for(var i = 0; i < actionMessages.length; i++) {
						messageHTML += xmlParser.concatChildValues(actionMessages[i]);
					}
					messageDiv.innerHTML = substituteVariables(messageHTML);

					var actionFields = actions[a].getElementsByTagName('field');
					for(var f = 0; f < actionFields.length; f++) {
						renderField(id, actionFields[f]);
					}
				}
			}
		} else {
			for(var i = 0; i < fields.length; i++) {
				renderField(parentId, fields[i]);
			}
		}

		nextBtn.step = step+1;
		backBtn.step = step-1;

		nextBtn.onclick = stepFunction;
		backBtn.onclick = stepFunction;

		cancelBtn.onclick = function() {
			MySelf.onCancel();
/*			Layers['VectorDrawing'].setVisibility(false);*/
			LayerManager.hideDrawingLayer();
		/*	var drawTools = ['Draw Polygon','Draw Line','Draw Point'];
			for(var d = 0; d < drawTools.length; d++) {
				deactivateMapTool(drawTools[d]);	
			}*/

		}

		if(step == 0) { /*backBtn.disabled = true;*/
			if(BACK_BUTTON_TO_MENU) {
				backBtn.onclick = cancelBtn.onclick;
			} else {
				backBtn.disabled = true;
			}
		}
		if(step+1 >= allSteps.length) {
/*			nextBtn.value = 'Create Overlay';*/
			nextBtn.value = 'Go!';
			nextBtn.className += ' FinishedButton';
			nextBtn.onclick = function() {
				var postData = MySelf.getPostData(taskXMLObj.getAttribute('id'));
				postData += '&unique=' + (new Date()).getTime();

				ActiveAjaxRequests.push(openURL(taskXMLObj.getAttribute('action'),
					postData, {"taskName" : taskXMLObj.getAttribute('id')},
					processPostReturn, null));

			/*	ActiveAjaxRequests.push(OpenLayers.loadURL(taskXMLObj.getAttribute('action'),
							postData, {"taskName" : taskXMLObj.getAttribute('id')},
							processPostReturn, null));*/
				LayerManager.stopAnimation();
				LayerManager.hideDrawingLayer();
				MySelf.onWait();
			}
		}
	}

	this.onWait = function () { }

	function returnToLastStep(taskName) {
		if(this.taskName) { taskName = this.taskName; }
		if(!taskName) { return false; }
		var task = getTask(taskName);
		var steps = task.getElementsByTagName('step').length;
		MySelf.renderStep('Reports',task,steps-1);

	}

	this.resultsContainer = 'Results';

	this.recallQuery = function(qid,kt) {
		var params = 'queryid='+qid;
		if(kt) {
			params += '&keeptime='+kt;
		}
		//openURL(RECALL_QUERY_URL, params, {}, processPostReturn, null);
		openURL(RECALL_QUERY_URL, params, {zoomToExtent: true}, processPostReturn, null);
	}

	function processPostReturn(req) {
		var p = document.getElementById(MySelf.resultsContainer);
		if(!req.responseXML && !req.responseText) {
			p.innerHTML = '<font color="red"><b><i>Map and Report Generation Cancelled by User.</i></b></font>';
			return false;
		}

		p.innerHTML = ''; /* Clear out the old content */


		var content = document.createElement('div');
		p.appendChild(content);

		/* Change rendering  behaviour based on Content-type */
		var contentType = req.getResponseHeader('Content-type');
		if(contentType.match(/xml/i)) {
			var xmlParser = new OpenLayers.Format.XML();
			var contentNodes = req.responseXML.getElementsByTagName('content');
			var html = '';
			for(var i =0; i < contentNodes.length; i++) {
				html += xmlParser.concatChildValues(contentNodes[i]);		
			}
			content.innerHTML = html;
			if(req.responseXML) {
				LayerManager.addLayersToMap(req.responseXML);
			}

			CurrentQuery = req.responseXML.documentElement.getAttribute('id');
		
			var ext = req.responseXML.documentElement.getAttribute('extent');
			if(ext && this.zoomToExtent) {
				Map.zoomToExtent(OpenLayers.Bounds.fromArray(ext.split(',')));
			}
		} else if(contentType.match(/plain/i)) {
			var text = req.responseText;
			text =text.replace('\n', '<br/>\n','g');
			content.innerHTML = text;
		} else {
			content.innerHTML = req.responseText;
		}

	}

	function createButton(title) {
		var button = document.createElement('input');
		button.type = 'button';
		button.value = title;
		return button;
	}
	
	var MySelf = this;

	function getTask(taskName) {
		var taskXML = Tasks[taskName];
		if(taskXML) {
			return taskXML;
		} else {
			alert(Messages['NO_REPORT_FOUND']+taskName);
			return false;
		}
	}

	this.startTask = function(parentId, taskName) {
		var taskXML = getTask(taskName);
		if(taskXML) {
			if(taskXML.getAttribute('variables')) {
				setTaskVariables(new String(taskXML.getAttribute('variables')));
			}
			MySelf.renderStep(parentId, taskXML, 0);
		}
	}

	this.shapeObjectsEqual = function(shpA,shpB) {
		var attributes = ['wkt', 'inner', 'outer', 'buffer', 'start', 'end',
					'layer', 'bounds'];
		var match = true;
		var a = 0;
		while(match && a < attributes.length) {
			var attr = attributes[a];
			if(isNaN(shpA[attr]) && isNaN(shpB[attr])) {
				match = match && true;
			} else {
				match = match && (shpA[attr] == shpB[attr]);
			}
			a++;
		}
		return match;
	}

	this.getShapeObject = function(step) {
		var testAttributes = ['inner','outer','buffer','start','end'];
		var obj = {
			"wkt" : step.getAttribute('wkt'),
			"inner" : parseFloat(step.getAttribute('inner')),
			"outer" : parseFloat(step.getAttribute('outer')),
			"buffer" : parseFloat(step.getAttribute('buffer')),
			"start" : parseFloat(step.getAttribute('start')),
			"end" : parseFloat(step.getAttribute('end')),
			"layer" : step.getAttribute('layer'),
			"bounds" : step.getAttribute('bounds')
		};
		for(var a = 0; a < testAttributes.length; a++) {
			if(isNaN(obj[testAttributes[a]])) { obj[testAttributes[a]] = ''; }
		}
		return obj;
	}

	this.getShapeObjects = function() {
		var shapeArray = new Array();
		for(var taskName in Tasks) {
			var task = Tasks[taskName];
			var steps = task.getElementsByTagName('step');
			for(var i = 0; i < steps.length; i++) {
				if(steps[i].getAttribute('wkt')) {
					shapeArray.push(MySelf.getShapeObject(steps[i]));
				}
			}
		}
		return shapeArray;
	}

	function loadedTasks(response) {
		var tasksXML = response.responseXML;
		this.xmlDoc = tasksXML;

		if(tasksXML.documentElement.getAttribute('extent')) {
			Map.zoomToExtent(OpenLayers.Bounds.fromString(tasksXML.documentElement.getAttribute('extent')));
		}
		var tasks = tasksXML.getElementsByTagName('task');
		for(var t = 0; t < tasks.length; t++) {
			Tasks[tasks[t].getAttribute('id')] = tasks[t];
		}
		this.onLoadedTasks(tasksXML);
	}

	this.onLoadedTasks = function() { }

	this.loadTasks = function(url) {
		OpenLayers.loadURL(url, "", this, loadedTasks);
	}

	var wwwRenderers = new Array();

	wwwRenderers['text'] = function (fieldXML) {
		if(fieldXML.getAttribute('value')) {
			return fieldXML.getAttribute('name')+'='+fieldXML.getAttribute('value');
		} else {
			return fieldXML.getAttribute('name')+'=';
		}
	}
	wwwRenderers['hidden'] = wwwRenderers['text'];

	wwwRenderers['extent'] = function(fieldXML) {
		var wwwStr = new String();
		var name = fieldXML.getAttribute('name');

		var extent = Map.getExtent();
		var extentString = (new Array(extent.left, extent.bottom, extent.right, extent.top)).join(',');
		return name+'='+extentString;
	}

	wwwRenderers['select'] = function(fieldXML) {
		var wwwStr = new String();
		var name = fieldXML.getAttribute('name');
		var options = fieldXML.getElementsByTagName('option');
		var appendSymbol = ''
		for(var i = 0; i < options.length; i++) {
			if(new String(options[i].getAttribute('selected')).match(/true/i)) {
				wwwStr += appendSymbol+name+'='+options[i].getAttribute('value');
			}
			appendSymbol = '&';
		}
		return wwwStr;
	}

	wwwRenderers['select1'] = wwwRenderers['select'];
	wwwRenderers['checkbox'] = function(fieldXML) {
		if(new String(fieldXML.getAttribute('selected')).match(/true/i)) {
			return fieldXML.getAttribute('name')+'='+fieldXML.getAttribute('value');
		}
		return '';
	}


	this.getPostData = function(taskName,xml) {
		var taskXML = getTask(taskName);

		if(!xml) { xml = false; } /* Do an XML Post */

		if(taskXML) {
			if(!xml) { /* www url encoding */
				var wwwStr = '';
				var fields = taskXML.getElementsByTagName('field');
				for(var i = 0; i < fields.length; i++) {
					var rend = wwwRenderers[fields[i].getAttribute('type')];
					if(rend) {
						wwwStr += '&'+rend(fields[i]);
					}
				}

				var steps  = taskXML.getElementsByTagName('step');
				for(var i = 0 ; i < steps.length; i++) {
					var stepType = steps[i].getAttribute('type');
					name = steps[i].getAttribute('name');
					if(stepType && stepType.match(/select/i)) {
						//wwwStr += '&'+name+'='+steps[i].getAttribute('wkt');
						var shapeAttributes = ['wkt','buffer','inner','outer','layer','start','end'];
						for(var attr = 0; attr < shapeAttributes.length; attr++) {
							var val = steps[i].getAttribute(shapeAttributes[attr]);
							if(val == null || val == 'null') {
								wwwStr += '&' + name + '_' + shapeAttributes[attr] + '=';
							} else if(isNaN(parseFloat(val))) {
								wwwStr += '&' + name + '_' + shapeAttributes[attr]
										+ '=' + val;
							} else {
								wwwStr += '&' + name + '_' + shapeAttributes[attr] 
										+ '=' + parseFloat(val)*1609.3;
							}
						}
					}
				}
				return wwwStr;
			} else { /* Do an XML Post of the task */
			}
		}
	}
}


var Map;
var LayerManager;
var MapControls = new Array();
var TaskManager = new GRITaskManager();
var NavigationHistory;

var ImageType = 'image/png';

function init() {
	ImageType = browserImageType();
	Map = new OpenLayers.Map("right-pane", {projection: PROJECTION_STRING,
		units: 'm',
		resolutions: MAP_RESOLUTIONS,
		maxExtent : OpenLayers.Bounds.fromArray(MAP_MAXEXTENT), controls: []});

	var NArrow = new NorthArrow(Map, 'NorthArrow');
	var SBar = new Scalebar(Map, 'Scalebar');

	NArrow.init();
	SBar.init();

	LayerManager = new GRILayers(Map, 'layers-tab', 'legends');
	LayerManager.init();

	/* start the navigation history */
	NavigationHistory = new GRINavigatorHistory(Map);
	
	/* from search.js */
	populateSearchDropdown('SearchSelect');

	var urlArgs = OpenLayers.Util.getArgs();

	/* We need to load a base-layer before all this navigation business can 
		go down */
	LayerManager.onLoaded = function () {

		/* recall the previous query */
		if(urlArgs.queryid) {
			recallQuery(urlArgs.queryid, urlArgs.keeptime);
		}
		
		/* Turn layers on from url */
		if(urlArgs.layers) {
			var urlLayers = new String(urlArgs.layers).split(',');
			for(var i = 0; i < urlLayers.length; i++) {
				try {
					this.setLayerVisibility(urlLayers[i], true);
				} catch(e) {
				}
			}
		}
		/* Turn layers off from url */
		if(urlArgs.layersoff) {
			var urlLayers = new String(urlArgs.layersoff).split(',');
			for(var i = 0; i < urlLayers.length; i++) {
				try {
					this.setLayerVisibility(urlLayers[i], false);
				} catch(e) {
				}
			}
		}

		if(urlArgs.center) {
			zoomLevel = 5;
			var coordsArr = new String(urlArgs.center).split(',');
			zoomCenter = new OpenLayers.LonLat(coordsArr[0],coordsArr[1]);
			if(urlArgs.zoom) {
				zoomLevel = parseInt(urlArgs.zoom);
			}
			Map.setCenter(zoomCenter, zoomLevel);
		} else if(urlArgs.mapext) {
			zoomBounds = OpenLayers.Bounds.fromString(new String(urlArgs.mapext));
			Map.zoomToExtent(zoomBounds);
		} else {
			Map.zoomToMaxExtent();
		}
	}
	
	LayerManager.loadLayers(LAYERS_URL);

	Map.addControl(new OpenLayers.Control.PanZoomBar());
	Map.addControl(new OpenLayers.Control.Navigation());
	Map.addControl(new OpenLayers.Control.MousePosition());
	Map.addControl(new OpenLayers.Control.ScaleLine());

	/* Check to see if we need to load up a search */
	if(urlArgs.search && urlArgs.searchvalue) {
		callSearch(urlArgs.search, urlArgs.searchvalue,
			'search-results','searching');
		document.getElementById('search-value').value = urlArgs.searchvalue;
	}

	/* Load the tasks */

	TaskManager.resultsContainer = 'results-tab';
	TaskManager.onLoadedTasks = createReportsMenu;
	/*TaskManager.onCancel = onCancelReport;*/
	TaskManager.onWait = waitingForReport;
	if(urlArgs.tasks) {
		TaskManager.loadTasks(urlArgs.tasks);
	} else {
		TaskManager.loadTasks(TASKS_URL);
	}
}


function createReportsMenu(xml) {
	var tasks = xml.getElementsByTagName('task');
	var reportsTab = document.getElementById('analysis-tab');
	var list = document.createElement('ul');
	reportsTab.appendChild(list);
	for(var i = 0; i < tasks.length; i++) {
		var li = document.createElement('li');
		list.appendChild(li);
		var a = document.createElement('a');
		a.setAttribute('href',"javascript:TaskManager.startTask('analysis-tab','"+tasks[i].getAttribute('id')+"')");
		li.appendChild(a);
		a.appendChild(document.createTextNode(tasks[i].getAttribute('title')));
//		reportsTab.appendChild(document.createElement('br'));
	}
	if(DEFAULT_TASK) {
		TaskManager.startTask('analysis-tab', DEFAULT_TASK);
	} else {
		showReportsMenu();
	}

}

function browserImageType() {
	var name = new String(navigator.userAgent).toLowerCase();
	var supported = {
		'safari' : 2,
		'netscape' : 7,
		'opera' : 8,
		'firefox' : 0,
		'msie' : 7
	};
	for(var s in supported) {
		var nameLoc = name.indexOf(s);
		var versionLoc = nameLoc + s.length + 1;
		if(nameLoc >= 0 &&  parseFloat(name.substring(versionLoc, versionLoc+3)) >= supported[s]) {
			return 'image/png';
		}
	}
	return 'image/gif';
}



function waitingForReport() {
	changeTab('results-tabbtn','results-tab');
	document.getElementById('results-tab').innerHTML = 
		document.getElementById('waiting').innerHTML;
}


function deactivateMapTools() {
	for(var c in MapControls) {
		MapControls[c].deactivate();
	}
}
function activateMapTool(mapToolTitle) {
	deactivateMapTools();
	if(MapControls[mapToolTitle]) {
		MapControls[mapToolTitle].activate();
	}
}

/* Pulls together information to create a link from the app */
function linkToMe() {
	var mapext = Map.getExtent();
	var extString = [mapext.left, mapext.bottom, mapext.right, mapext.top].join(',');

	var params = new Array();
	params.push('mapext='+extString);
	var queryId = TaskManager.getQueryId();
	if(queryId) {
		params.push('queryid='+queryId);
	}
	params.push('layers='+LayerManager.getActiveLayers().join(','));

	var url = new String(window.location);
	/* Called with parameters, easy split */
	if(url.indexOf('?') >= 0) {
		url = url.substring(0, url.indexOf('?'));
	}
	url = url.replace('#','');
	window.location = url+'?'+params.join('&');
}

function recallQuery(qid,kt) {
	TaskManager.recallQuery(qid,kt);
	document.getElementById('results-tabbtn').onclick();
}

/*
 * Javascript functions to support the new layout
 */

function changeTab(buttonId, tabId) {
	var tab = document.getElementById(tabId);
	var p = tab.parentNode;
	for(var i = 0; i < p.childNodes.length; i++) {
		var clName = new String(p.childNodes[i].className);
		if(clName.match(/tabcontent/)) {
			p.childNodes[i].className =
				clName.replace('visible','hidden');
		}
	}

	tab.className = new String(tab.className).replace('hidden','visible');

	var button = document.getElementById(buttonId);
	p = button.parentNode;
	for(var i = 0; i < p.childNodes.length; i++) {
		if(p.childNodes[i].className == 'tab-active') {
			p.childNodes[i].className = 'tab-inactive';
		}
	}
	button.className = 'tab-active';
}

var LastActiveTool = false;

function sleepCurrentTool() {
	LastActiveTool = false;
	for(var c in MapControls) {
		if(MapControls[c].active) {
			LastActiveTool = c;
		}
	}
	deactivateMapTools();
}

function awakeTool() {
	if(LastActiveTool != false) {
		activateMapTool(LastActiveTool);
	}
}

function toggleTabs() {
	var body = document.getElementById('body');
	var clName = new String(body.className);
	if(clName.match(/NoLeft/)) {
		clName = '';
	} else {
		clName = 'NoLeft';
	}
	body.className = clName;
	Map.updateSize();
}

function openHelp(event) {
	var obj;
	if(window.event) {
		window.event.cancelBubble = true;
		obj = window.event.srcElement;
	} else if(event.stopPropagation) {
		event.stopPropagation();
		obj = event.target;
	}
	var help = obj.getAttribute('value');
	if(HelpLinks[help]) {
		window.open(HelpLinks[help],'','height=300,width=1024,scrollbars=1');
	} else {
		alert('No contextual help found for item: "'+help+'".');
	}
	return false;
}

function createHelpLink(pId, helpContext) {
	var p = document.getElementById(pId);
	var helpLink = document.createElement('a');
	p.appendChild(helpLink);
	helpLink.setAttribute('value', helpContext);
	helpLink.className = 'context-help';
	helpLink.onclick = openHelp;
	helpLink = null;
	p = null;

}


function closeDialog(id) {
	var e = document.getElementById(id);
	e.parentNode.removeChild(e);
}

function getSavedSettings(r) {
	//window.open('cgi-bin/getSettings.py?id='+r.responseText);

	var eTest = document.getElementById('save-dialog');
	if(eTest) { return false; } /* Dialog is already being shown */

	var body = document.getElementsByTagName('body')[0];
	var saveDialog = document.createElement('div');
	saveDialog.id = 'save-dialog';

	var infoDiv = document.createElement('div');
	infoDiv.className = 'DialogInfo';
	saveDialog.className = 'Dialog';

	body.appendChild(saveDialog);

	saveDialog.appendChild(infoDiv);
	infoDiv.innerHTML = 'Settings need to be saved to disk.  Clicking <b>"Save to Disk"</b> will open a dialog asking you where you wish to place the file on disk.<br/>';

	cancelLink = document.createElement('a');
	cancelLink.id = 'cancel-link'
	saveDialog.appendChild(cancelLink);

	cancelLink.className = 'control-icons control-cancel';
	var cancelLabel = document.createElement('span');
	cancelLabel.className = 'control-label';
	cancelLink.appendChild(cancelLabel);
	cancelLabel.appendChild(document.createTextNode('Cancel'));
	cancelLink.onclick = function () { closeDialog('save-dialog'); }
	cancelLink.href = '#';

	saveLink = document.createElement('a');
	saveDialog.appendChild(saveLink);
	saveLink.className = 'control-icons control-save';

	saveLink.id = 'save-link';
	var saveLabel = document.createElement('span');
	saveLabel.className = 'control-label';
	saveLink.appendChild(saveLabel);
	saveLabel.appendChild(document.createTextNode('Save to Disk'));
	saveLink.onclick = function () { closeDialog('save-dialog'); }
	saveLink.href = 'cgi-bin/getSettings.py?id='+r.responseText;
	saveLink.target = '_blank';

}

function saveSettings() {
	var xml = new OpenLayers.Format.XML();
	var node = TaskManager.xmlDoc.documentElement;
	node.setAttribute('extent', Map.getExtent().toArray().join(','));
	var str = xml.write(node);

	var req = new OpenLayers.Ajax.Request(
	    'cgi-bin/saveSettings.py',
	    {
		method: 'post',
		contentType: 'text/plain',
		postBody : str,
		onComplete : getSavedSettings
	    }
	);
}

function recallSettings(url) {
	TaskManager.loadTasks(url);
}

function startRecallSettings() {
	var eTest = document.getElementById('upload-iframe');
	if(eTest) { return false; } /* Dialog is already being shown */

	var iframe = document.createElement('iframe');
	iframe.id = 'upload-iframe';

	var body = document.getElementsByTagName('body')[0];
	body.appendChild(iframe);

	iframe.src = 'upload.html';
}


function closeUploadIframe() {
	var e = document.getElementById('upload-iframe');
	e.parentNode.removeChild(e);
}



