/**
 * MapBox - container for map
 * @extends Component
 */
MapBox = Class.create(Component, {
	init: function() {
		this.container.addClassName('window');
		this.map;
		this.mapOn;
		this.lastLoadedBounds;
	},

	close: function() {
		$A(this.map.geoTags).each(function(geoTag) {
			if(geoTag)
				this.map.removeOverlay(geoTag);
		}, this);
		google.maps.Unload();
		this.contents.removeChildren();
		this.setVisibility(false);
		this.mapOn = false;
	}
});

Layout.addMethods({
	geoTag: function(category) {
		if (typeof google.maps.BrowserIsCompatible != "undefined" && google.maps.BrowserIsCompatible()) {
			var mapBox = $A(this.components).find(function(component) { return component instanceof MapBox; })
			mapBox.geoTag(category);
		} else {
			alert(language('nomaps-alert'));
		}
	}
});

if(typeof google != 'undefined')
	google.setOnLoadCallback(function() {
		if(typeof google.maps.BrowserIsCompatible != "undefined" && google.maps.BrowserIsCompatible())
		{
			var handle = new google.maps.Icon();
			handle.iconSize = new google.maps.Size(11, 11);
			handle.iconAnchor = new google.maps.Point(5, 5);
			handle.maxHeight = 0; //undocumented
			handle.dragCrossImage = ' '; //undocumented

			var resizeNE = new google.maps.Icon(handle, 'generated/icons/resizeNE.png');
			var resizeNW = new google.maps.Icon(handle, 'generated/icons/resizeNW.png');
			var resizeSE = new google.maps.Icon(handle, 'generated/icons/resizeNW.png');
			var resizeSW = new google.maps.Icon(handle, 'generated/icons/resizeNE.png');
			var moveIcon = new google.maps.Icon(handle, 'generated/icons/move.png');

			/**
			 * MapBox.geoTag - load a specified category for viewing/editing
			 * @method
			 * @param {int} category - the category
			 */
			MapBox.addMethods({
				geoTag: function(category) {
					if(!this.mapOn)
						this.loadMap();
					if(category)
					{
						if(!this.map.geoTags[category])
						{
							new RPC('ajax.geotag.xml.php', {
								parameters: {
									mode: this.layout.edit ? 'load' : 'find',
									category: category
								},
								onSuccess: (function(transport) {
									var xml = transport.responseXML;
									var markers = xml.getElementsByTagName("marker");
									if(markers.length)
									{
										var category = parseInt(markers[0].getAttribute("category"));
										var catName = markers[0].getAttribute("catName");
										if(markers[0].getAttribute("latMin"))
										{
											var sw = new google.maps.LatLng(
												parseFloat(markers[0].getAttribute("latMin")),
												parseFloat(markers[0].getAttribute("lngMin"))
											);
											var ne = new google.maps.LatLng(
												parseFloat(markers[0].getAttribute("latMax")),
												parseFloat(markers[0].getAttribute("lngMax"))
											);
											var rect = new GeoTag(category, catName, new google.maps.LatLngBounds(sw, ne));
											this.map.geoTags[category] = rect;
											this.map.centerAndZoom(category);
											this.map.addOverlay(rect);
										}
										else if(this.layout.edit)
										{
											var rect = new GeoTag(category, catName);
											this.map.geoTags[category] = rect;
		
											this.map.addOverlay(rect);
										}
									}
								}).bind(this)
							});
						}
						else
						{
							this.map.centerAndZoom(category);
						}
					}
					else
					{
						this.loadTags();
					}
				},
				/**
				 * MapBox.loadMap - load a new google.maps.Map object
				 * @method
				 */
				loadMap: function() {
					this.mapOn = true;
					if(this.draggable)
					{
						Position.prepare();
						this.container.style.top = (10 + Position.deltaY) + 'px';
					}
					this.setVisibility(true);
					this.contents.removeChildren()
/*
					var searchBox = this.contents.appendChild(new Element('div'));
					var searchInput = searchBox.appendChild(new Element('input', { type: 'text' }));
					new OverrideSubmit(searchInput, (function() {
						this.showAddress(searchInput.value);
					}).bind(this));
*/
					var mapFrame = this.contents.appendChild(new Element('div', { className: 'map_frame' }));
					this.map = new google.maps.Map2(mapFrame);
					this.map.addControl(this.layout.edit ? new google.maps.LargeMapControl() : new google.maps.SmallMapControl());
					this.map.addControl(new google.maps.MapTypeControl(true));
					this.map.setCenter(new google.maps.LatLng(55, 0), 4);
					this.map.setMapType(G_HYBRID_MAP);
					this.map.enableScrollWheelZoom();
					this.map.enableContinuousZoom();
					if(this.layout.edit)
						this.map.enableGoogleBar();
					this.map.geoTags = {};
					this.map.mapBox = this;
					this.redrawShadow();

					this.geocoder = new google.maps.ClientGeocoder();

					google.maps.Event.addListener(this.map, 'moveend', this.loadTags.bind(this, false));
					google.maps.Event.addListener(this.map, 'zoomend', (function(oldLevel, newLevel) {
						if(newLevel > oldLevel)
							this.loadTags(true);
					}).bind(this));
				},
				/**
				 * MapBox.loadTags - load all the geotags in the current viewport
				 * @method
				 * @param {boolean} force - force reload of new markers, even if viewport hasn't moved enough
				 */
				loadTags: function(force) {
					if(!force && this.lastLoadedBounds && this.lastLoadedBounds.containsBounds(this.map.getBounds()))
						return;
	
					var b = this.map.getBounds();
					var span = b.toSpan();
	
					var sw = new google.maps.LatLng(b.getSouthWest().lat() - span.lat()/2, b.getSouthWest().lng() - span.lng()/2);
					var ne = new google.maps.LatLng(b.getNorthEast().lat() + span.lat()/2, b.getNorthEast().lng() + span.lng()/2);
	
					this.lastLoadedBounds = new google.maps.LatLngBounds(sw, ne);
	
					new RPC('ajax.geotag.xml.php', {
						parameters: {
							mode: 'load',
							latMax: ne.lat(),
							latMin: sw.lat(),
							lngMax: ne.lng(),
							lngMin: sw.lng(),
							width: this.map.getSize().width,
							height: this.map.getSize().height
						},
						onSuccess: (function(transport) {
							var xml = transport.responseXML;
							for(var i in this.map.geoTags)
								if(this.map.geoTags[i])
									this.map.removeOverlay(this.map.geoTags[i]);
	
							var xml = transport.responseXML;
							var markers = xml.getElementsByTagName("marker");
							for (var i = 0; i < markers.length; i++) {
								var category = parseInt(markers[i].getAttribute("category"));
								var catName = markers[i].getAttribute("catName");
								var sw = new google.maps.LatLng(
									parseFloat(markers[i].getAttribute("latMin")),
									parseFloat(markers[i].getAttribute("lngMin"))
								);
								var ne = new google.maps.LatLng(
									parseFloat(markers[i].getAttribute("latMax")),
									parseFloat(markers[i].getAttribute("lngMax"))
								);
								var rect = new GeoTag(category, catName, new google.maps.LatLngBounds(sw, ne));
								this.map.addOverlay(rect);
								this.map.geoTags[category] = rect;
							}
						}).bind(this)
					});
				},
				showAddress: function(address) {
					if(this.geocoder) {
						this.map.getContainer().setOpacity(0.5);
						this.geocoder.getLatLng(
							address,
							(function(point) {
								this.map.getContainer().setOpacity(1);
								if (point) {
									//this.map.setZoom(11);
									this.map.panTo(point);
								}
							}).bind(this)
						);
					}
				}
			});
			/**
			 * GeoTag - rectanglular marker to show and edit boundaries of a geotag
			 * @constructor
			 * @param {int} category - category of geotag
			 * @param {String} catName - category name of geotag
			 * @param {google.maps.LatLngBounds} bounds - boundaries of geotag
			 */
			function GeoTag(category, catName, bounds) {
				this.bounds = bounds;
				this.category = category;
				this.catName = catName;
			}
			GeoTag.prototype = new google.maps.Overlay();

			GeoTag.prototype.initialize = function(map) {
				this.map = map;
				if(!this.bounds)
				{
					var span = this.map.getBounds().toSpan();
					var c = this.map.getCenter();
					var sw = new google.maps.LatLng(c.lat() - span.lat()/8, c.lng() - span.lng()/8);
					var ne = new google.maps.LatLng(c.lat() + span.lat()/8, c.lng() + span.lng()/8);
					this.bounds = new google.maps.LatLngBounds(sw, ne);
				}

				var div = new Element('div', { className: 'rect' });
				this.map.getPane(G_MAP_MARKER_SHADOW_PANE).appendChild(div);

				var label = this.map.getPane(G_MAP_MARKER_PANE).appendChild(new Element('div', { className: 'label' }));
				label.setOpacity(0.8);
				if(this.map.mapBox.layout.edit)
				{
					label.appendChild(new TextButton(this.map.mapBox.layout.asscatName.bind(this.map.mapBox.layout, this.category, this.catName), this.catName));
					label.appendChild($T(' '));
					label.appendChild(new ImageButton(
						this.deleteTag.bind(this), 'generated/icons/delete.png', 'del', 'Delete', 'generated/icons/hover_delete.png' //lang
					));
				}
				else
				{
					label.appendChild(new TextButton(this.map.mapBox.layout.showCat.bind(this.map.mapBox.layout, this.category), this.catName));
				}

				label.style.display = "none";
				google.maps.Event.addDomListener(div, "mouseover", function() {
					label.style.display = "block";
				});
				google.maps.Event.addDomListener(div, "mouseout", function() {
					label.style.display = "none";
				});
				google.maps.Event.addDomListener(label, "mouseover", function() {
					this.style.display = "block";
				});
				google.maps.Event.addDomListener(label, "mouseout", function() {
					this.style.display = "none";
				});

				google.maps.Event.addDomListener(div, "click", this.map.centerAndZoom.bind(this.map, this.category, true));

				if(this.map.mapBox.layout.edit)
				{
					this.handleNE = new google.maps.Marker(this.map.getCenter(), {icon: resizeNE, draggable: true});
					this.handleNW = new google.maps.Marker(this.map.getCenter(), {icon: resizeNW, draggable: true});
					this.handleSE = new google.maps.Marker(this.map.getCenter(), {icon: resizeSE, draggable: true});
					this.handleSW = new google.maps.Marker(this.map.getCenter(), {icon: resizeSW, draggable: true});
					this.handleMove = new google.maps.Marker(this.map.getCenter(), {icon: moveIcon, draggable: true} );

					this.map.addOverlay(this.handleNE);
					this.map.addOverlay(this.handleNW);
					this.map.addOverlay(this.handleSE);
					this.map.addOverlay(this.handleSW);
					this.map.addOverlay(this.handleMove);

					google.maps.Event.addListener(this.handleMove, 'drag', (function() {
						var span = this.bounds.toSpan();
						var center = this.handleMove.getPoint();
						this.bounds = new google.maps.LatLngBounds(
							new google.maps.LatLng(center.lat() - span.lat()/2, center.lng() - span.lng()/2),
							new google.maps.LatLng(center.lat() + span.lat()/2, center.lng() + span.lng()/2));
						this.redraw(true);
					}).bind(this));
					google.maps.Event.addListener(this.handleNE, 'drag', this.extendTo.bind(this, this.handleSW, this.handleNE));
					google.maps.Event.addListener(this.handleNW, 'drag', this.extendTo.bind(this, this.handleSE, this.handleNW));
					google.maps.Event.addListener(this.handleSE, 'drag', this.extendTo.bind(this, this.handleNW, this.handleSE));
					google.maps.Event.addListener(this.handleSW, 'drag', this.extendTo.bind(this, this.handleNE, this.handleSW));

					google.maps.Event.addListener(this.handleMove, 'dragend', this.saveTag.bind(this));
					google.maps.Event.addListener(this.handleNE, 'dragend', this.saveTag.bind(this));
					google.maps.Event.addListener(this.handleNW, 'dragend', this.saveTag.bind(this));
					google.maps.Event.addListener(this.handleSE, 'dragend', this.saveTag.bind(this));
					google.maps.Event.addListener(this.handleSW, 'dragend', this.saveTag.bind(this));
				}

				this.div_ = div;
				this.label_ = label;
				this.initialized = true;
			}
			/**
			 * GeoTag.extendTo - extend boundaries of geotag to specified points
			 * @method
			 * @param {google.maps.Marker} from - start marker
			 * @param {google.maps.Marker} to - end marker
			 */
			GeoTag.prototype.extendTo = function(from, to)
			{
				var b = new google.maps.LatLngBounds();
				b.extend(from.getPoint());
				b.extend(to.getPoint());
				this.bounds = b;
				this.redraw(true);
			}

			/**
			 * GeoTag.redraw - redraws the geotag
			 * @method
			 * @param {boolean} force - force redraw
			 */
			GeoTag.prototype.redraw = function(force)
			{
				if(force && this.initialized)
				{
					var p1 = this.map.fromLatLngToDivPixel(this.bounds.getSouthWest());
					var p2 = this.map.fromLatLngToDivPixel(this.bounds.getNorthEast());
					this.label_.style.left = Math.min(p1.x, p2.x) + "px";
					this.label_.style.top  = (Math.min(p1.y, p2.y)-20) + "px";
					this.div_.style.left   = Math.min(p1.x, p2.x) + "px";
					this.div_.style.top    = Math.min(p1.y, p2.y) + "px";
					this.div_.style.width  = Math.abs(p1.x-p2.x) + "px";
					this.div_.style.height = Math.abs(p1.y-p2.y) + "px";
					if(this.map.mapBox.layout.edit)
					{
						var latN = this.bounds.getNorthEast().lat();
						var latS = this.bounds.getSouthWest().lat();
						var lngW = this.bounds.getSouthWest().lng();
						var lngE = this.bounds.getNorthEast().lng();

						this.handleNE.setPoint(new google.maps.LatLng(latN, lngE));
						this.handleNW.setPoint(new google.maps.LatLng(latN, lngW));
						this.handleSE.setPoint(new google.maps.LatLng(latS, lngE));
						this.handleSW.setPoint(new google.maps.LatLng(latS, lngW));
						this.handleMove.setPoint(this.bounds.getCenter());
					}
				}
			}
			/**
			 * GeoTag.getCenter - calculates center of geotag
			 * @method
			 * @return {google.maps.LatLng} - coordinates of center
			 */
			GeoTag.prototype.getCenter = function() {
				return this.bounds.getCenter();
			}
			/**
			 * GeoTag.remove - remove the geotag from the map
			 * @method
			 */
			GeoTag.prototype.remove = function() {
				if(this.initialized)
				{
					if(this.map.mapBox.layout.edit)
					{
						this.map.removeOverlay(this.handleNE);
						this.map.removeOverlay(this.handleNW);
						this.map.removeOverlay(this.handleSE);
						this.map.removeOverlay(this.handleSW);
						this.map.removeOverlay(this.handleMove);
						delete this.handleNE;
						delete this.handleNW;
						delete this.handleSE;
						delete this.handleSW;
						delete this.handleMove;
						this.initialized = false;
					}
					this.div_.parentNode.removeChild(this.div_);
					this.label_.parentNode.removeChild(this.label_);
					delete this.map.geoTags[this.category];
				}
			}
			/**
			 * GeoTag.copy - make a copy of the geotag
			 */
			GeoTag.prototype.copy = function() {
				return new GeoTag(this.category, this.catName, this.bounds);
			}
			/**
			 * GeoTag.saveTag - save the geotags current coordinates
			 * @method
			 */
			GeoTag.prototype.saveTag = function()
			{
				wait();
				google.maps.DownloadUrl(
					'ajax.geotag.xml.php?mode=set&category=' + this.category
					+ '&latMin=' + this.bounds.getSouthWest().lat() + '&lngMin=' + this.bounds.getSouthWest().lng()
					+ '&latMax=' + this.bounds.getNorthEast().lat() + '&lngMax=' + this.bounds.getNorthEast().lng(),
					function(data, responseCode)
					{
						unwait();
						var xml = data.responseXML;
		//				this.map.mapBox.layout.errorAlerts(xml);
					}
				);
			}
			/**
			 * GeoTag.deleteTag - delete the geotag from the database
			 * @method
			 */
			GeoTag.prototype.deleteTag = function()
			{
				wait();
				google.maps.DownloadUrl(
					'ajax.geotag.xml.php?mode=delete&category=' + this.category,
					function(data, responseCode)
					{
						unwait();
						var xml = data.responseXML;
		//				this.map.mapBox.layout.errorAlerts(xml);
					}
				);
				this.map.removeOverlay(this.map.geoTags[this.category]);
			}
			/**
			 * google.maps.Map2.centerAndZoom - center the map on the specific geotag and set a suitable zoom level
			 * @method
			 * @param {int} category - category of geotag
			 * @param {boolean} noZoom - disable zooming
			 */
			google.maps.Map2.prototype.centerAndZoom = function(category, noZoom)
			{
				var zoom = this.getBoundsZoomLevel(this.geoTags[category].bounds)
				if(!noZoom && (!this.getCenter() || zoom != this.getZoom()))
				{
					this.setCenter(this.geoTags[category].getCenter(), zoom);
					this.setMapType(G_HYBRID_MAP);
				}
				else
				{
					this.panTo(this.geoTags[category].getCenter());
				}
			}
		}
	});