
// Class for describing embedded OpenLayers map
// Written by John Westwood and Decio Battaglia
// 2007-2009
function EmbeddedMap(mapDiv)
{
	// Create OpenLayers map object and add the controls
	this.map = new OpenLayers.Map(mapDiv, { resolutions: [4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 2048.0, 4096.0],
					     maxExtent: new OpenLayers.Bounds(0, 0, 8388608, 8388608),
					     restrictedExtent: new OpenLayers.Bounds(600000, 0, 7300000, 6700000),
					     tileSize: new OpenLayers.Size(256, 256),
					     controls: [],
					     theme: null,
					     projection: "epsg:3034",
					     units: "m" 
					   } );

	// Define the single click "Tell Me More" control
	this.clickControl = new OpenLayers.Control.Click( { handlerOptions: { "single": true, "double": false } } );

	// Add the controls
	this.map.addControl(this.clickControl);
	this.map.addControl(new OpenLayers.Control.Navigation());
	this.map.addControl(new OpenLayers.Control.PanZoomBar());
	this.map.addControl(new OpenLayers.Control.ScaleLine());

	// Declare the mapLayers array
	this.mapLayers = [];
}

// toggleClickControl, get the single click control handler
EmbeddedMap.prototype.toggleClickControl = function()
{
	if(this.clickControl.active)
	{
		this.clickControl.deactivate();
	}
	else
	{
		this.clickControl.activate();
	}
}

// defineMapLayer, adds a base layer definition to the mapLayer array
EmbeddedMap.prototype.defineMapLayer = function(newMapLayer)
{
	this.mapLayers.push(newMapLayer);
}

// setRequestedLayer, makes the requested base layer the visible layer
EmbeddedMap.prototype.setRequestedLayer = function(requestedLayer)
{
	if(!this.mapLayers)
	{
		return;
	}

	for(var i = 0; i < this.mapLayers.length; i++)
	{
		if(this.mapLayers[i].params["LAYERS"] == requestedLayer)
		{
			this.map.setBaseLayer(this.mapLayers[i]);
			return;
		}
	}

	// Set the default active base layer, in case selected fails
	this.map.setBaseLayer(this.mapLayers[0]);
}

// setExtent, sets the extent to the location and nearest zoom level
EmbeddedMap.prototype.setExtent = function(xMin, yMin, xMax, yMax)
{
	this.map.zoomToExtent(new OpenLayers.Bounds(xMin, yMin, xMax, yMax), true);
}

// setCenter, sets the map center and zoom level
EmbeddedMap.prototype.setCenter = function(lon, lat, zoom)
{
	this.map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);
}

// addMapLayers method, adds the array of defined mapLayers to the map
EmbeddedMap.prototype.addMapLayers = function()
{
	if(this.mapLayers)
	{
		this.map.addLayers(this.mapLayers);
	}
}

// getOpenLayersMap method, returns the OpenLayers map object
EmbeddedMap.prototype.getOpenLayersMap = function()
{
	return this.map;
}

EmbeddedMap.prototype.render = function(div)
{
	this.map.render(div);
}

// getMapLayerName method, returns the layer name(s) of the currently active base layer
EmbeddedMap.prototype.getMapLayerName = function()
{
	return this.map.baseLayer.params["LAYERS"];
}

// getSize method, returns the map size as a size object;
// use .w to retrieve the width and .h to retrieve the height
EmbeddedMap.prototype.getSize = function()
{
	return this.map.size;
}

// getScale method, returns the current scale
EmbeddedMap.prototype.getScale = function()
{
	return this.map.getScale();
}

// getExtent method, returns the extent of the current map view
// The return type is an extent object;
EmbeddedMap.prototype.getExtent = function()
{
	return this.map.getExtent();
}

// getLonLatFromViewPortPx, retrieve the world coordinates for a set of specified
// view port coordinates
EmbeddedMap.prototype.getLonLatFromViewPortPx = function(xy)
{
	return this.map.getLonLatFromViewPortPx(xy);
}

// getCenter method, returns the real-world center coordinates of the current extent
// The return type is a coordinate pair; use .lat to retrieve the latitude
// and .lon to retrieve the longitude 
EmbeddedMap.prototype.getCenter = function()
{
	return this.map.getCenter();
}

// getZoomLevel method, returns the current zoom level as an integer
EmbeddedMap.prototype.getZoom = function()
{
	return this.map.getZoom();
}


//
// GreatBritainMap inherits from EmbeddedMap
//
function GreatBritainMap(mapDiv, requestedLayer, xMin, yMin, xMax, yMax)
{
	EmbeddedMap.call(this, mapDiv);

	// Define the base layers
	EmbeddedMap.prototype.defineMapLayer.call(this, new OpenLayers.Layer.WMS(
		"Great Britain 20th Century",
		"http://vision.port.ac.uk/geowebcache/service/wms",
//		"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/gbhgis.map&service=WMS",
		{ layers: "europe", format: "image/jpeg" },
		{ transitionEffect: "resize", projection: "epsg:3034" } ));

	EmbeddedMap.prototype.defineMapLayer.call(this, new OpenLayers.Layer.WMS(
		"Great Britain 19th Century",
		"http://vision.port.ac.uk/geowebcache/service/wms",
//		"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/gbhgis.map&service=WMS",
		{ layers: "nineteenth", format: "image/jpeg" },
		{ transitionEffect: "resize", projection: "epsg:3034" } ));

	EmbeddedMap.prototype.defineMapLayer.call(this, new OpenLayers.Layer.WMS(
		"Great Britain Land Utilisation",
		"http://vision.port.ac.uk/geowebcache/service/wms",
//		"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/gbhgis.map&service=WMS",
		{ layers: "land", format: "image/jpeg" },
		{ transitionEffect: "resize", projection: "epsg:3034" } ));

	EmbeddedMap.prototype.defineMapLayer.call(this, new OpenLayers.Layer.WMS(
		"OpenStreetMap",
		"http://vision.port.ac.uk/geowebcache/service/wms",
//		"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/osm.map&service=WMS",
		{ layers: "osm", format: "image/png" },
		{ transitionEffect: "resize", projection: "epsg:3034" } ));

	// Add the base layers to the map
	EmbeddedMap.prototype.addMapLayers.call(this);

	// Set the requested active base layer
	EmbeddedMap.prototype.setRequestedLayer.call(this, requestedLayer);

	// Set the location
	EmbeddedMap.prototype.setExtent.call(this, xMin, yMin, xMax, yMax);

	// determineSubLayer method, determines the name of the subLayer depending
	// on the current active layer and the current scale
	// The returned value is used to construct the sublayer name for the
	// Map Library query that returns the map metadata
	// The scale values need to be the same as those in the gbhgis.map file
	// I consider this function to be a hack
	this.determineSubLayer = function()
	{
		var mapLayerName = this.getMapLayerName();
		var scale = this.getScale();

		if(mapLayerName == "europe")
		{
			if(scale > 500000)
			{
				return "gsgs_2957";
			}
			else if(scale > 62500 && scale <= 500000)
			{
				return "gsgs_4072";
			}
			else if(scale > 7813 && scale <= 62500)
			{
				return "new_pop";
			}
			else
			{
				return;
			}
		}
		else if(mapLayerName == "nineteenth")
		{
			if(scale > 500000)
			{
				return "wilkinson_1812";
			}
			else if(scale > 62500 && scale <= 500000)
			{
				return "smith_1806";
			}
			else if(scale > 7813 && scale <= 62500)
			{
				return "first_edition";
			}
			else
			{
				return;
			}
		}
		else if(mapLayerName == "land")
		{
			if(scale > 62500)
			{
				return "lus_stamp_10";
			}
			else if(scale > 7813 && scale <= 62500)
			{
				return "lus_stamp";
			}
			else
			{
				return;
			}
		}
		else
		{
			return;
		}
	}
}

// Perform the inheritance
GreatBritainMap.prototype = EmbeddedMap.prototype;
GreatBritainMap.prototype.constructor = GreatBritainMap;


//
// EuropeMap inherits from EmbeddedMap
//
function EuropeMap(mapDiv, requestedLayer, xMin, yMin, xMax, yMax)
{
	EmbeddedMap.call(this, mapDiv);

	// Define the base layers
	EmbeddedMap.prototype.defineMapLayer.call(this, new OpenLayers.Layer.WMS(
		"Europe 20th Century",
//		"http://vision.port.ac.uk/geowebcache/service/wms",
		"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/gbhgis.map&service=WMS",
		{ layers: "europe", format: "image/jpeg" },
		{ transitionEffect: "resize", projection: "epsg:3034" } ));

	EmbeddedMap.prototype.defineMapLayer.call(this, new OpenLayers.Layer.WMS(
		"OpenStreetMap",
//		"http://vision.port.ac.uk/geowebcache/service/wms",
		"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/osm.map&service=WMS",
		{ layers: "osm", format: "image/png" },
		{ transitionEffect: "resize", transitionEffect: "resize", projection: "epsg:3034" } ));

	// Add the base layers to the map
	EmbeddedMap.prototype.addMapLayers.call(this);

	// Set the requested active base layer
	EmbeddedMap.prototype.setRequestedLayer.call(this, requestedLayer);

	// Set the location
	EmbeddedMap.prototype.setExtent.call(this, xMin, yMin, xMax, yMax);

	// determineSubLayer method, determines the name of the sublayer depending
	// on the current active layer and the current scale
	// The returned value is used to construct the sublayer name for the
	// Map Library query that returns the map metadata
	// The scale values need to be the same as those in the gbhgis.map file
	// I consider this function to be a hack
	this.determineSubLayer = function()
	{
		var mapLayerName = this.getMapLayerName();
		var scale = this.getScale();

		if(mapLayerName == "europe")
		{
			if(scale > 500000)
			{
				return "gsgs_2957";
			}
			else if(scale > 62500)
			{
				return "gsgs_4072";
			}
			else if(scale > 7813 && scale <= 62500)
			{
				return "new_pop";
			}
			else
			{
				return;
			}
		}
		else
		{
			return;
		}
	}
}

// Perform the inheritance
EuropeMap.prototype = EmbeddedMap.prototype;
EuropeMap.prototype.constructor = EuropeMap;


//
// SearchResultsMap does not inherit from EmbeddedMap
//
function SearchResultsMap(mapDiv, xCenter, yCenter, scale, mapLayer)
{
	scale = Math.abs(scale);

	// Define the available resolutions
	var r = [4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 2048.0, 4096.0];

	// Determine the actual resolutions depending on the map series scale
	var resolutions = null;

	if(mapLayer == "osm")
	{
		resolutions = [r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9]];	
	}
	else if(scale > 2000000)
	{
		resolutions = [r[6], r[7], r[8], r[9], r[10]];
	}
	else if(scale > 1000000 && scale <= 2000000)
	{
		resolutions = [r[6], r[7], r[8], r[9]];	
	}
	else if(scale > 125000 && scale <= 1000000)
	{
		resolutions = [r[3], r[4], r[5]];
	}
	else if(scale <= 125000)
	{
		resolutions = [r[0], r[1], r[2]];
	}
	else
	{
		resolutions = r;
	}

	// Create OpenLayers map object
	this.map = new OpenLayers.Map(mapDiv, { resolutions: resolutions,
					     maxExtent: new OpenLayers.Bounds(0, 0, 8388608, 8388608),
					     restrictedExtent: new OpenLayers.Bounds(600000, 0, 7300000, 6700000),
					     tileSize: new OpenLayers.Size(256, 256),
					     controls: [],
					     theme: null,
					     projection: "epsg:3034",
					     units: "m" 
					   } );

	// Define the requested base layer, use osm if not avaiable
	var baseLayer = null;

	if(mapLayer == "europe")
	{
		baseLayer = new OpenLayers.Layer.WMS(
			null,
			"http://vision.port.ac.uk/geowebcache/service/wms",
//			"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/gbhgis.map&service=WMS",
			{ layers: "europe", format: "image/jpeg" },
			{ transitionEffect: "resize", projection: "epsg:3034" } );
	}
	else if(mapLayer == "nineteenth")
	{
		baseLayer = new OpenLayers.Layer.WMS(
			null,
			"http://vision.port.ac.uk/geowebcache/service/wms",
//			"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/gbhgis.map&service=WMS",
			{ layers: "nineteenth", format: "image/jpeg" },
			{ transitionEffect: "resize", projection: "epsg:3034" } );
	}
	else if(mapLayer == "land")
	{
		baseLayer = new OpenLayers.Layer.WMS(
			null,
			"http://vision.port.ac.uk/geowebcache/service/wms",
//			"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/gbhgis.map&service=WMS",
			{ layers: "land", format: "image/jpeg" },
			{ transitionEffect: "resize", projection: "epsg:3034" } );
	}
	else
	{
		baseLayer = new OpenLayers.Layer.WMS(
			null,
			"http://vision.port.ac.uk/geowebcache/service/wms",
//			"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/osm.map&service=WMS",
			{ layers: "osm", format: "image/png" },
			{ transitionEffect: "resize", projection: "epsg:3034" } );
	}

	// Add the base layer to the map
	this.map.addLayer(baseLayer);

	// Set the location
	this.map.setCenter(new OpenLayers.LonLat(xCenter, yCenter), 0);

	// Set up the overview map
	var overviewLayer = new OpenLayers.Layer.WMS(
		"Overview Map",
		"http://vision.port.ac.uk/geowebcache/service/wms",
//		"http://vision.port.ac.uk/cgi-bin/mapserv?map=/data/map-files/osm.map&service=WMS",
		{ layers: "osm", format: "image/png" },
		{ maxResolution: 8192.0,
		  maxExtent: new OpenLayers.Bounds(0, 0, 8388608, 8388608),
		  tileSize: new OpenLayers.Size(256, 256),
		  transitionEffect: "resize",
		  projection: "epsg:3034",
		  units: "m" } );

	// Create the overview map and resize it
	var overviewMap = new OpenLayers.Control.OverviewMap(
		{ layers: [overviewLayer],
		  size: new OpenLayers.Size(180, 100),
		  minRatio: 32,
		  maxRatio: 32 } );

	// Define the single click "Tell Me More" control
	this.clickControl = new OpenLayers.Control.Click( { handlerOptions: { "single": true, "double": false } } );

	// Add the controls
	this.map.addControl(this.clickControl);
	this.map.addControl(new OpenLayers.Control.Navigation());
	this.map.addControl(new OpenLayers.Control.PanZoomBar());
	this.map.addControl(overviewMap);
	overviewMap.maximizeControl();

	// getExtent method, returns the extent of the current map view
	// The return type is an extent object;
	this.getExtent = function()
	{
		return this.map.getExtent();
	}
	
	// getScale method, returns the current scale	
	this.getScale = function()
	{
		return this.map.getScale();	
	}

	// getOpenLayersMap method, returns the OpenLayers map object
	this.getOpenLayersMap = function()
	{
		return this.map;
	}

	// getLonLatFromViewPortPx, retrieve the world coordinates for a set of specified
	// view port coordinates
	this.getLonLatFromViewPortPx = function(xy)
	{
		return this.map.getLonLatFromViewPortPx(xy);
	}
	
	// toggleClickControl, get the single click control handler
	this.toggleClickControl = function()
	{
		if(this.clickControl.active)
		{
			this.clickControl.deactivate();
		}
		else
		{
			this.clickControl.activate();
		}
	}	
}
