/*
 * JavaScript code to generate maps used by the
 * Seismological Observatory of the Ruhr-University Bochum
 * 
 * Copyright 2013 Kasper D. Fischer <kasper.fischer@rub.de>
 * 
 * License
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 *  your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 *
 * $Id$

*/

/* Global variables */
var map, mapargs;

/* Main function to create the map */
function init(showGoogle, showStations, showQuakes, noFrils) {
	
	/* get parameters from url */
	mapargs = OpenLayers.Util.getParameters();
    if (mapargs['print']) {
		if (mapargs['print'] == 'true') {
			noFrils = true;
		} else {
			noFrils = false;
		}
	}
	if (mapargs['quakes']) {
		if (mapargs['quakes'] == 'true') {
			showQuakes = true;
		} else {
			showQuakes = false;
		}
	}
	if (mapargs['stations']) {
		if (mapargs['stations'] == 'true') {
			showStations = true;
		} else {
			showStations = false;
		}
	}
	
	/* Creating map */
	if ( !noFrils ) {
		map = new OpenLayers.Map(
			'map',
			{
				projection: new OpenLayers.Projection('EPSG:900913'),
				displayProjection: new OpenLayers.Projection('EPSG:4326'),
				controls: [
					new OpenLayers.Control.Attribution(),
					new OpenLayers.Control.KeyboardDefaults(),
					new OpenLayers.Control.LayerSwitcher({}),
					new OpenLayers.Control.MousePosition(),
					new OpenLayers.Control.Navigation(),
					new OpenLayers.Control.OverviewMap(),
					new OpenLayers.Control.PanZoomBar({zoomWorldIcon: true}),
					new OpenLayers.Control.Permalink({anchor: noFrils}),
					new OpenLayers.Control.ScaleLine({geodesic: true})
				]
			}
		);
	} else {
		map = new OpenLayers.Map(
			'map',
			{
				projection: new OpenLayers.Projection('EPSG:900913'),
				displayProjection: new OpenLayers.Projection('EPSG:4326'),
				controls: [
					new OpenLayers.Control.Attribution(),
					new OpenLayers.Control.KeyboardDefaults(),
					new OpenLayers.Control.Navigation(),
					new OpenLayers.Control.Permalink({anchor: noFrils}),
					new OpenLayers.Control.ScaleLine({geodesic: true})
				]
			}
		);
	};

	/* Base Layers */
	// OpenStreetMap
	var osmde_map_layer = new OpenLayers.Layer.OSM(
		'OpenStreetMap (DE)',
		[
			"http://a.tile.openstreetmap.de/tiles/osmde/${z}/${x}/${y}.png",
			"http://b.tile.openstreetmap.de/tiles/osmde/${z}/${x}/${y}.png",
			"http://c.tile.openstreetmap.de/tiles/osmde/${z}/${x}/${y}.png"
		],
		{
			attribution: 'Kartenbasis: Daten von <a href="http://www.openstreetmap.org/">OpenStreetMap</a> - Veröffentlicht unter <a href="http://opendatacommons.org/licenses/odbl/">ODbL</a><br />' +
                                     'Seismische Daten von <a href="http://www.gmg.ruhr-uni-bochum.de/geophysik/seisobs">Ruhr-Universität Bochum</a> - Veröffentlicht unter <a href="http://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>'
		}
	);
	var osm_map_layer = new OpenLayers.Layer.OSM('OpenStreetMap (Standard)');
	map.addLayers([
		osm_map_layer,
		osmde_map_layer
	]);

	// Google Maps
	if (showGoogle) {
		var googleT_map_layer = new OpenLayers.Layer.Google(
			OpenLayers.i18n('Google Maps (Terrain)'),
			{type: google.maps.MapTypeId.TERRAIN,transitionEffect: "resize"}
		);
		var googleS_map_layer = new OpenLayers.Layer.Google(
			OpenLayers.i18n("Google Maps (Satellite)"),
			{type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22,transitionEffect: "resize"}
		);
		var googleH_map_layer = new OpenLayers.Layer.Google(
			'Google Maps (Hybrid)',
			{type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20,transitionEffect: "resize"}
		);
		var googleM_map_layer = new OpenLayers.Layer.Google(
			OpenLayers.i18n("Google Maps (Streets)"),
			{numZoomLevels: 20,transitionEffect: "resize"}
		);
		map.addLayers([
			googleT_map_layer,
			googleS_map_layer,
			googleH_map_layer,
			googleM_map_layer
		]);
	};

	// ESRI
	var esri_map_layer = new OpenLayers.Layer.XYZ(
		'ESRI',
		"https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/${z}/${y}/${x}",
		{
			sphericalMercator: true,
			attribution: 'Copyright &copy; 2013 by ESRI. ' +
				'This work is licensed under the Web Services and API <a href="http://links.esri.com/agol_tou" target="_blank">Terms of Use</a>.'
		}
	);
	map.addLayers([esri_map_layer]);
	
	// Show quakes
	quakes_layer = loadKML(OpenLayers.i18n("Events"), 'quakes.kml', false, true);
	quakes_layer.events.on({'loadend': setQuakesMapkeyVisibility});
	quakes_layer.events.on({'visibilitychanged': setQuakesMapkeyVisibility});
	map.addLayer(quakes_layer);
	quakes_layer.setVisibility(showQuakes);
		
	// color coding of events
	var day2sec = 86400.;
	var timeNow = new Date().getTime()/1000.;
	var timeCoding;
	if (mapargs['timeCoding']) {
		switch ( mapargs['timeCoding'] ){
			case 'decade':
				timeCoding = {
					'colors': [  '#0000ff', '#ff0000', '#ffa500', '#ffff00'], 
					'times':   [1262300400, 946681200, 631148400, 315529200]
					//            1.1.2010,  1.1.2000,  1.1.1990,  1.1.1980
				};
		};
	};
	if (!mapargs['timeCoding'] || !timeCoding ) {
		timeCoding = {
			'colors': ['#0000ff',       '#ff0000',       '#ffa500',      '#ffff00'], 
			'ages':   [7*day2sec, 30.4375*day2sec, 182.625*day2sec, 365.25*day2sec]
		};
	};
		
	// Adding custom style to quakes
	var quake_style_default = new OpenLayers.Style({
			fillColor: '${pntcolor}', fillOpacity: 0.2,
			strokeColor: '${pntcolor}', strokeWidth: 2,
			pointRadius: '${pntsize}'
	},
	{
		context: {
			pntcolor: function(feature){
				return feature.data.pntcolor.value; 
			},
			/*	if (timeCoding['ages']) {
					quakeAge = feature.data.age.value;
					// quakeAge = timeNow - feature.data.stime.value;
					for ( level = 0; level < timeCoding['ages'].length; level += 1 ) {
						if ( quakeAge <= timeCoding['ages'][level] ) {
							return timeCoding['colors'][level];
						};
					};
				} else if (timeCoding['decade']) {
					return feature.data.pntcolor.value;
				} else {
					quakeTime = timeNow + feature.data.age.value;
					// quakeTime = feature.data.stime.value;
					for ( level = 0; level < timeCoding['times'].length; level += 1 ) {
						if ( quakeTime >= timeCoding['times'][level] ) {
							return timeCoding['colors'][level];
						};
					};
				};
				//return '#ffffff00';
			}, */
			pntsize: function(feature){
				// quakeAge = feature.data.age.value;
				// quakeAge = timeNow - feature.data.time.value;
				// if ( timeCoding['ages'] && quakeAge > timeCoding['ages'][timeCoding['ages'].length-1] ) {
				//	return 0;
				// } else {
					return feature.data.pntsize.value;
				//}
			}
		}
	});
	var quake_style_select = quake_style_default.clone();
	quake_style_select.defaultStyle.fillOpacity = 0.8;

	var quake_style_map = new OpenLayers.StyleMap({
		'default': quake_style_default,
		'select': quake_style_select
	});
	quakes_layer.styleMap = quake_style_map;

	// Show stations
	stations_layer = loadKML(OpenLayers.i18n("Stations"), 'stations.kml', false, noFrils);
	map.addLayer(stations_layer);
	stations_layer.setVisibility(showStations);

	// Adding custom style to stations
	var station_style_default = new OpenLayers.Style({
		fillColor: '${pointColor}', fillOpacity: 0.8, // #8dae10
		strokeColor: 'black', strokeWidth: 2,
		label: "${text}", labelXOffset: 15, labelAlign: 'l',
		fontColor: "${tcolor}", fontFamily: 'sans-serif', fontWeight: 'bold',
		pointRadius: '${pntsize}',
		graphicName: '${pntsymbol}'
	},
	{
		context: {
			pointColor: function(feature){
				if (feature.attributes.count) {
					return '#8dae10';
				} else {
					return '#8dae10'; //return feature.data.pntcolor.value;
				}
			},
			text: function(feature){
				if (feature.attributes.count) {
					var c = feature.attributes.count;
					for (var i=0; i<feature.cluster.length; i++){
						c = c + feature.cluster[i].data.extrastation.value * 1.0;
					}
					return c + ' ' + OpenLayers.i18n('stations');
				} else {
					return feature.data.name;
				}
			},
			tcolor: function(feature){
				if (feature.attributes.count) {
					return 'black';
				} else {
					return feature.data.tcolor.value;
				}
			},
			pntsize: function(feature){
				if (feature.attributes.count) {
					return Math.min(feature.attributes.count * 2.0 + 6.0, 12);
				} else {
					return feature.data.pntsize.value;
				}
			},
			pntsymbol: function(feature){
				if (feature.attributes.count) {
					return 'circle';
				} else {
					return 'triangle';
				}
			}
		}
	});
	var station_style_select = station_style_default.clone();
	station_style_select.defaultStyle.strokeWidth = 4;
	var station_style_map = new OpenLayers.StyleMap({
		'default': station_style_default,
		'select': station_style_select
	});
	stations_layer.styleMap = station_style_map;

	// Set initial view
	if (!map.getCenter()) {
		map.setCenter(new OpenLayers.LonLat(7.5, 51.8).transform('EPSG:4326','EPSG:900913'), 9);
	}

	// Enable animated zoom
	for (var i=map.layers.length-1; i>=0; --i) {
		map.layers[i].animationEnabled = true;
	}

	// Show description
	select = new OpenLayers.Control.SelectFeature([quakes_layer, stations_layer]);
	map.addControl(select);
	select.activate();

	// Add graticule
	map.addControl(new OpenLayers.Control.Graticule({layerName: OpenLayers.i18n("Grid"), visible: false}));

}

/* Function to load KML file */
function loadKML(name, file, useStyle, noFrils) {
	// define layer strategy
	var layer_strategy
	if (noFrils){
		layer_strategy = [
			new OpenLayers.Strategy.Fixed(),
		];
	} else {
		// define cluster parameters
		var thresholdValue = 4;
		if (map.getZoom() <= 8){ thresholdValue = 2}
		if (map.getZoom() >= 10){ thresholdValue = 6}
		if (noFrils) {
			thresholdValue = 99;
			distanceValue = 0
		};

		var distanceValue = 10;
		if (map.getZoom() <= 9){ distanceValue = 20}

		layer_strategy = [
			new OpenLayers.Strategy.Fixed(),
			new OpenLayers.Strategy.Cluster({distance: distanceValue, threshold: thresholdValue})
		];
	}

	// create kml layer
	var kml_layer = new OpenLayers.Layer.Vector(
		name,
		{
			strategies: layer_strategy,
			protocol: new OpenLayers.Protocol.HTTP(
				{
					url: file,
					format: new OpenLayers.Format.KML({
						extractStyles: useStyle,
						extractAttributes: true,
						maxDepth: 1
					})
				}),
			transitionEffect: "resize",
			projection: new OpenLayers.Projection("EPSG:4326")
		});
	kml_layer.events.on(
		{
			"featureselected": onFeatureSelect,
			"featureunselected": onFeatureUnselect
		});
			
	// return layer object
	return kml_layer;
}

/* Function called at closing of a popup */
function onPopupClose(evt) {
	select.unselectAll();
}

/* Function called when clicking on a marker */
function onFeatureSelect(event) {
	var feature = event.feature;
	// Since KML is user-generated, do naive protection against
	// Javascript.
	if (feature.attributes.name){
		var content = "<h3>"+feature.attributes.name + "</h3><p>" + feature.attributes.description + '</p>';
		if (content.search("<script") != -1) {
			content = "Content contained Javascript! Escaped content below.<br>" + content.replace(/</g, "&lt;");
		}
	} else {
		var content = '<h3>';
		for (var i=0; i<feature.cluster.length; i++){
			content = content + feature.cluster[i].attributes.name;
			if (i < feature.cluster.length-1) {
				content = content + ', ';
			}
		}
		content += '</h3>'+
		OpenLayers.i18n('Zoom in to resolve individual stations.');
	}
	var popup = new OpenLayers.Popup.FramedCloud(
		"popups",
		feature.geometry.getBounds().getCenterLonLat(),
		new OpenLayers.Size(100,100),
		content,
		null, true,
		onPopupClose
	);
	feature.popup = popup;
	map.addPopup(popup);
}

/* Function to close popups */
function onFeatureUnselect(event) {
	var feature = event.feature;
	if(feature.popup) {
		map.removePopup(feature.popup);
		feature.popup.destroy();
		delete feature.popup;
	}
}

/* Function to activate map legend */
function setQuakesMapkeyVisibility() {
	var mapkey_div = document.getElementById('mapkey');
	var quakes_visibility = quakes_layer.getVisibility();
	if (quakes_visibility) {
		mapkey_div.style.display = "block";
		mapkey_div.style.visibility = "visible";
	} else {
		if (mapkey_div) {
			mapkey_div.style.visibility = "hidden";
			mapkey_div.style.display = "none";
		}
	}
}