
var GoogleMapVisualisation = function(mass, timescale, period) {
	this.mass = mass;
	this.timescale = timescale || 'year';
	this.period = period;
	GoogleMapVisualisation.mass = mass;
	this.map = GoogleMapVisualisation.map_instance();
	this.display();
};

GoogleMapVisualisation.prototype = {
	rescale: function() {
		GoogleMapVisualisation.depth_control.set_depth(this.mass)
		this.display_overlay();
	},
	display: function() {
		this.display_overlay();
		GoogleMapVisualisation.depth_control.set_depth(this.mass)
		GoogleMapVisualisation.first_run = false;
		var moveend = (function(visualisation) {
			return function() {
				var c = this.getCenter();
				GoogleMapVisualisation.centre = {
					lat: c.lat(),
					lng: c.lng()
				};
				Sharing.map_moved();
				// visualisation.display_overlay(true);
			}
		})(this);
		var move = (function(visualisation) {
			return function() {
				var c = this.getCenter();
				GoogleMapVisualisation.centre = {
					lat: c.lat(),
					lng: c.lng()
				};
				visualisation.display_overlay(true);
			}
		})(this);
		GEvent.addListener(this.map, "moveend", moveend);
		GEvent.addListener(this.map, "move", move);
		GEvent.addListener(this.map, "movestart", function() {
			Help.off();
		});

	},
	display_overlay: function(maintain_scale) {
		this.map.clearOverlays();
		var c = this.patch_for_position();
		if(!maintain_scale) { this.scale_map(c); }
		var boundaries = this.bounds_from_patch(c);
		// var patch = new GGroundOverlay("/images/overlay-60.png", boundaries);
		var patch = new PatchOverlay(boundaries, this.mass);
		this.map.addOverlay(patch);
	},
	display_polygon: function() {
		this.map.clearOverlays();
		var c = this.patch_for_position();
		var polygon = new GPolygon([
		new GLatLng(c.top_left.lat, c.top_left.lng),
		new GLatLng(c.top_right.lat, c.top_right.lng),
		new GLatLng(c.bottom_right.lat, c.bottom_right.lng),
		new GLatLng(c.bottom_left.lat, c.bottom_left.lng),
		new GLatLng(c.top_left.lat, c.top_left.lng)
		], "#f33f00", 2, 1, "#ff0000", 0.2);
		this.map.addOverlay(polygon);
		//// setting zoom according to size makes relative comparisons difficult
		////
		this.scale_map(c);
	},
	patch_for_position: function() {
		var centre = this.map.getCenter();
		var centre_lat = centre.lat(), centre_long = centre.lng();
		return this.patch_coordinates(centre_lat, centre_long);
	},
	patch_coordinates: function(centre_lat, centre_long) {
		var i33 = CQ.deg_to_rad(centre_lat);
		var i32 = CQ.deg_to_rad(centre_long);
		var d20 = this.mass.angular_size();
		var i20 = 2*Math.acos(Math.cos(d20/2)/Math.sqrt(2));
		var d23 = (Math.sin(d20/2) / Math.sin(i20/2));

		results = {};

		var latlon = function(m) {
			var lat =  Math.asin(Math.sin(i33)*Math.cos(d23) + Math.cos(i33)*Math.sin(d23)*Math.cos(m));
			var lon = i32 + Math.atan2(Math.sin(m)  *Math.sin(d23)*Math.cos(i33), Math.cos(d23)-Math.sin(i33)*Math.sin(lat));
			return {
				lat: CQ.rad_to_deg(lat),
				lng: CQ.rad_to_deg(lon)
			};
		};
		results.top_left = latlon(-Math.PI/4);
		results.top_right = latlon(Math.PI/4);
		results.bottom_left = latlon(-3*Math.PI/4);
		results.bottom_right = latlon(3*Math.PI/4);

		return results;
	},
	scale_map: function(c) {
		var bounds = this.bounds_from_patch(c)
		var current_zoom = GoogleMapVisualisation.current_zoom;
		var zoom = this.map.getBoundsZoomLevel(bounds);

		if(zoom === 0) { zoom = 20; } // zoom of 0 means it's too small to show at any zoom level
		// console.log('first_run:', GoogleMapVisualisation.first_run, '/ zoom:', zoom, '/ current_zoom:', current_zoom)

		var set_zoom = current_zoom;
		if (GoogleMapVisualisation.first_run || zoom < current_zoom || Math.abs((zoom - current_zoom) > 6))  {
			set_zoom = zoom;
			GoogleMapVisualisation.setZoom(Math.max(0, zoom - 1))
		}
	},
	bounds_from_patch: function(c) {
		var bl = new GLatLng(c.bottom_left.lat, c.bottom_left.lng);
		var tr = new GLatLng(c.top_right.lat, c.top_right.lng);
		return new GLatLngBounds(bl, tr);
	}
};

$.extend(GoogleMapVisualisation, {
	instance: false,
	depth_control: false,
	display: function(mass, timescale, period) {
		$(this.canvas()).show();
		// if (this.first_run || this.mass.kilogrammes !== mass.kilogrammes()){
		this.instance = new GoogleMapVisualisation(mass, timescale, period);
		this.instance.display();
		// }
	},
	rescale: function(new_scale, mult) {
		this.instance.rescale(new_scale, mult);
	},
	canvas: function() {
		return document.getElementById("visualisation_canvas");
	},
	map_instance: function() {
		if(!this.map) {
			this.map = new GMap2(this.canvas(), {
				// backgroundColor: 'inherit',
				googleBarOptions: {
					showOnLoad:false
				}
			});
			this.map.setMapType(G_SATELLITE_MAP);
			this.map.setCenter(new GLatLng(this.centre.lat, this.centre.lng));
			// this.map.setUIToDefault();
			var topRight = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10,10));
			var topRight2 = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(100,10));
			var bottomRight = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10,10));
			this.map.addControl(new GLargeMapControl3D(), topRight);
			this.map.addControl(new GHierarchicalMapTypeControl(), topRight2);
			this.map.addControl(new GScaleControl(), new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(322,10)));
			this.depth_control = new GoogleMapsPatchDepthControl();
			this.map.addControl(this.depth_control);
			this.map.enableGoogleBar();
		}
		return this.map;
	},
	reset: function() {
		$(this.canvas()).hide();
		// this.first_run = true;
		// this.map = false;
		this.instance = false;
	},
	first_run: true,
	map: false,
	mass: false,
	centre: { lat: 51.521054, lng: -0.109938},
	country: 'UK',
	api_key: false,
	setZoom: function(new_zoom) {
		this.current_zoom = new_zoom;
		this.map_instance().setZoom(new_zoom);
	},
	current_zoom: 0
});

function PatchOverlay(bounds, mass) {
	this.mass = mass;
  this.bounds_ = bounds;
	this.border_width = 3;
};

PatchOverlay.prototype = new GOverlay();

// Creates the DIV representing this rectangle.
PatchOverlay.prototype.initialize = function(map) {
  // Create the DIV representing our rectangle
  var outer = document.createElement("div");
  // div.style.border = this.weight_ + "px solid " + this.color_;
	// div.style.backgroundImage = "url(/images/overlay-60.png)"
  outer.style.position = "absolute";
	outer.style.backgroundColor = "transparent";
	outer.style.border = 'solid '+this.border_width+'px #f00';
	// outer.style.opacity = 0.6;

  var inner = document.createElement("div");
	inner.style.backgroundColor = "#f00";
	inner.style.opacity = this.mass.opacity();
	inner.style.filter = 'alpha(opacity='+(this.mass.opacity()*100)+')';
  // inner.style.position = "absolute";
  inner.style.color = "white";
	// var width = document.createElement('span');
	// width.innerHTML = this.mass.patch().dimension().distance().toString();
	// div.appendChild(width)
  // Our rectangle is flat against the map, so we add our selves to the
  // MAP_PANE pane, which is at the same z-index as the map itself (i.e.,
  // below the marker shadows)
	outer.appendChild(inner);
  map.getPane(G_MAP_FLOAT_PANE).appendChild(outer);

  this.map_ = map;
  this.inner = inner;
  this.outer = outer;
};

// Remove the main DIV from the map pane
PatchOverlay.prototype.remove = function() {
  this.outer.parentNode.removeChild(this.outer);
};

// Copy our data to a new PatchOverlay
PatchOverlay.prototype.copy = function() {
  return new PatchOverlay(this.bounds_, this.mass);
};

// Redraw the rectangle based on the current projection and zoom level
PatchOverlay.prototype.redraw = function(force) {
  // We only need to redraw if the coordinate system has changed
  if (!force) return;

  // Calculate the DIV coordinates of two opposite corners of our bounds to
  // get the size and position of our rectangle
  var c1 = this.map_.fromLatLngToDivPixel(this.bounds_.getSouthWest());
  var c2 = this.map_.fromLatLngToDivPixel(this.bounds_.getNorthEast());

  // Now position our DIV based on the DIV coordinates of our bounds
  this.inner.style.width = Math.max(1, Math.abs(c2.x - c1.x)-2*this.border_width) + "px";
  this.inner.style.height = Math.max(1, Math.abs(c2.y - c1.y)-2*this.border_width) + "px";
  this.outer.style.left = (Math.min(c2.x, c1.x)) + "px";
  this.outer.style.top = (Math.min(c2.y, c1.y)) + "px";
};


var WorldMapVisualisation = function(mass, timescale, period) {
	this.mass = mass;
	this.timescale = timescale || 'year';
	this.period = period;
	this.controls = [];
};

$.extend(WorldMapVisualisation.prototype, {
	rescale: function() {
			WorldMapVisualisation.depth_control.set_depth(this.mass)
			this.display_overlay();
	},
	display: function() {
		var canvas = $(WorldMapVisualisation.canvas());
		this.map_layer = document.createElement('div');
		this.map_layer.id = 'world_map';
		canvas.append(this.map_layer);
		// canvas.html('<div id="world_map"><div title="Drag around" id="world_map_patch"></div></div>')
		this.display_overlay();
		for (var i = 0; i < this.controls.length; i++) {
			var control = this.controls[i];
			var container = control.initialize(this);
			container.style.position = 'absolute';
			var c = ['top', 'left', 'bottom', 'right'];
			var pos = control.getDefaultPosition();
			for (var i = 0; i < c.length; i++) {
				var p = c[i];
				container.style[p] = pos[p]
			};
		};
		WorldMapVisualisation.depth_control.set_depth(this.mass);
		canvas.show();
	},

	display_overlay: function() {
		this.clear_overlays();
		var canvas = $(WorldMapVisualisation.canvas());
		var cwidth = canvas.width(), cheight = canvas.height();
		var carea = cwidth * cheight;
		var area = this.mass.percentage() * carea;
		var length = Math.sqrt(area);
		var width = height = length;
		var bw = 3;
		if(height > cheight) {
			var ar = cwidth/cheight;
			height = Math.sqrt(area/ar)
			width = height * ar;
		}
		width = Math.min(width, cwidth);
		height = Math.min(height, cheight);
		this.patch_layer = document.createElement('div');
		// this.patch_layer.id = 'world_map_patch';
		this.patch_layer.title = 'Drag around'
		this.patch_layer.style.border = "solid "+bw+"px #f00"
		this.patch_layer.style.position = "absolute"

		var inner = document.createElement('div');
		inner.id = 'world_map_patch'

		$(inner).width(width-2*bw).height(height-2*bw).css('opacity', this.mass.opacity())
		$(this.patch_layer).css('left',(cwidth - width)/2).css('top',(cheight - height)/2);
		this.patch_layer.appendChild(inner);
		this.map_layer.appendChild(this.patch_layer)
		$(this.patch_layer).draggable();
	},
	clear_overlays: function() {
		if(this.patch_layer) { this.patch_layer.parentNode.removeChild(this.patch_layer); }
	},
	getContainer: function() {
		return WorldMapVisualisation.canvas();
	},
	addControl: function(control) {
		this.controls.push(control);
	}
});

$.extend(WorldMapVisualisation, {
	instance: false,
	display: function(mass, timescale, period) {
		this.depth_control = new WorldMapPatchDepthControl();
		this.instance = new WorldMapVisualisation(mass)
		this.instance.addControl(this.depth_control);
		this.instance.display();
	},
	rescale: function(new_scale, mult) {
		this.instance.rescale(new_scale, mult);
	},
	canvas: function() {
		return document.getElementById("world_map_visualisation_canvas");
	},
	reset: function() {
		var canvas = $(WorldMapVisualisation.canvas());
		canvas.html('')
		canvas.hide();
		this.instance = false;
	},
	depth_control: false
});

DepthControlFunctions = {
	initialize: function(map) {
		this.map = map;
		var container = this.build_control();
		map.getContainer().appendChild(container);
		return container;
	},

	build_control: function() {
		var container = document.createElement('div');
		container.id = "patch-depth-control";
		depth_wrapper = document.createElement('div');
		var title = document.createElement('h4')
		title.appendChild(document.createTextNode('Depth of Quilt'));
		var help = document.createElement('span')
		help.id = 'help-depth-of-quilt';
		help.className = 'help';
		title.appendChild(help);
		// <span id="help-area-of-quilt" class="help"></span>
		depth_wrapper.appendChild(title);
		ddt = document.createElement('span');
		ddt.innerHTML = '';
		this.depth_display_text = ddt;
		depth_wrapper.appendChild(ddt);
		container.appendChild(depth_wrapper);
		// var scale = document.createElement('div');
		// scale.id = 'patch-depth-scale';
		// this.depth_display = scale;
		// container.appendChild(scale);
		this.timescale = document.createElement('div');
		this.timescale.className = 'timescale';
		var label = document.createElement('label')
		label.innerHTML = 'As a fraction of';
		this.timescale.appendChild(label);

		help = document.createElement('span')
		help.id = 'help-fraction-of';
		help.className = 'help';
		label.appendChild(help);
		this.select = document.createElement('select')
		this.select.id = "patch-depth-timescale"
		label.setAttribute('for', this.select.id);
		var range = ['year', 'day', 'second'];
		for (var i = 0; i < range.length; i++) {
			var r = range[i];
			var o = document.createElement('option');
			o.value = r;
			o.innerHTML = '1 ' + r + "'s emissions";
			this.select.appendChild(o);
		};
		this.timescale.style.display = 'none';
		this.timescale.appendChild(this.select);
		container.appendChild(this.timescale);
		return container;
	},

	set_depth: function(mass) {
		this.depth_display_text.innerHTML = mass.patch_depth().to_distance();
		for (var i = 0; i < this.select.childNodes.length; i++) {
			var opt = this.select.childNodes[i];
			opt.selected = (mass.timescale == opt.value);
		};
		this.select.onchange = function(e) {
			scale(this.options[this.selectedIndex].value);
		};
		// only show the timescale selector if the mass is small enough that this makes 
		// some kind of sense
		if(!mass.external_scaling && (mass.mass.percentage.year < 1)) {
			this.timescale.style.display = '';
		} else {
			this.timescale.style.display = 'none';
		}
	}
};

function GoogleMapsPatchDepthControl() { };

Object.extend(GoogleMapsPatchDepthControl.prototype, new GControl(), DepthControlFunctions, {
	getDefaultPosition: function() {
		return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0, 0));
	}
});

function WorldMapPatchDepthControl() { };

Object.extend(WorldMapPatchDepthControl.prototype, DepthControlFunctions, {
	getDefaultPosition: function() {
		return {
			left: 0,
			top: 0,
			right: 'auto',
			bottom: 'auto'
		}
	}
});

