
PbLib.module.load('loader');

var PZD = PZD || {};

PZD.map = (function () {

	var conf,
		items,
		map,
		markerClusterer,
		markerManager,
		tooltip,
		highlight,
		activeMarkers = {},
		pickerCoordinates,
		colorCycle,
		mousePos;

	function initialize (mapConf, mapItems) {

		if (window.GBrowserIsCompatible && GBrowserIsCompatible()) {

			conf = mapConf;
			items = mapItems;

			// create map
			map = new GMap2(document.getElementById("map"));
			map.setCenter(new GLatLng(conf.lat, conf.lng), parseInt(conf.zoomlevel, 10));

			if(conf.zoomlevel == 9) {
				map.disableDragging();
			}

			var customUI = map.getDefaultUI();
			customUI.controls.scalecontrol = false;
			map.setUI(customUI);

			markerClusterer = new MarkerClusterer(map, [], {
				gridSize: 50,
				maxZoom: 16,
				styles: [{
					'url': PbLib.getNewURI("/files/mod_pzd/img/m1.png"),
					'height': 53,
					'width': 53
				}, {
					'url': PbLib.getNewURI("/files/mod_pzd/img/m2.png"),
					'height': 56,
					'width': 56
				}, {
					'url': PbLib.getNewURI("/files/mod_pzd/img/m3.png"),
					'height': 66,
					'width': 66
				}, {
					'url': "http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/images/m4.png",
					'height': 78,
					'width': 78
				}, {
					'url': "http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/images/m5.png",
					'height': 90,
					'width': 90
				}]
			});

//			{
//      'url': "http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/images/m" + i + ".png",
//      'height': sizes[i - 1],
//      'width': sizes[i - 1]
//    }


			// the clusterer adds and removes markers from the map
			// when this happens the marker defaults to it's normal icon which shouldn't happen for the highlighted marker
			GEvent.addListener(map, "moveend", function () {
				if (highlight) {
					highlight.setImage(conf.highlightIcon + '24.png');
				}
			});

			GEvent.addListener(map, 'mousemove', function (e) {
				// used for poly mouseovers
				mousePos = e;
			});

			// reusable tooltip overlay
			tooltip = createTooltip();
			colorCycle = createColorCycle();

			// zoom settings for map
			G_PHYSICAL_MAP.getMinimumResolution = function () {return 9};
			G_NORMAL_MAP.getMinimumResolution = function () {return 9};
			G_SATELLITE_MAP.getMinimumResolution = function () {return 9};
			G_HYBRID_MAP.getMinimumResolution = function () {return 9};

			GEvent.addListener(map,'zoomend', zoomendHandler);

			if (conf.mode == 'full') {

				map.setMapType(G_PHYSICAL_MAP);

				// tile layer for zoomlevel 9

				if (conf.useCustomMapOverlays) {
					addTileOverlay();
				}

				//events on map
				GEvent.addListener(map, "dragend", dragendHandler);

				drawTypeList();
				drawRegionSelector();
				reloadObjects();
				$('searchfield').value = '';

				var filterToggleButton = $('map-divider-toggle');
				if (filterToggleButton) {
					filterToggleButton.observe('click', function() {
						$('fullmap').toggleClassName('closed');
						map.checkResize();
					});
				}

			} else if (conf.mode == 'picker') {

				markerManager = new MarkerManager(map);

				map.setMapType(G_NORMAL_MAP);
				map.disableDoubleClickZoom();

				GEvent.addListener(map, "click", function (overlay, latlng) {
					if (latlng) {
						drawPickerMarker(latlng.x, latlng.y);
					}
				});

				pickerCoordinates = {lon: '', lat: ''};

				if (conf.lat != '' && conf.lng != '') {
					pickerCoordinates.lon = conf.lng;
					pickerCoordinates.lat = conf.lat;
					drawPickerMarker(conf.lng, conf.lat)
				} else {
					map.setCenter(new GLatLng(51.6, 3.9), 9);
				}

				$('submitCoordinates').observe('click', function(event) {
					window.top.$('latitude').value = pickerCoordinates.lat.substr(0, 14);
					window.top.$('longitude').value = pickerCoordinates.lon.substr(0, 14);

					if (window.top.$('zoomlevelSnippet')) {
						window.top.$('zoomlevelSnippet').value = map.getZoom();
					}
					PbLib.destroyDialog();
				});

			} else if (conf.mode == 'seeker') {

				map.setMapType(G_PHYSICAL_MAP);
				if (conf.useCustomMapOverlays) {
					addTileOverlay();
				}
				drawItems();

			} else if (conf.mode == 'showItems') {

				map.setMapType(G_SATELLITE_MAP);
				if (conf.useCustomMapOverlays) {
					addTileOverlay();
				}

				drawItems();
			}
		}
	}

	function createTooltip () {

		var tooltip = new GOverlay();

		tooltip.initialize = function (map) {
			this.div_ = new Element('div', {className: 'map-tooltip'});
			map.getPane(G_MAP_FLOAT_PANE).appendChild(this.div_);
		};

		tooltip.redraw = function (force) {

			if (!force) {
				return;
			}

			if (!this.marker_) {
				this.div_.hide();
				return;
			}

			var markerPos = map.fromLatLngToDivPixel(this.marker_.getPoint());
			var iconAnchor = this.marker_.getIcon().iconAnchor;
			var xPos = markerPos.x + iconAnchor.x + 12;
			var yPos = markerPos.y - iconAnchor.y;
			this.div_.show();
			this.div_.setStyle({
				top:	yPos + 'px',
				left:	xPos + 'px'
			});
		};

		tooltip.showForMarker = function (marker) {

			this.div_.update(marker.title);
			this.marker_ = marker;
			this.redraw(true);
		};

		tooltip.showForPoly = function (item, poly) {
			this.div_.update(item.title);
			var pos = map.fromLatLngToDivPixel(mousePos);
			this.div_.show();
			this.div_.setStyle({
				top:	pos.y + 'px',
				left:	pos.x + 'px'
			});
		};

		tooltip.hide = function () {
			this.marker_ = null;
			this.redraw(true);
		};

		map.addOverlay(tooltip);

		return tooltip;
	}

	function createColorCycle() {

		var cycle = {},
			h = 200, // start in the blue region
			s = 0.8,
			v = 1;

		cycle.nextColor = function () {

			var color;

			h = (h + 37) % 360;
			color = new Color()
			color.setHSV(h, s, v);
			return color;
		}

		return cycle;
	}

	function addTileOverlay () {

		// Set up the copyright information
		// Each image used should indicate its copyright permissions
		var myCopyright = new GCopyrightCollection("© ");
		myCopyright.addCopyright(new GCopyright('PZD',
		  new GLatLngBounds(new GLatLng(-90,-180), new GLatLng(90,180)),
		  0,'©2009'));

		// Create the tile layer overlay and
		// implement the three abstract methods
		var tilelayerZoom9 = new GTileLayer(myCopyright);

		var baseUrl;

		if (conf.overlayType == 1) {
			baseUrl = PbLib.getNewURI("/files/mod_pzd/img/mapImages/");
		} else if (conf.overlayType == 2) {
			baseUrl = PbLib.getNewURI("/files/mod_pzd/img/mapImages2/");
		} else {
			baseUrl = PbLib.getNewURI("/files/mod_pzd/img/mapImages3/");
		}

		tilelayerZoom9.getTileUrl = function(tile, zoom) {
			if (zoom == 9 && tile.x <= 263 && tile.x >= 259 && tile.y >= 168 && tile.y <= 171) {
				return baseUrl + "x" + tile.x + "y" + tile.y +"z9.png";
			} else {
				if (zoom == 9) {
					return baseUrl + "/standard.png";
				} else {
					return "";
				}
			}
		};
		tilelayerZoom9.minResolution = function () {
			return 9;
		};
		tilelayerZoom9.maxResolution = function () {
			return 9;
		};
		tilelayerZoom9.isPng = function () {
			return true;
		};
		tilelayerZoom9.getOpacity = function () {
			return 1.0;
		}

		map.addOverlay(new GTileLayerOverlay(tilelayerZoom9));
	}

	function drawTypeList () {

		var objectTypeList = new Element('ul', {
			'class' : 'visibility-selector'
		});

		// for each category
		for (var i in conf.typeMapping) {
			if (conf.typeMapping.hasOwnProperty(i)) {
				if (!conf.hideInactiveTypes || isActiveType(i, conf.typeMapping[i])) {
					objectTypeList.appendChild(drawType(i, conf.typeMapping[i], false, true));
				}
			}
		}

		$('visibility-selector').insert(objectTypeList);
	}

	function drawType (childId, child, selected, upperLayer) {

		var childLi = new Element('li');
		var childLiInput = childLi.appendChild(new Element('input', {type: 'checkbox'}));
		childLiInput.limeTypeName = childId;
		childLiInput.observe('click', function() {
			changeCheckboxes(childLiInput, childLi);
		});

		childLi.appendChild(new Element('img', {'src' : child.icon}));
		var childLabel = childLi.appendChild(new Element('label').update(child.title));

		if (upperLayer) {
			childLi.observe('click', function(event) {

				if (!Object.isArray(child.children) && (Event.element(event) == childLabel || Event.element(event) == childLi)) {

					if (childLabel.up().hasClassName('open')) {
						childLabel.up().removeClassName('open');
						childLabel.up().addClassName('closed');

						var firstUl = childLabel.up().select('ul').first();
						if (firstUl) {
							childLabel.up().select('ul').first().setStyle({
								'display' : 'none'
							});
						}
					} else if (Event.element(event) == childLabel || Event.element(event) == childLi) {
						childLabel.up().addClassName('open');
						childLabel.up().removeClassName('closed');

						var firstUl = childLabel.up().select('ul').first();
						if (firstUl) {
							childLabel.up().select('ul').first().setStyle({
								'display' : ''
							});
						}
					}
				}
			});
		}

		if (conf.types[childId] == true || selected == true) {
			childLiInput.checked = true;
			conf.types[childId] = true;
			childLi.hasBeenChecked = true;
		} else {
			childLi.hasBeenChecked = false;
		}

		if (!Object.isArray(child.children)) {

			childLabel.addClassName('hasChildren');

			if (upperLayer) {
				childLi.addClassName('closed');
			}

			var childUl = childLi.appendChild(new Element('ul'));

			if (upperLayer) {
				childUl.setStyle({display : 'none'});
			}

			var allChildrenSelected = true;

			for (var i in child.children) {
				if (child.children.hasOwnProperty(i)) {
					if (!conf.hideInactiveTypes || isActiveType(i, child.children[i])) {
						var childUlLi = childUl.appendChild(drawType(i, child.children[i], conf.types[childId], false));
						if (childUlLi.hasBeenChecked == false) {
							allChildrenSelected = false;
						}
					}
				}
			}

			if (allChildrenSelected && conf.types[childId] != true) {
				childLiInput.checked = true;
				conf.types[childId] = true;
			}
		}

		return (childLi);
	}

	function isActiveType(childId, child) {

		if (conf.types[childId]) {
			return true;
		}

		for (var i in child.children) {
			if (isActiveType(i, child.children[i])) {
				return true;
			}
		}

		return false;
	}

	function changeCheckboxes (typeInput, typeLi) {

		if (typeInput.checked) {
			typeLi.select('input').each(function(input) {
				input.checked = true;

				if (!Object.isUndefined(conf.types[input.limeTypeName])) {
					conf.types[input.limeTypeName] = true;
				}
			});

			if (typeLi.up().up()) {
				while ((typeLi = typeLi.up().up())) {
					if ((typeLi.tagName).toLowerCase() == 'li') {

						var mustBeChecked = true;
						typeLi.select('ul').first().select('input').each(function(input) {

							if(input.checked == false) {
								mustBeChecked = false;
							}
						});

						if (mustBeChecked) {
							var firstInput = typeLi.select('input').first();
							firstInput.checked = true;

							if (!Object.isUndefined(conf.types[firstInput.limeTypeName])) {
								conf.types[firstInput.limeTypeName] = true;
							}
						}
					} else {
						break;
					}
				}
			}

		} else {

			typeLi.select('input').each(function(input) {
				input.checked = false;

				if(!Object.isUndefined(conf.types[input.limeTypeName])) {
					conf.types[input.limeTypeName] = false;
				}
			});

			if (typeLi.up().up()) {
				while ((typeLi = typeLi.up().up())) {
					if ((typeLi.tagName).toLowerCase() == 'li') {
						var firstInput = typeLi.select('input').first();
						firstInput.checked = false;

						if (!Object.isUndefined(conf.types[firstInput.limeTypeName])) {
							conf.types[firstInput.limeTypeName] = false;
						}
					} else {
						break;
					}
				}
			}
		}

		reloadObjects();
	}

	function drawRegionSelector () {

		var regionSelector = new Element('div', {
			'id'	: 'regionSelector'
		}).insert('<h4>' + PbLib.g('Also show object of these regions:') + '</h4>');

		var ul = new Element('ul');
		regionSelector.insert(ul);

		var minimalOneRegion = false;

		for (var i in conf.regions) {
			if (conf.regions.hasOwnProperty(i)) {

				var region = conf.regions[i];

				if (region.visible) {
					minimalOneRegion = true;
					var input = new Element('input', {type: 'checkbox'});
					input.regionId = i;
					input.checked = region.selected;
					input.observe('click', changeRegionHandler);

					var li = new Element('li').update(input).insert(region.title);
					ul.insert(li);
				}
			}
		}

		if (minimalOneRegion) {
			$('visibility-selector').insert(regionSelector);
		}
	}

	var getItemIcon = (function () {

		var icons = {};

		return function (image) {

			if (!icons[image]) {

				var itemIcon = new GIcon();

				if (image == 'panned') {
					itemIcon.image = conf.highlightIcon + '24.png';
				} else {
					itemIcon.image = image + '24.png';
				}

				itemIcon.iconSize = new GSize(24, 24);
				itemIcon.shadowSize = new GSize(22, 20);
				itemIcon.iconAnchor = new GPoint(6, 20);

				icons[image] = itemIcon;
			}

			return icons[image];
		}

	}());

	function drawItems () {

		var batch = [],
			markers = {},
			i = items.length,
			item;

		while (i--) {

			item = items[i];

			if (!activeMarkers[item.objectId]) {

				//make marker
				var marker = new GMarker(new GLatLng(item.lat, item.lng), {icon: getItemIcon(item.icon)});
				marker.probaseIcon = item.icon;
				marker.title = item.title;
				marker.objectId = item.objectId;

				if (item.route) {
					item.route = item.route.evalJSON();
				}
				if (item.area) {
					item.area = item.area.evalJSON();
				}

				if (item.route && (item.route.waypoints || item.route.route)) {
					(function () {
						var myItem = item;
						marker.showRoute = function () {
							if (!this.route) {
								this.route = drawRoute(myItem.route);
								GEvent.addListener(this.route, 'click', highlightItem.curry(myItem.objectId, false));
								GEvent.addListener(this.route, 'mouseover', tooltip.showForPoly.bind(tooltip, myItem, this.route));
								GEvent.addListener(this.route, 'mouseout', tooltip.hide.bind(tooltip));
							} else {
								this.route.show();
							}
						}
						marker.hideRoute = function () {
							this.route && this.route.hide();
						}
					}());
					if (!conf.hidePolys) {
						marker.showRoute();
					}
				}

				if (item.area && (item.area.waypoints || item.area.area)) {
					(function () {
						var myItem = item;
						marker.showArea = function () {
							if (!this.area) {
								this.area = drawArea(myItem.area);
								GEvent.addListener(this.area, 'click', highlightItem.curry(myItem.objectId, false));
								GEvent.addListener(this.area, 'mouseover', tooltip.showForPoly.bind(tooltip, myItem, this.area));
								GEvent.addListener(this.area, 'mouseout', tooltip.hide.bind(tooltip));
							} else {
								this.area.show();
							}
						}
						marker.hideArea = function () {
							this.area && this.area.hide();
						}
					}());
					if (!conf.hidePolys) {
						marker.showArea();
					}
				}

				addMarkerEvents(marker);

			} else {

				marker = activeMarkers[item.objectId];
			}


			if (!markers[item.objectId]) {
				markers[item.objectId] = marker;
				batch.push(marker);
			}
		}

		for (i in activeMarkers) {
			if (!markers[i]) {
				if (activeMarkers[i].area) {
					GEvent.clearListeners(activeMarkers[i].area);
					map.removeOverlay(activeMarkers[i].area);
				}
				if (activeMarkers[i].route) {
					GEvent.clearListeners(activeMarkers[i].route);
					map.removeOverlay(activeMarkers[i].route);
				}
			}
		}
		markerClusterer.clearMarkers();
		markerClusterer.addMarkers(batch);
		activeMarkers = markers;
	}

	function addMarkerEvents(marker) {

		GEvent.addListener(marker, 'mouseover', function () {
			tooltip.showForMarker(this);
			this.showRoute && this.showRoute();
			this.showArea && this.showArea();
		});

		GEvent.addListener(marker, 'mouseout', function () {
			tooltip.hide();
			if (highlight !== this && conf.hidePolys) {
				this.hideRoute && this.hideRoute();
				this.hideArea && this.hideArea();
			}
		});

		// not if showitems because that is only for showing, not for getting data of an object
		if (conf.mode != 'showItems') {

			GEvent.addListener(marker, "click", function () {
				highlightItem(marker.objectId);
			});
		}
	}

	function drawRoute(route) {

		var waypoints,
			latLngs = [],
			l,
			p,
			poly,
			color,
			baseColor,
			highlightColor;

		if (route.travelMode) {
			waypoints = route.route;
		} else {
			waypoints = route.waypoints;
		}

		l = waypoints.length;
		while (l--) {
			p = waypoints[l];
			latLngs[l] = new GLatLng(p[0], p[1]);
		}

		color = colorCycle.nextColor();
		baseColor = color.toString();
		color.setS(1);
		color.setV(0.9)
		highlightColor = color.toString();

		poly = new GPolyline(latLngs, baseColor, 3);
		map.addOverlay(poly);

		GEvent.addListener(poly, 'mouseover', function () {
			poly.setStrokeStyle({color: highlightColor, weight: 4});
		});

		GEvent.addListener(poly, 'mouseout', function () {
			poly.setStrokeStyle({color: baseColor, weight: 3});
		});

		return poly
	}

	function drawArea(area) {

		var waypoints,
			latLngs = [],
			l,
			p,
			poly,
			color,
			baseColor,
			highlightColor;

		if (area.travelMode) {
			waypoints = area.area;
		} else {
			waypoints = area.waypoints;
		}

		l = waypoints.length;
		while (l--) {
			p = waypoints[l];
			latLngs[l] = new GLatLng(p[0], p[1]);
		}
		latLngs.push(latLngs[0]);

		color = colorCycle.nextColor();
		baseColor = color.toString();
		color.setS(1);
		color.setV(0.9)
		highlightColor = color.toString();

		poly = new GPolygon(latLngs, baseColor, 1, 0.6, baseColor, 0.4);
		map.addOverlay(poly);

		GEvent.addListener(poly, 'mouseover', function (e) {
			poly.setStrokeStyle({color: highlightColor, weight: 2});
			poly.setFillStyle({color: highlightColor});
		});

		GEvent.addListener(poly, 'mouseout', function () {
			poly.setStrokeStyle({color: baseColor, weight: 1});
			poly.setFillStyle({color: baseColor});
		});

		return poly
	}

	function drawPickerMarker (lon, lat) {

		markerManager.clearMarkers();

		//point on map
		var point = new GLatLng(lat, lon);
		//make marker
		var marker = new GMarker(point, {draggable: true});

		GEvent.addListener(marker, "dragend", function () {
			var latlng = marker.getLatLng();
			pickerCoordinates.lon = latlng.x + '';
			pickerCoordinates.lat = latlng.y + '';
			$('selectedCoordinate').update(pickerCoordinates.lon.substring(0,4) + '/' + pickerCoordinates.lat.substring(0,4));
		});

		markerManager.addMarker(marker, 9);
		markerManager.refresh();

		pickerCoordinates.lon = lon.toString();
		pickerCoordinates.lat = lat.toString();

		$('selectedCoordinate').update(pickerCoordinates.lon.substring(0,4) + '/' + pickerCoordinates.lat.substring(0,4));
	}

	function highlightItem (id, pan) {

		var marker,
			highlightDiv;

		if (activeMarkers && activeMarkers[id]) {

			if (highlight) {
				highlight.setImage(highlight.probaseIcon + '24.png');
				if (conf.hidePolys) {
					highlight.hideRoute && highlight.hideRoute();
					highlight.hideArea && highlight.hideArea();
				}
			}

			marker = activeMarkers[id];
			if (pan) {
				map.setZoom(13);
				map.panTo(marker.getLatLng());
			}
			marker.setImage(conf.highlightIcon + '24.png');
			marker.showRoute && marker.showRoute();
			marker.showArea && marker.showArea();
			highlight = marker;

			if (!(highlightDiv = $('highlightDiv'))) {
				highlightDiv = new Element('div', {id: 'highlightDiv', className: 'current-object'});
				$('pzdMapList').insert({before: highlightDiv});
			}

			new Ajax.Request(PbLib.getNewURI('l/pzd/map/get_object_data'), {
				parameters: {objectId: id},
				onSuccess: function (response) {
					highlightDiv.update(response.responseText);
					highlightDiv.scrollIntoView(false);
				}
			});
		}
	}

	function setItems (newItems) {

		items = newItems;
		drawItems();
	}

	function addItems (newItems) {
		items = items.concat(newItems);
		drawItems();
	}

	function setItemList (itemlist) {

		if ($('pzdMapList')) {
			$('pzdMapList').replace(itemlist);
		}
	}

	function reloadObjects () {

		PbLib.startLoader('');

		new Ajax.Request(PbLib.getNewURI('l/pzd/map/change_selection'), {
			parameters: {
				conf: Object.toJSON(conf)
			},
			onSuccess: function (response) {

				response = response.responseJSON;

				//reload items on map
				if (response.items) {
					setItems(response.items);
				}

				//reload itemlist under map
				if (response.list) {
					setItemList(response.list);
				}
				PbLib.stopLoader();
			}
		});
	}

	function addRelatedObjects(objectId) {

		PbLib.startLoader('');

		new Ajax.Request(PbLib.getNewURI('l/pzd/map/related_objects'), {
			parameters: {objectId: objectId},
			onSuccess: function (response) {

				response = response.responseJSON;
				if (response.items) {
					addItems(response.items);
					drawItems();
				}

				PbLib.stopLoader();
			}
		});
	}

	function zoomendHandler (oldLevel, newLevel) {

		if (conf.useZoomlevels && conf.useZoomlevels == 1) {

			if (newLevel < oldLevel && newLevel < 9) {
				newLevel = 9;
				map.setZoom(newLevel);
			} else if (newLevel < oldLevel && newLevel > 9 && newLevel <12) {
				newLevel = 9;
				map.setZoom(newLevel);
			} else if (newLevel > 9 && newLevel <12) {
				//inzoomen
				newLevel = 12;
				map.setZoom(newLevel);
			}
		}

		if (newLevel >= 13) {
			map.setMapType(G_SATELLITE_MAP);
		} else if (newLevel > 9 && newLevel <= 12) {
			map.setMapType(G_PHYSICAL_MAP);
		}

		conf.zoomlevel = newLevel;

		if (newLevel == 9 && oldLevel != 9) {
			map.setCenter(new GLatLng(conf.centerLat, conf.centerLng), newLevel);
		}

		if (newLevel == 9) {
			map.disableDragging();
		} else {
			map.enableDragging();
		}

		if (conf.mode == 'full') {
			var bounds = map.getBounds();
			var Ne = bounds.getNorthEast();
			var Sw = bounds.getSouthWest();

			conf.bounds = {
				'maxLon' : Ne.x,
				'maxLat' : Ne.y,
				'minLon' : Sw.x,
				'minLat' : Sw.y
			};
		}
	}

	function dragendHandler () {

		var bounds = map.getBounds();
		var Ne = bounds.getNorthEast();
		var Sw = bounds.getSouthWest();

		conf.bounds = {
			'maxLon' : Ne.x,
			'maxLat' : Ne.y,
			'minLon' : Sw.x,
			'minLat' : Sw.y

		}
	}

	function changeRegionHandler () {

		conf.regions[this.regionId].selected = this.checked ? 1 : 0;

		reloadObjects();
	}

	return {
		initialize: initialize,
		highlightItem: highlightItem,
		setItems: setItems,
		setItemList: setItemList,
		addRelatedObjects: addRelatedObjects
	};

}());

