//Set up windows event handlers to resize map to fill window area
window.onload = fillWindow;
window.onresize = fillWindow;

//Declare global page variables
var map;
var bOnce;
var dataFilename;
var defaultZoom = 12;
var mgr;
var mapControl;
var defaultMapType;
var dataURL = './';

//Create marker icons
var miniIcon = new GIcon();
miniIcon.shadow = "img/mini_marker_shadow.png";
miniIcon.iconSize = new GSize(12, 20);
miniIcon.shadowSize = new GSize(22, 20);
miniIcon.iconAnchor = new GPoint(6, 20);
miniIcon.infoWindowAnchor = new GPoint(10, 2);

var newsiteIcon = new GIcon();
newsiteIcon.shadow = "img/newsite_marker_shadow.png";
newsiteIcon.iconSize = new GSize(22, 28);
newsiteIcon.shadowSize = new GSize(27, 28);
newsiteIcon.iconAnchor = new GPoint(11, 28);
newsiteIcon.infoWindowAnchor = new GPoint(20, 6);

var circleIcon = new GIcon();
circleIcon.iconSize = new GSize(20, 20);
circleIcon.iconAnchor = new GPoint(10, 10);
circleIcon.infoWindowAnchor = new GPoint(15, 5);

var year = 9999;

//OnLoad: Function called when page is loaded
function load() {
	//Variables to hold argument values parsed from page url
	var strLat;
	var strLng;
	var strZoom;	
	var strSites;

	//process command line arguments first time in
	if(!bOnce){
		strLat = getParam("lat");
		strLng = getParam("lon");
		strZoom = getParam("zoom");
		strSites = getParam("sites");
		strData = getParam("data");
	}
	bOnce = 1;

	//Set data file name to load
	if (strSites) {
		dataFilename = 'sitedata' + strSites + '.json';
	}
	else {
		dataFilename = 'sitedata.json';
	}
	
	//Check that browser is compatible
	if (GBrowserIsCompatible()) {
		fillWindow();
		map = new GMap2(document.getElementById("map"));
		map.addControl(new GLargeMapControl3D());
		map.addControl(new GScaleControl());
		map.addControl(new YearControl());
		map.enableScrollWheelZoom();
		map.enableContinuousZoom();
		map.getContainer().style.overflow="hidden";
		map.addMapType(G_PHYSICAL_MAP);

		//Set centre of map to specified location, or use default if none specified
		var mapCentre;
		var zoomLevel;
		if((strLat)&&(strLng)) {
			mapCentre = new GLatLng(parseFloat(strLat),parseFloat(strLng));
			//Change default zoom to higher level as a point was specified
			defaultZoom = 16;
		} 
		else {
			mapCentre = new GLatLng(43.33,-3.59);//centred on Matienzo expedition area
		}
		
		//Get zoom level if a valid value was specified, else use default zoom
		if (strZoom) {
			zoomLevel = parseInt(strZoom);
			if ((zoomLevel < 1) || (zoomLevel > 20)) {
				//Bad zoom level value, so use default
				zoomLevel = defaultZoom;
			}
		}
		else {
			zoomLevel = defaultZoom; //Default to show whole area
		}


		//Apply map centre and zoom level
		map.setCenter(mapCentre, zoomLevel);

		//Add dragable marker to enable position coordinated to be determined
		var marker = new GMarker(new GLatLng(43.326520,-3.586736), {draggable: true});
		GEvent.addListener(marker, "dragstart", function() {
			map.closeInfoWindow();
		});
		GEvent.addListener(marker, "dragend", function() {
			marker.openInfoWindowHtml("Lat: "+marker.getPoint().lat()+" Lon: "+marker.getPoint().lng());
		});
		map.addOverlay(marker);

		//Add polyline to define expedition boundary
		map.addOverlay(createPermitBoundary());

		//Create copyright collection for Matienzo data
		var copyright =  new GCopyright(1,
				new GLatLngBounds(new GLatLng(43.2, -3.8),new GLatLng(43.4, -3.5)),
				0,"&copy;2010 <a href='http://www.matienzo.org.uk/'>Matienzo Caving Expeditions</a>");							  
		var copyrightCollection = new GCopyrightCollection('Cave data layer');
		copyrightCollection.addCopyright(copyright);

		//Custom no data messages (displayed for tiles where no data could be loaded)
		var noCaveDataMessage = {errorMessage:"No cave data at this zoom level here. Get yourself out there and survey something!"};

		var noMapData = {errorMessage:"Sorry, but there is no data available at this zoom level here. Try zooming out for a wider view, or changing to another map type to view this area."};

		//Custom tile layer for base tiles to set copyright and determine where to show cave tiles
		//as upper tile layers only show up when tiles are returned for the base layer
		var baseTileLayer = new GTileLayer(copyrightCollection,12,19); 
		baseTileLayer.getTileUrl = baseTileURL; 

		//Custom overlay for cave survey tiles
		var caveTileLayer = new GTileLayer(copyrightCollection, 14, 19);
		caveTileLayer.getTileUrl = caveTileURL;
		caveTileLayer.getOpacity = function() {return 1;}

		//Custom map type for google mapping with cave overlay
		var caveHybrLayer = new Array();
		caveHybrLayer[0] = baseTileLayer;
		caveHybrLayer[1] = G_NORMAL_MAP.getTileLayers()[0];
		caveHybrLayer[2] = caveTileLayer;
		var cavesMap = new GMapType(caveHybrLayer, G_NORMAL_MAP.getProjection(), 'Caves', noCaveDataMessage); 
		cavesMap.getTextColor = function() {return "#FFFFFF";};
		map.addMapType(cavesMap);

		//Custom map type for satellite photos with cave overlay
		var caveSatHybrLayer = new Array();
		caveSatHybrLayer[0] = baseTileLayer; //Use as first layer to control where 'no data' tiles appear
		caveSatHybrLayer[1] = G_HYBRID_MAP.getTileLayers()[0];
		caveSatHybrLayer[2] = G_HYBRID_MAP.getTileLayers()[1];
		caveSatHybrLayer[3] = caveTileLayer;
		//caveSatHybrLayer[2].getOpacity = function () {return 1.0;};//Function to set transparency for this layer
		var caveSatMap = new GMapType(caveSatHybrLayer, G_SATELLITE_MAP.getProjection(), 'SatCave', noCaveDataMessage); 
		caveSatMap.getTextColor = function() {return "#0080FF";};
		map.addMapType(caveSatMap);

		//Custom map type for terrain with cave overlay
		var caveTerrainLayer = new Array();
		caveTerrainLayer[0] = baseTileLayer; //Use as first layer to control where 'no data' tiles appear
		caveTerrainLayer[1] = G_PHYSICAL_MAP.getTileLayers()[0];
		caveTerrainLayer[2] = caveTileLayer;
		var caveTerrMap = new GMapType(caveTerrainLayer, G_PHYSICAL_MAP.getProjection(), 'TerrCave', noCaveDataMessage); 
		caveTerrMap.getTextColor = function() {return "#0080FF";};
		map.addMapType(caveTerrMap);

		//Custom overlay for Matienzo expo map tiles
		var mapTileLayer = new GTileLayer(copyrightCollection,12,18); 
		mapTileLayer.getTileUrl = mapTileURL; 

		//Custom map type for Matienzo maps
		var matMaps = new GMapType([mapTileLayer], G_SATELLITE_MAP.getProjection(), "MatMaps",noMapData); 
		matMaps.getTextColor = function() {return "#000000";}; 

		//Custom map type for Matienzo maps with cave overlay
		var caveHybridLayer = new Array();
		caveHybridLayer[0] = mapTileLayer;
		caveHybridLayer[1] = caveTileLayer;
		var matMapsWithCaves = new GMapType(caveHybridLayer, G_SATELLITE_MAP.getProjection(), 'MapCave',noCaveDataMessage); 
		matMapsWithCaves.getTextColor = function() {return "#000000";};

		//Custom overlay for Matienzo expo area aerial photo tiles
		var photoTileLayer = new GTileLayer(copyrightCollection,12,18); 
		photoTileLayer.getTileUrl = photoTileURL; 

		//Custom map type for Matienzo expo area aerial photo map
		var photoMap = new GMapType([photoTileLayer], G_SATELLITE_MAP.getProjection(), "Photos",noMapData); 
		photoMap.getTextColor = function() {return "#000000";}; 

		//Custom map type for Matienzo maps with cave overlay
		var cavePhotoLayer = new Array();
		cavePhotoLayer[0] = photoTileLayer;
		cavePhotoLayer[1] = caveTileLayer;
		var cavePhotoMap = new GMapType(cavePhotoLayer, G_SATELLITE_MAP.getProjection(), 'PhotoCave',noCaveDataMessage); 
		cavePhotoMap.getTextColor = function() {return "#000000";};
		
		//MS Virtual Earth tiles
		function msnVeTileA(a, b){                      
			var sTile = TileToQuadKey(a.x,a.y,b);            
			s = 'http://a'
			s += sTile.substring(sTile.length-1, sTile.length);
			s += '.ortho.tiles.virtualearth.net/tiles/a'
			s += sTile;
			s += '.jpeg?g=1';
			return s;
		}
		function TileToQuadKey( tx,  ty,  zl){
			var quad;
			quad = "";
			for (var i = zl; i > 0; i--){
				var mask = 1 << (i - 1);
				var cell = 0;
				if ((tx & mask) != 0)
					cell++;
				if ((ty & mask) != 0)
					cell += 2;
				quad += cell;
			}
			return quad;
		}

		var msnLayerA = new GTileLayer(new GCopyrightCollection(''),1,19);
		msnLayerA.getTileUrl = msnVeTileA;
		msnLayerA.getCopyright = function(a,b) {return 'MSN Virtual Earth';}

		//Custom map type for MS Virtual Earth
		var msnMapA = new GMapType([msnLayerA], G_SATELLITE_MAP.getProjection(), 'MS VE Aerial',{errorMessage:noMapData});
		msnMapA.getTextColor = function() {return "#FFFFFF";};
		map.addMapType(msnMapA);
		 
		//Add hierarchical map types control
		mapControl = new GHierarchicalMapTypeControl();

		// Set up map type menu relationships
		mapControl.clearRelationships();
		mapControl.addRelationship(G_SATELLITE_MAP, G_HYBRID_MAP, "Labels", false);
		mapControl.addRelationship(G_SATELLITE_MAP, caveSatMap, "Caves", true);
		mapControl.addRelationship(G_SATELLITE_MAP, msnMapA, "MS VE", false);
		mapControl.addRelationship(G_NORMAL_MAP, cavesMap, "Caves", true);
		mapControl.addRelationship(G_PHYSICAL_MAP, caveTerrMap, "Caves", true);
/*		
		//Add matienzo maps to map types control
		map.addMapType(matMaps);
		map.addMapType(matMapsWithCaves);
		mapControl.addRelationship(matMaps, matMapsWithCaves, "Caves", true);
*/
		//Add matienzo hi-res photos to map types control
		map.addMapType(photoMap);
		map.addMapType(cavePhotoMap);
		mapControl.addRelationship(photoMap, cavePhotoMap, "Caves", true);

		defaultMapType = cavePhotoMap;
		
		// Add control after you've specified all the relationships
		map.addControl(mapControl);
		//Set map type has to be done after setting the other things above or 
		//map will not show
		map.setMapType(defaultMapType);

		//Add OverviewMapControl here so we can set the map type to match the main map type
		var overCtrl = new GOverviewMapControl();
		overCtrl.setMapType(defaultMapType);
		map.addControl(overCtrl);
		
		//Create new marker manager to hold map marker groups
		mgr = new MarkerManager(map);

		//Create site markers
		reloadMapMarkers(dataURL + dataFilename);
	}
}

//reloadMapMarkers: Loads markers data file and create a set of markers to show on the map
function reloadMapMarkers ( filename ) {
	//Fetch sites data to create markers, with second attempt on error for local file
	fetchData( filename, state_Change, function(){alert("Error loading sites data. No markers can be created.");}, true );
}

//Function to resize the map to fill the web browser window
function fillWindow(){

	var mapDiv = document.getElementById("map");

	try{
		if (window.innerHeight) //if browser supports window.innerWidth
			mapDiv.style.height = window.innerHeight+'px';
		else{
			//MSIE
			mapDiv.style.height = document.documentElement.clientHeight;
			mapDiv.style.width = document.documentElement.clientWidth + document.documentElement.clientLeft - 2;
		}
	}
	catch(ex){
	}
}

//Function to get arguments from url used to load page
function getParam(n)
{
	var sSearch;
	var aPairs;
	sSearch = (document.location.search.length > 1) ? document.location.search.substring(1) : "";
	if (sSearch != "")
	{
		aPairs = sSearch.split("&");
		for (var i = 0; i < aPairs.length; i++)
		{
			if(aPairs[i].split("=")[0] == n)
				return unescape(aPairs[i].split("=")[1]);
		}
	}
}

//Function to serve up cave survey tile files
//This needs to serve up google's tiles for areas outside our data area and for lower zoom levels where we have no
//data. So the code returns an invisible blank tile for these cases, but returns our tiles within our area.
function tileURL(folder,a,b) {	
	//At lower zoom levels than we provide tiles, return invisible tile so google map data is still displayed
	var tileFilename = folder + "/cleartile"; //Default blank tile
	if (b>=12) {
		//Within zoom range of cave data tiles
		if (b>15) {
			//At highest zoom levels, there are no google data tiles, so return only our tiles where they exist
			//(this allows error message text to show when there is no data tiles)
			tileFilename = folder + "/"+(a.x)+"_"+(a.y)+"_"+b;
		} else {
			//Mid zoom levels where both we and google have data.
			//Check if we are inside the area covered by our tiles
			var lonTest = (a.x)/Math.pow(2,(b-13));
			if ((lonTest>4011.9)&&(lonTest<4016.9)) {
				var latTest = (a.y)/Math.pow(2,(b-13));
				if ((latTest>2997.9)&&(latTest<3001.7)) {
					tileFilename = folder + "/"+(a.x)+"_"+(a.y)+"_"+b;
				}
			}
		}
	}
	return tileFilename;
}

function baseTileURL(a,b) {	
	//Return cave tiles only where they exist for zoom levels above the max for each map type
	var mapName = map.getCurrentMapType().getName();
	var useCaveTiles = false;
	
	if (b==19) {
		//Use cave tiles for all map types except street maps
		if (mapName!='Caves') {
			useCaveTiles = true;
		}
	} else if (b>15) {
		//Use cave tiles only for terrain map
		if (mapName=='TerrCave') {
			useCaveTiles = true;
		}
	}
	
	if ( useCaveTiles == true ) {
		return caveTileURL(a,b);
	} else {
		return "cavetiles/cleartile.gif";
	}
}

function caveTileURL(a,b) {	
	var baseURL = dataURL + "cavetiles";
	return tileURL(baseURL,a,b) + ".gif";
}

function mapTileURL(a,b) {	
	if ( (b>18) && (map.getCurrentMapType().getName() == 'MapCave') ) {
		return caveTileURL(a,b);
	}
	else {
		return tileURL("maptiles",a,b) + ".gif";
	}
}

function photoTileURL(a,b) {	
	if ( (b>17) && (map.getCurrentMapType().getName() == 'PhotoCave') ) {
		return caveTileURL(a,b);
	}
	else {
		return tileURL("phototiles",a,b) + ".jpg";
	}
}

function createPermitBoundary() {	
	//Create polyline to define expedition boundary
	var colour = "#FF0000";
	var width = 4;
	var pts = [];
	var index = 0;

	function ap(lat,lon) {
		pts[index] = new GLatLng(lat,lon);
		index +=1;
	}

	ap(43.371771,-3.673983);
	ap(43.371239,-3.670067);
	ap(43.371811,-3.661957);
	ap(43.369620,-3.655293);
	ap(43.368041,-3.648692);
	ap(43.368403,-3.581362);
	ap(43.368695,-3.520886);
	ap(43.336730,-3.520613);
	ap(43.303991,-3.520333);
	ap(43.307926,-3.532104);
	ap(43.302118,-3.547812);
	ap(43.301712,-3.549807);
	ap(43.299525,-3.551931);
	ap(43.298807,-3.554184);
	ap(43.298932,-3.556652);
	ap(43.299588,-3.558691);
	ap(43.299674,-3.564827);
	ap(43.298627,-3.566297);
	ap(43.298323,-3.580599);
	ap(43.295231,-3.595533);
	ap(43.296792,-3.603902);
	ap(43.294825,-3.613054);
	ap(43.291139,-3.618944);
	ap(43.291998,-3.621840);
	ap(43.291076,-3.624587);
	ap(43.292451,-3.627377);
	ap(43.293481,-3.636324);
	ap(43.292279,-3.642612);
	ap(43.294731,-3.644285);
	ap(43.295043,-3.646023);
	ap(43.296870,-3.647804);
	ap(43.297917,-3.648148);
	ap(43.301212,-3.649521);
	ap(43.302773,-3.657525);
	ap(43.303539,-3.664434);
	ap(43.303164,-3.669906);
	ap(43.301883,-3.673210);
	ap(43.371771,-3.673983);

	return new GPolyline(pts,colour,width);
}

var batch1 = []; //Markers which are visible at all zoom levels
var batch2 = []; //Markers which are only visible at middle zoom levels
var batch3 = []; //Markers which are only visible at close zoom levels

function addMarker(marker, cat) {
	//Assign marker to appropriate array for zoom range it should be displayed within
	switch (cat) {
	case 1 : 
	case 7 : 
		batch3.push(marker);
		break;
	case 2 : 
	case 8 : 
		batch2.push(marker);
		break;
	default :
		batch1.push(marker);
	}
}

function showMarkers() {
	//Add marker batches to marker manager for different zoom levels
	mgr.addMarkers(batch1, 0);
	mgr.addMarkers(batch2, 15);
	mgr.addMarkers(batch3, 16);
	mgr.refresh();
}

function createNewMarker (lat, lon, siteName, siteDesc, siteNum, col) {
	//Create point from coordinates
	var point = new GLatLng( parseFloat(lat),parseFloat(lon) );

	//Create marker icon with specified colour
	var colIcon;
	if (col > 12) {
		//New site icon
        colIcon = new GIcon(newsiteIcon);
	}
	else if (col < 7) {
		//GPS site icon
		colIcon = new GIcon(miniIcon);
	}
	else {
		//Non-gps site icon
		colIcon = new GIcon(circleIcon);
	}
	colIcon.image = getMarkerImgUrl( col );

	//Format number with leading zeros
	var numZeropad = siteNum + '';
	while(numZeropad.length < 4) {
		numZeropad = "0" + numZeropad;
	}

	//Create a formatted marker title which correctly displays accented characters in the pop-up hints on markers
	var formattedName = numZeropad + ' ' + formatSiteName(siteName);

	// Create a marker for this point using the icon created above
	var marker = new GMarker(point, { icon: colIcon, title:formattedName});

	//Add a click event listener to the marker to display the info window containing the site details and hyperlink
	GEvent.addListener(marker, "click", function() {
		marker.openInfoWindowHtml("<a target=\"NEW\" href=\"http://www.geography.lancs.ac.uk/Matienzo/descrip/" + numZeropad + ".htm\" >Site: " + numZeropad + "</a><BR/>" + siteDesc);
	});
	return marker;
}

function updateProgress( prog, message ) {
	if (message.length < 50) prog = 50;
}

//Custom control
function YearControl() {
}
YearControl.prototype = new GControl();



YearControl.prototype.initialize = function(map) {

	var container = document.createElement("div");
	container.style.fontFamily='Arial';
	container.style.fontSize='x-small';

	var sel1 = document.createElement("SELECT");
	sel1.id = "yearSelect1";
	var mts = map.getMapTypes();
	for(var i=2011; i > 1989; i--)
	{
		var o = document.createElement("OPTION");
		if ( i == 2011 ) {
			o.text = 'all';
		}
		else {
			o.text = '' + i;
		}
			o.value=i;
		try {
			sel1.add(o, null); // standards compliant; doesn't work in IE
		}
		catch(ex) {
			sel1.add(o); // IE only
		}  
	}
	sel1.title = "Select the year to show data from";
	container.appendChild(sel1);
  
  GEvent.addDomListener(sel1, "change", function() {
  
    var sel1 = document.getElementById("yearSelect1"); 
    var mt1 = sel1.options[sel1.selectedIndex].text;

	dataURL = './';
	testYear = parseInt(mt1);
	if (testYear > 1960) {
		year = testYear;
	}
	else {
		year = 9999;
	}			

	//Clear marker batches and old markers
	batch1 = []; 
	batch2 = []; 
	batch3 = [];
	mgr.clearMarkers();
	
    //Reload markers and set dataUrl for selection
	reloadMapMarkers(dataURL + dataFilename);
	
  });
   
  map.getContainer().appendChild(container);

  return container;

  }




// By default, the control will appear in the top left corner of the
// map with 7 pixels of padding.
YearControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(350, 7));
}

