var mo;
if(!mo) {
	mo = {};
}
else if(typeof mo != "object") {
	throw new Error("mo already exists and is not an object");
}

if(!mo.gov) {
	mo.gov = {};
}
else if(typeof mo.gov != "object") {
	throw new Error("mo.gov already exists and is not an object");
}

/**
 * Set firebug console
 */
mo.gov.fbconsole = window.console;

/**
 * Define object clone function
 */
mo.gov.clone = function(obj){
    if(obj == null || typeof(obj) != 'object')
        return obj;
    var temp = new obj.constructor(); // changed (twice)

    for(var key in obj)
        temp[key] = mo.gov.clone(obj[key]);
    return temp;

}

/**
 * Object clone method
 * Should replace the clone method above with this one.
 * @return
 */
//Object.prototype.clone = function() {
//	  var newObj = (this instanceof Array) ? [] : {};
//	  for (i in this) {
//	    if (i == 'clone') continue;
//	    if (this[i] && typeof this[i] == "object") {
//	      newObj[i] = this[i].clone();
//	    } else newObj[i] = this[i]
//	  } return newObj;
//	};

mo.gov.StringBuffer = function() { 
	   this.buffer = []; 
}

mo.gov.StringBuffer.prototype.append = function append(string) { 
	   this.buffer.push(string); 
	   return this; 
}; 

mo.gov.StringBuffer.prototype.toString = function toString() { 
	   return this.buffer.join(""); 
}; 


mo.gov.calculateDistance = function(latlng1, latlng2) {
	return latlng1.distanceFrom(latlng2, 3959).toFixed(1);
}

mo.gov.distanceFromCurrentLocation = function(feature) {
	var featureLatLng = new GLatLng(feature.geometry.coordinates[1], feature.geometry.coordinates[0]);
	return featureLatLng.distanceFrom(mo.gov.CurrentLocation.userLatLng, 3959).toFixed(1);
}


/*
 * ###############################
 * Create the GeoDataDisplay Class.  
 * ###############################
 */
if(mo.gov.GeoDataDisplay) {
	throw new Error("mo.go.GeoDataDisplay already exists");
}

/**
 * Singleton constructor for GeoDataDisplay object
 * @param options
 * @constructor
 */
mo.gov.GeoDataDisplay = function(options) {
	if(typeof mo.gov.GeoDataDisplay.single_instance === 'undefined') {
		mo.gov.GeoDataDisplay.single_instance = this;
		mo.gov.GeoDataDisplay = this;
		this.visibleDataSets = 0;
		this.geocoder = new GClientGeocoder();	
		this.options = options;
		this.autoDetectUserLocation = options.autoDetectUserLocation;
		this.init(options);
	}
	return mo.gov.GeoDataDisplay.single_instance;
};

/**
 * Init function: Does nothing at this time
 * Looks at the list of dataset registered and builds a display panel.
 */
mo.gov.GeoDataDisplay.prototype.init = function(options) {
	if (mo.gov.fbconsole) {
		mo.gov.fbconsole.log("Initializing the the geo data display component");
	}
	
	$('#radiusDropDown').selectToUISlider({
		sliderOptions: {
		change: function(event, ui) {
			mo.gov.CurrentLocation.radiusSelection = ui.value * 10;
			mo.gov.CurrentLocation.setCurrentLocation();
		}
	}
	});
	mo.gov.CurrentLocation.radiusSelection = $('#radiusDropDown').val();
	

	mo.gov.CurrentLocation.setEventListeners();

	mo.gov.GeoDataPageRepository.displayAvailableDataSets();


	if(options.geoDataGrid) {
		mo.gov.GeoDataGrid = new mo.gov.GeoDataGrid();
		this.geoDataGrid = mo.gov.GeoDataGrid;
	}
	
	if(options.geoDataMap) {
		mo.gov.GeoDataMap = new mo.gov.GeoDataMap();
		mo.gov.GeoDataMap.init();
		this.geoDataMap = mo.gov.GeoDataMap;

	}
	
	//If there is only one dataset in the repository go ahead and display it.
	if(mo.gov.GeoDataPageRepository.size == 1) {
		for(var dataset in mo.gov.GeoDataPageRepository.dataSets) {
			$("#" + dataset).attr("checked", true);
			mo.gov.GeoDataPageRepository.dataSets[dataset].toggleData();		
		}
		$("#" + dataset + "_li").addClass("hide");
		
	}

};



/*
 * ###############################
 * Create the CurrentLocation Class
 * ###############################
 */

/**
 * @class
 */
mo.gov.CurrentLocation = {radiusSelection:10};

/**
 * @member mo.gov.CurrentLocation
 */
mo.gov.CurrentLocation.setEventListeners = function(){
	$("#currentLocation").toggleClass('hide');
	
	$("#setLocationButton").bind('click', function(){
		if (mo.gov.fbconsole) {
			mo.gov.fbconsole.log("click event currentlocation changed");
		}
		mo.gov.CurrentLocation.setCurrentLocation();
		});
	
	$("#locationString").bind('change', function(){
		if (mo.gov.fbconsole) {
				mo.gov.fbconsole.log("change event currentlocation changed");
				mo.gov.fbconsole.log("geocode " + $(this).val());
			}
			mo.gov.CurrentLocation.setCurrentLocation();
			
		});
	
	$("#radiusSelection").bind('change', function(){
		mo.gov.CurrentLocation.setCurrentLocation();
	});

}

mo.gov.CurrentLocation.setCurrentLocation = function() {
	mo.gov.CurrentLocation.userLatLng = null;
	
	if($("#locationString").val().length > 0 && $("#locationString").val() != 'zip code or city') {
		mo.gov.CurrentLocation.geoCodeLocation($("#locationString").val());		
		mo.gov.CurrentLocation.userLocationString = $("#locationString").val();
	}
	else if (mo.gov.GeoDataDisplay.autoDetectUserLocation) {
		if (google.loader.ClientLocation && google.loader.ClientLocation.address.region == "MO"){
			$("#IPlocation").toggleClass('hide');
			$('#locationString').val(google.loader.ClientLocation.address.city);
			$("#city").html(google.loader.ClientLocation.address.city + " ");
			mo.gov.CurrentLocation.geoCodeLocation(google.loader.ClientLocation.address.city);
			mo.gov.CurrentLocation.userLocationString = google.loader.ClientLocation.address.city;
		}
	} 
	
	$("#radius").html(mo.gov.CurrentLocation.radiusSelection);
	
}

mo.gov.CurrentLocation.geoCodeLocation = function(locationString, callBackFn) {

	locationString = htmlentities(locationString);
	locationString = unescape(locationString);
	
	var geoCodeString;
	if(locationString.match(/^\d*$/)) {
	    geoCodeString = 'MO, ' + locationString;
	}
	else {
		geoCodeString = locationString + ', Missouri';
	}

	mo.gov.GeoDataDisplay.geocoder.getLocations(geoCodeString, function(georesponse){


	if(georesponse.Placemark.length > 1) {
		$("#geoCoderMessages").html('Could not find exact match for ' + georesponse.name + ', but did come up with following possible matches:<ul></ul>'  );
		for(var i=0; i<georesponse.Placemark.length; i++){
			placemark = georesponse.Placemark[i];
			var countryCode = null;
			if(placemark.AddressDetails && placemark.AddressDetails.Country){
				countryCode = placemark.AddressDetails.Country.CountryNameCode;
			}

			if(countryCode != null && countryCode == 'US') {
				var address = '<li><a href="#" onclick="mo.gov.CurrentLocation.geoCodeLocation(\'' + escape(georesponse.Placemark[i].address) + '\');$(\'#locationString\').val(\'' +  escape(georesponse.Placemark[i].address) + '\');return false;">' + georesponse.Placemark[i].address + '</a></li>';
				$("#geoCoderMessages ul").append(address);
			}
		}
	}
	else if(georesponse.Placemark.length == 1 && georesponse.Placemark[0].AddressDetails.Accuracy > 3 ) {
		$('#locationString').val(html_entity_decode(locationString));
		$("#geoCoderMessages").html('Found the following match: ' + georesponse.Placemark[0].address);
			mo.gov.CurrentLocation.userLatLng = new GLatLng(georesponse.Placemark[0].Point.coordinates[1], georesponse.Placemark[0].Point.coordinates[0]);
			if (mo.gov.fbconsole) {
				mo.gov.fbconsole.log("User current location has been set");
			}
			
			mo.gov.GeoDataMap.updateCurrentLocation();
			mo.gov.GeoDataGrid.show();
	}
   else {
   	$("#geoCoderMessages").html('Could not find a match or anything similar to ' + georesponse.name + '. Please try again.');
   }
	
});
};


/*
 * ###############################
 * Create the GeoDataPageRepository Class 
 * ###############################
 */
if(mo.gov.GeoDataPageRepository) {
	throw new Error("mo.go.GeoDataPageRepository already exists");
}

mo.gov.GeoDataPageRepository = {dataSets: {}};


/**
 * Add dataset
 */
mo.gov.GeoDataPageRepository.add = function(dataset){
	this.dataSets[dataset.dataSetID] = dataset;	
};


mo.gov.GeoDataPageRepository.displayAvailableDataSets = function() {
	// Build list of available datasets
	mo.gov.GeoDataPageRepository.size = 0;
	var html;
	for ( var dataset in mo.gov.GeoDataPageRepository.dataSets) {
		mo.gov.GeoDataPageRepository.size++;
		$("#geoDataSets ul").append('<li id="' + mo.gov.GeoDataPageRepository.dataSets[dataset].dataSetID + '_li\"><img class="smallMarker" src="' + mo.gov.GeoDataPageRepository.dataSets[dataset].mapLayer.markerOptions.icon + '" /> <input type="checkbox" name="' + mo.gov.GeoDataPageRepository.dataSets[dataset].dataSetID + '" id="' + mo.gov.GeoDataPageRepository.dataSets[dataset].dataSetID + '" />' +mo.gov.GeoDataPageRepository.dataSets[dataset].name + '</li>')
		
	}
	
	// Setup event handlers for datasets
	$("#geoDataSets input:checkbox").click(function(){
		mo.gov.GeoDataPageRepository.dataSets[this.id].toggleData();
	});
	
}


/*
 * ###############################
 * GeoDataGrid Class
 * ###############################
 */
if(mo.gov.GeoDataGrid) {
	throw new Error("mo.gov.GeoDataGrid already exists");
}

mo.gov.GeoDataGrid = function(){
		this.data = [];
		this.loadedDataSets = [];
		this.dataSets = {};
		return this;
};

mo.gov.GeoDataGrid.prototype.filterByCurrentLocation = function() {
	var features = [];
	var gridData = {};
	var currentLocation = mo.gov.CurrentLocation.userLatLng;
	var radius = parseInt(mo.gov.CurrentLocation.radiusSelection);
	
	for(var dataSet in this.dataSets) {
		gridData[dataSet] = [];
		for(var recordIndex in this.dataSets[dataSet]){
			var feature = this.dataSets[dataSet][recordIndex];
			if(currentLocation) {
				if(mo.gov.distanceFromCurrentLocation(this.dataSets[dataSet][recordIndex]) < radius) {
					var gridDisplayText = mo.gov.GeoDataPageRepository.dataSets[dataSet].gridLayer.createRecordText(feature);
					features.push({feature: feature, dataSetID: dataSet, gridDisplayText: gridDisplayText});
					//gridData[dataSet].push(this.dataSets[dataSet][recordIndex]);
				}
			}
			else {
				var gridDisplayText = mo.gov.GeoDataPageRepository.dataSets[dataSet].gridLayer.createRecordText(feature);
				features.push({feature: feature, dataSetID: dataSet, gridDisplayText: gridDisplayText});
				//gridData[dataSet].push(this.dataSets[dataSet][recordIndex]);
			}
		}
	
	}
	
	features.sort(function(a,b) {
		if(a.gridDisplayText.name == b.gridDisplayText.name){

			if(a.gridDisplayText.name == b.gridDisplayText.name){
				return 0;
			}

			return (a.gridDisplayText.name < b.gridDisplayText.name) ? -1 : 1;
		}

		return (a.gridDisplayText.name < b.gridDisplayText.name) ? -1 : 1;
	})
	
	return features;
}

mo.gov.GeoDataGrid.prototype.show = function(dataSetID) {
	if(mo.gov.GeoDataDisplay.visibleDataSets >= 1) {
		var gridRecords = mo.gov.GeoDataGrid.filterByCurrentLocation();
		
		var gridRecordsHashMap = {};
		
		var userLatLng = mo.gov.CurrentLocation.userLatLng;
		
		
		$("#geoDataGridContent").html("");
		
		if(gridRecords.length > 0) {
			var htmltable = new mo.gov.StringBuffer();
			htmltable.append('<table id="tableGrid">');
			htmltable.append('<tr><th>Name / Office Number</th><th>Address</th><th>City</th><th>Phone</th><th>Driving Directions</th><th><span class="hide">Details</span></th></tr>');
			for(var record  in gridRecords) {
					var feature = gridRecords[record].feature;
					var trRowID = gridRecords[record].feature.id;
					var gridDisplay = gridRecords[record].gridDisplayText;
					htmltable.append('<tr id="' + trRowID.replace(".","_") + '"><td>' + gridDisplay.name + '</td>' + '<td>' + gridDisplay.address + '</td>' +  '<td>' + gridDisplay.city + '</td>' +  '<td class="nowrap">' + gridDisplay.phone + '</td><td>');
					
					if(userLatLng) {
						htmltable.append('<a href="http://maps.google.com/maps?saddr=' + userLatLng.lat() + ',' + userLatLng.lng() + '&daddr=' + feature.geometry.coordinates[1] + ',' + feature.geometry.coordinates[0] +  '" target="_blank">Driving directions');
					}
					else {
						htmltable.append('');
					}
					
					htmltable.append('</td><td><div class="arrow" title="Expand or collapse for more or less details"><span class="hide">Expand or collapse for more or less details</span></div></td></tr>');
					htmltable.append('<tr id="' + trRowID.replace(".","_") + '_details"><td colspan="6" class="details"></td></tr>');
					
					gridRecordsHashMap[trRowID.replace(".","_")] = gridRecords[record];
			}
			
			htmltable.append('</table>');
			$("#geoDataGridContent").append(htmltable.toString());
			$("#tableGrid tr:odd").addClass("odd");
		    $("#tableGrid tr:not(.odd)").hide();
		    $("#tableGrid tr:not(.odd)").css('display', 'none');
		    $("#tableGrid tr:first-child").show();
		    
		    $("#tableGrid tr.odd").bind('click', {gridRecordsHashMap: gridRecordsHashMap}, function(){
		        var detailsRow = $(this).next("tr");

		        if(detailsRow.css('display') == 'none'){
		        	if($.browser.msie) {
		        		detailsRow.css('display', 'inline');
		        	}
		        	else {
		        		detailsRow.css('display', 'table-row');
		        	}
		        	$(this).find(".arrow").toggleClass("up");
		        	var trRowID = this.id;
		            var detailsText = mo.gov.GeoDataPageRepository.dataSets[gridRecordsHashMap[this.id].dataSetID].gridLayer.createDetailsText(gridRecordsHashMap[this.id].feature);
		            $("#" + trRowID.replace(".","_") + "_details td").html(detailsText);       	
		        }
		        else {
		        		detailsRow.css('display', 'none');
		        		$(this).find(".arrow").toggleClass("up");
		        }
		    });
		}
		else {
			$("#geoDataGridContent").append('There is no information to be displayed based upon your selection of a ' + mo.gov.CurrentLocation.radiusSelection + ' mile radius from ' + $("#locationString").val() +' .' );
		}
	    
	    
	}
	else {
		$("#geoDataGridContent").html('No data selected.  Please check the checkbox above for the data you would like to see.');
	}

}

mo.gov.GeoDataGrid.prototype.hide = function(dataSetID) {
	mo.gov.GeoDataGrid.dataSets[this.dataSetID] = this.json.features;
	mo.gov.GeoDataGrid.loadedDataSets[dataSetID] = {show: false};
	for(var record in this.data) {
		if(this.data[record].dataSetID == dataSetID){
			$("#" + this.data[record].recordID).toggleClass('hide');
		}
	}
}

/*
 * ###############################
 * Create GridLayer Class
 * ###############################
 */
if(mo.gov.GridLayer) {
	throw new Error("mo.gov.GridLayer already exists");
}

mo.gov.GridLayer = function(gridLayerConfig) {
	this.createRecordText = gridLayerConfig.createRecordText;
	this.createDetailsText = gridLayerConfig.createDetailsText;
	
}

mo.gov.GridLayer.prototype.addToMasterGrid = function() {
	// add to GeoDataGrid array
	var features = this.gridLayerData.json.features;
	for ( var i = 0; i < features.length; i++) {
		var recordText = this.createRecordText(features[i].properties);
		var latlng = features[i].geometry.coordinates;
		var glatlng = new GLatLng(latlng[1], latlng[0]);
		// Add data to master grid array
		mo.gov.GeoDataGrid.data.push({text: recordText, latLng: glatlng, dataSetID: this.gridLayerData.dataSetID, recordID: features[i].id.replace('.','_'), index: i});
	}
	
}

/*
 * ###############################
 * Create GridLayerConfig Class
 * ###############################
 */
if(mo.gov.GridLayerConfig) {
	throw new Error("mo.gov.GridLayerConfig already exists");
}

mo.gov.GridLayerConfig = function() {
	return this;
};

/*
 * Create GeoDataMap Class
 */
if(mo.gov.GeoDataMap) {
	throw new Error("mo.gov.GeoDataMap already exists");
}

mo.gov.GeoDataMap = function(){
	this.sideBarData={};
	return this;
}

mo.gov.GeoDataMap.prototype.init = function() {
	
	this.map = new GMap2(document.getElementById('map'));
	mo.gov.GeoDataMap.map.setCenter(new GLatLng('38.627888', '-92.566524'), 7);
	this.map.setUIToDefault();
	
	
}

mo.gov.GeoDataMap.prototype.createMarker = function(markerdata) {
	var marker = new GMarker(new GLatLng(markerdata.latitude, markerdata.longitude));
	this.map.addOverlay(marker);
	GEvent.addListener(marker, 'click', function() {
		marker.openInfoWindowTabsHtml(mo.gov.GeoDataMap.createInfoWindow(markerdata));
	});
	return marker;
}

mo.gov.GeoDataMap.prototype.createInfoWindow = function(markerdata) {
	var html = "<div>";
	html += markerdata.locationName + "<br/>";
	html += "<div/>";
	return html;
}


mo.gov.GeoDataMap.prototype.updateCurrentLocation = function() {
	if (mo.gov.CurrentLocation.marker) {
		 mo.gov.CurrentLocation.marker.remove();
	}
	
	if(mo.gov.CurrentLocation.userLatLng){
		mo.gov.CurrentLocation.marker = mo.gov.GeoDataMap.createMarker({
	       latitude: mo.gov.CurrentLocation.userLatLng.lat(),
	       longitude: mo.gov.CurrentLocation.userLatLng.lng(),
	       locationName: mo.gov.CurrentLocation.userLocationString
		})
		
		mo.gov.GeoDataDisplay.geoDataMap.map.setCenter(mo.gov.CurrentLocation.userLatLng);
		mo.gov.GeoDataDisplay.geoDataMap.map.setZoom(10);
	}
	
}

mo.gov.GeoDataMap.prototype.displaySideBar = function() {
	var mergedSideBarData = [];
	for(var dataSetID in this.sideBarData) {
		for(var recordIndex in this.sideBarData[dataSetID]) {
			mergedSideBarData.push(this.sideBarData[dataSetID][recordIndex]);
		}
	}
	
	mergedSideBarData.sort(function(a,b) {
	
		if(a.displayString == b.displayString){

			if(a.displayString == b.displayString){
				return 0;
			}

			return (a.displayString < b.displayString) ? -1 : 1;
		}

		return (a.displayString < b.displayString) ? -1 : 1;
	})
	
	$("#sidebar ul").html("");
	if(mergedSideBarData.length > 0){
	for(var index in mergedSideBarData) {
		if (mo.gov.fbconsole) {
			mo.gov.fbconsole.log(mergedSideBarData[index].marker.getIcon());
		}
		var icon = mergedSideBarData[index].marker.getIcon();
		$("#sidebar ul").append('<li><img class="smallMarker" src="' + icon.image + '" /><a href="#" onclick="Clusterer.showMarker(' + mergedSideBarData[index].marker.path + ');return false;">'+ mergedSideBarData[index].displayString + '</a></li>');
	}
	}
	else {
		$("#sidebar ul").append('<li>No data selected.  Please check the checkbox above for the data you would like to see.</li>');
	}
}

/*
 * ###############################
 * Create GeoDataMapLayer Class
 * ###############################
 */
if(mo.gov.MapLayer) {
	throw new Error("mo.gov.MapLayer already exists");
}

mo.gov.MapLayer = function(mapLayerConfig) {
	/* Either a WMS and WFS layer */
	this.mapServiceType = mapLayerConfig.mapServiceType || 'WFS';
	this.buildInfoWindow = mapLayerConfig.buildInfoWindow;
	this.infoWindowOptions = mapLayerConfig.infoWindowOptions;
	this.markerOptions = mapLayerConfig.markerOptions;
	this.sideBarFn = mapLayerConfig.sidebarFn;
	this.clusterer;
	this.markers = [];
	//this.map = mo.gov.GeoDataDisplay.geoDataMap.map;
	return this;
};

mo.gov.MapLayer.prototype.show = function() {
	if(this.markers.length < 1) {
		this.createMarkers();
	}
	else {
		this.clusterer  = null;
		clusterer = new Clusterer(mo.gov.GeoDataDisplay.geoDataMap.map);
		clusterer.layerID = this.layerData.dataSetID;
		var clustericon = MapIconMaker.createFlatIcon({primaryColor: this.markerOptions.color, labelColor: '000000', label: "markerCluster"});
	
		clusterer.SetMaxVisibleMarkers(6);
		clusterer.SetMinMarkersPerCluster(3)
		clusterer.SetMaxLinesPerInfoBox(25);
		clusterer.SetIcon(clustericon);
		
		for ( var i = 0; i < this.markers.length; i++) {
			this.markers[i].inCluster = false;
			clusterer.AddMarker(this.markers[i], this.markers[i].title);
		}
		this.clusterer = clusterer;
	}

};

mo.gov.MapLayer.prototype.hide = function() {
	
	var markers = this.clusterer.markers;
	for ( var i = 0; i < markers.length; i++) {
		this.clusterer.RemoveMarker(markers[i]);
	}
	this.clusterer = null;
}


mo.gov.MapLayer.prototype.createMarkers = function() {
	var icon = new GIcon();
	icon.infoWindowAnchor = new GPoint(16, 0);
	icon.iconSize = new GSize(32, 32);
	icon.shadowSize = new GSize(32, 32);
	icon.iconAnchor = new GPoint(16, 32);
	icon.image = this.markerOptions.icon;
	
	var clustericon = MapIconMaker.createFlatIcon({primaryColor: this.markerOptions.color, labelColor: '000000', label: "markerCluster"});

	iwoptions = this.infoWindowOptions;

	clusterer = new Clusterer(mo.gov.GeoDataDisplay.geoDataMap.map);
	clusterer.layerID = this.layerData.dataSetID;
	clusterer.SetMaxVisibleMarkers(20);
	clusterer.SetMinMarkersPerCluster(3)
	clusterer.SetMaxLinesPerInfoBox(25);
	clusterer.SetIcon(clustericon);
	var coords = {};

	var features = this.layerData.json.features;
	for ( var i = 0; i < features.length; i++) {
		var title = '';
		if (features[i].properties[this.markerOptions.titleProperty].length > 0) {
			title = features[i].properties[this.markerOptions.titleProperty];
		}

		var latlng = features[i].geometry.coordinates;
	
		// Check to see if this marker has exact coordinates of another marker
		var hash = latlng[0].toString() + latlng[1].toString();
		hash = hash.replace(".","").replace(",", "").replace("-","");

		if(coords[hash] == null) {
		  coords[hash] = 1;
		} else {
		  latlng[0] = latlng[0] + (Math.random() -.5) / 1500;
		  //latlng[1] = latlng[1] + (Math.random() -.2) / 1500;

		}
			
		var marker = new GMarker(new GLatLng(latlng[1], latlng[0]), {
			title : title,
			icon : icon
		});

		marker.data = features[i];
		marker.layerID = this.layerData.dataSetID;
		marker.path = 'mo.gov.GeoDataPageRepository.dataSets[\'' +  this.layerData.dataSetID + '\'].mapLayer.markers[' + i +']';
		this.markers[i] = marker;

		GEvent.addListener(this.markers[i], "click", this.infowindowFn(marker, "defaulttext"));

		GEvent.addListener(this.markers[i], "click2", this.infowindowFn(marker, "toHere"));

		GEvent.addListener(this.markers[i], "click3", this.infowindowFn(marker, "fromHere"));

		GEvent.addListener(this.markers[i], "click4", this.infowindowFn(marker, "search"));

		this.markers[i] = marker;
		clusterer.AddMarker(marker, title);
		
	}

	this.isLoaded = true;
	this.clusterer = clusterer;
}

mo.gov.MapLayer.prototype.infowindowFn = function(marker, trigger) {
	return function() {
		var infoWindowFooter = mo.gov.GeoDataPageRepository.dataSets[this.layerID].mapLayer.getDirectionsFooter(marker);
		var infoWindowContent = mo.gov.GeoDataPageRepository.dataSets[this.layerID].mapLayer.buildInfoWindow(marker);
		infoWindowContent += infoWindowFooter[trigger];
		mo.gov.GeoDataDisplay.geoDataMap.map.setCenter(marker.getLatLng());
		marker.openInfoWindowHtml(infoWindowContent, iwoptions);
	}
}

mo.gov.MapLayer.prototype.getDirectionsFooter = function(marker) {
	var point = marker.getLatLng();
	
	var defaulttext = '<div class="directions">' + 'Get Directions: <a href="#" onclick="GEvent.trigger('+ marker.path + ',\'click2\');return false;">To Here</a> - ' 
		+ '<a href="#" onclick="GEvent.trigger('	+ marker.path + ',\'click3\');return false;">From Here</a><br>' + '<a href="#" onclick="GEvent.trigger('
		+ marker.path + ',\'click4\');return false;">Search nearby</a> | <a href="#" onclick="' + 'mo.gov.GeoDataDisplay.geoDataMap.map.setCenter(new GLatLng(' + point.lat() + ',' + point.lng() + '),' + 10 + ');return false;">Zoom Here</a></div>';

	var toHere = '<div >' + 'Get Directions: To here - ' + '<a href="#" onclick="GEvent.trigger('	+ marker.path + ',\'click3\');return false;">From Here</a><br>' 
		+ 'Start address:<form action="http://maps.google.com/maps" method="get" target="_blank">' + '<input type="text" SIZE=35 MAXLENGTH=80 name="saddr" id="saddr" value="" />'
		+ '<INPUT value="Go" TYPE="SUBMIT">' + '<input type="hidden" name="daddr" value="' + point.lat() + ',' + point.lng() + '"/>' + '<br><a href="#" onclick="GEvent.trigger('
		+ marker.path + ',\'click\');return false;"> Back</a>| <a href="#" onclick="' + 'mo.gov.GeoDataDisplay.geoDataMap.map.setCenter(new GLatLng(' + point.lat() + ',' + point.lng() + '),' + 10 + ');return false;">Zoom Here</a></div>';

	var fromHere = '<div >' + 'Get Directions: <a href="#" onclick="GEvent.trigger('	+ marker.path + ',\'click2\');return false;">To Here</a> - ' + 'From Here<br>' 
		+ 'End address:<form action="http://maps.google.com/maps" method="get"" target="_blank">' + '<input type="text" SIZE=35 MAXLENGTH=80 name="daddr" id="daddr" value="" />'
		+ '<INPUT value="Go" TYPE="SUBMIT">' + '<input type="hidden" name="saddr" value="' + point.lat() + ',' + point.lng() + '"/>' + '<br><a href="#" onclick="GEvent.trigger('
		+ marker.path + ',\'click\');return false;"> Back</a> | <a href="#" onclick="' + 'mo.gov.GeoDataDisplay.geoDataMap.map.setCenter(new GLatLng(' + point.lat() + ',' + point.lng() + '),' + 10 + ');return false;">Zoom Here</a></div>';

	var search = '<div >' + 'Search nearby: e.g. "pizza"<br>' + '<form action="http://maps.google.com/maps" method="get"" target="_blank">' + '<input type="text" SIZE=35 MAXLENGTH=80 name="q" id="q" value="" />'
			+ '<INPUT value="Go" TYPE="SUBMIT">' + '<input type="hidden" name="near" value="' + name + ' @' + point.lat() + ',' + point.lng() + '"/>' + '<br><a href="#" onclick="GEvent.trigger('
			+ marker.path + ',\'click\');return false;"> Back</a> | <a href="#" onclick="' + 'mo.gov.GeoDataDisplay.geoDataMap.map.setCenter(new GLatLng(' + point.lat() + ',' + point.lng() + '),' + 10 + ');return false;">Zoom Here</a></div>';

	return {
		defaulttext : defaulttext,
		toHere : toHere,
		fromHere : fromHere,
		search : search
	};

}


/*
 * ###############################
 * Create MapLayerConfig Class
 * ###############################
 */
if(mo.gov.MapLayerConfig) {
	throw new Error("mo.gov.MapLayerConfig already exists");
}

mo.gov.MapLayerConfig = function() {
	return this;
};


/*
 * ###############################
 * Create DataSet Class
 * ###############################
 */
if(mo.gov.DataSet) {
	throw new Error("mo.gov.DataSet already exists");
}

mo.gov.DataSet = function() {
	this.dataSetID;
	return this;
};

mo.gov.DataSet.prototype.registerWithRepository = function() {

	mo.gov.GeoDataPageRepository.add(this);
}

mo.gov.DataSet.prototype.getData = function(showDataCallBackFn) {
	$.getJSON(this.dataURL, getDataCallbackFn(this, showDataCallBackFn));
	
	function getDataCallbackFn(dataSet, showDataCallBackFn) {
		return function(data) {
		dataSet.json = data;
		showDataCallBackFn.call(dataSet);
		}
	}
}

mo.gov.DataSet.prototype.toggleData = function() {
	
	var showDataCallBackFn = function() {
		if(mo.gov.GeoDataDisplay.geoDataMap) {
			this.mapLayer.show();	
		}
		
		if(mo.gov.GeoDataDisplay.geoDataGrid) {
			mo.gov.GeoDataGrid.dataSets[this.dataSetID] = this.json.features;
			mo.gov.GeoDataGrid.show(this.dataSetID);
		}
	}
	
	if($('#' + this.dataSetID).attr("checked")) {
		mo.gov.GeoDataDisplay.visibleDataSets++;
		if(!this.json) {
			this.getData(showDataCallBackFn);
		}
		else {
			showDataCallBackFn.call(this);
		}
	}
	else {
		mo.gov.GeoDataDisplay.visibleDataSets--;
		
		if(mo.gov.GeoDataDisplay.visibleDataSets == 0) {
			$("#geoDataGridContent").html('');
		}
		else {
			mo.gov.GeoDataGrid.dataSets[this.dataSetID] = null;
			mo.gov.GeoDataGrid.show(this.dataSetID);
		}

		this.mapLayer.hide();


		
	}
	
}







