/**
 * Reisadvies Points of Interest
 *
 * @version   1.00.090602
 * @author    LBI Lost Boys
 */
NS(function($){

	var CLASS_HOVER = 'hover';
	var DIALOG_POI = 'poi';
	
	/**
	 * Points of interest controller
	 */
	function Pois(){
		NS.relateLink(/update-poi/, this.handleClick.bind(this));
		NS.relateLink(/poi-map/, this.toggleMap.bind(this));
		NS.subscribe('change', this.handleChange.bind(this));
	}
	
	Pois.prototype = {
		handleClick:function(link, rel) {
			var panel = this.findPanel(link);
			this.updatePOIPanel(panel, link.href);
			return true;
		},

		handleChange:function(e) {
			var input = e.target;
			if(/poi-result/i.test(input.className)) {
				this.updateTravelMethod(input);
			}
		},

		updateTravelMethod:function(input) {
			var panel = this.findPanel(input);
			var method = panel.find('.travel-method select')[0];
			var post = NS.getFormValues(input.form);
			var url = NS.getProperty('POST_ALT_TRAVEL');
			NS.XHR.sendAndLoad(post, url, function(xml){
				NS.autocomplete.handleResponse(xml, method);
			});
		},

		findPanel:function(origin) {
			var advice = $(origin).closest('div.travel-advice');
			var panel = advice.find('div.advice-panel');
			return panel;
		},

		findPois:function(origin) {
			var panel = this.findPanel(origin);
			return panel.find('.poi-results li');
		},

		updatePOIPanel:function(panel, url) {
			NS.XHR.load(url, function(xml){
				NS.DOM.write(panel, $(xml).find('response').text());
				//+"<a rel='dialog-poicategory' href='findPoiList.ajax?outwardTrip.potentialToLocation.where=Amsterdam%20Centraal%20station&outwardTrip.potentialToLocation.what='>zoek iets anders</a>");
				panel.show();
			});
		},

		toggleMap:function(link, rel) {
			if(!link._map) {
				link._map = new PoiMap();
			}

			link._map.filterMarkers(link);

			return true;
		},
			
		/**
		 * The POI marker class cannot be created before the google maps api
		 * has been loaded. getMarker does this dynamically on request.
		 */
		getMarker:function(Marker) {
			if(!this.POIMarker) {
				this.POIMarker = NS.Class.extend(
					Marker, 
					function(point){
						this.point = point;
						this._node = $('<a href="#" class="poi-marker"></a>');
					},{
					initialize:function(map){
						this.map = map;
						this.pane = map.getPane(G_MAP_MAP_PANE);
						this.pane.appendChild(this._node[0]);
					},
					write:function(html) {
						this._node.html(html);
					},
					linkToResult:function(poi) {
						var marker = this._node;
						marker.addClass(poi.className);
						marker.hover(
							function(){ poi.addClass(CLASS_HOVER);}, 
							function(){ poi.removeClass(CLASS_HOVER); });

						poi.hover(
							function(){ marker.addClass(CLASS_HOVER);}, 
							function(){ marker.removeClass(CLASS_HOVER); });

						marker.bind('click', function(e){
							NS.Dialogs.open(DIALOG_POI, poi.find("a")[0]);
							e.preventDefault();
						});
					},
					remove:function() {
						this.pane.removeChild(this._node[0]);
					},
					redraw:function() {
						var point = this.map.fromLatLngToDivPixel(this.point);
						this._node.css({
							left: point.x + 'px',
							top: point.y + 'px'
						});
					}
				});
			}
			return this.POIMarker;
		}
	};


	/**
	 * Poi Map
	 * 
	 */
	function PoiMap() {
	}

	PoiMap.prototype = {
		filterMarkers: function (origin) {
			this.origin = origin;
			this.container = $(origin).closest('.advice-panel').find('.poi-map');
			if(this.container.is(':visible')) {
				this.container.slideUp();
			} else {
				this.container.slideDown(
					this.toggleMap.bind(this)
				);
			}
		},

		toggleMap:function() {
			if(!this.map) {
				var googleJS = NS.getProperty('GOOGLE_API_URL') + 
					'?key=' + NS.getProperty('GOOGLE_API_KEY');
				$.getScript(googleJS, this.initialize.bind(this));
			} else {
				this.displayPOIs();
			}
		},
			
		initialize:function() {
			if(!google.maps || !google.maps.Map2) {
				google.load("maps", "2.92", {
					callback: this.displayGoogleMap.bind(this)
				});
			} else {
				this.displayGoogleMap();
			}
		},

		displayGoogleMap:function() {
			try {
				if(!this.map) {
					var node = this.container[0];
					this.map = new GMap2(node);
					this.map.setCenter(new GLatLng(52.369174, 4.899130), 6);
					this.map.setMapType(G_NORMAL_MAP);
					this.smallControl = new GSmallMapControl();
					this.map.addControl(this.smallControl);
					this.displayPOIs();
				}
			} catch (e) {
				var self = this;
				setTimeout(function(){
					self.displayGoogleMap.call(self);
				}, 1000);
			}
		},

		displayPOIs:function() {
			this.map.clearOverlays();
			
			var pois = NS.getApplication('pois'),
				points = pois.findPois(this.origin),
				bounds = new GLatLngBounds(),
				Marker = pois.getMarker(GMarker);

			for(var i=0; i<points.length; i++) {
				var poi = $(points[i]),
					latlng = poi.find(".geo span"),				
					lat = parseFloat(latlng[0].innerHTML, 10),
					lng = parseFloat(latlng[1].innerHTML, 10),
					point = new GLatLng(lat, lng);

				bounds.extend(point);
				
				var marker = new Marker(point);
				marker.write(i+1);
				marker.linkToResult(poi);
				this.map.addOverlay(marker);
			}

			var clat = (bounds.getNorthEast().lat() + bounds.getSouthWest().lat()) /2,
				clng = (bounds.getNorthEast().lng() + bounds.getSouthWest().lng()) /2,
				zoom = this.map.getBoundsZoomLevel(bounds) -1;
			
			this.map.setZoom(zoom);
			this.map.setCenter(new GLatLng(clat,clng));
		}
	}

	/**
	 * The POI dialog displays additional information for points of interest.
	 */
	var POIDialog = NS.Dialogs.register('poi', NS.Class.extend(
		NS.Dialog,
		function(){
			this.content = $("#poi-details");
		}, {

		activate:function(toggle) {
			if(toggle) {
				this.write('');
				var url = this.origin.href, 
					input = $(this.origin).closest('li').find('input');

				NS.XHR.load(url, this.displayDetails.bind(this));
				input.click();
			}
		},

		displayDetails:function(xml) {
			var html = $(xml).find('response').text();
			this.write(html);
		}
	}));

	/**
	 * The POI category dialog enables entry of free text as a category.
	 */
	NS.Dialogs.register('poicategory', NS.Class.extend(
		NS.Dialog,
		function(){
			this.form = this.container.find('form')[0];
			NS.subscribe('submit', this.updateCategory.bind(this));
		}, {

		activate:function(toggle) { 
			if(toggle) {
				// name/value pairs from this.origin are copied to the dialog's inputs;
				// not so pretty, but the same dialog is used by up to 4 locations

				var href = this.origin.href;
				var paramReg = /\?([^#]+)/;
				
				if(paramReg.test(href)) {
					var params = paramReg.exec(href)[1].split('&');
					var whatReg = /\.what/i;

					for(var i=0; i<2; i++) {
						var input, 
							param = params[i].split('='), 
							name = param[0], 
							value = param[1];
						
						if(whatReg.test(name)) {
							input = $('#poicategory-what');
						} else {
							input = $('#poicategory-where');
						}

						input.attr('name', name);
						input.val(unescape(value || ''));
					}
				}
			}
		},
		
		// called via the submit listener, both on enter, and on the dialog-submit link
		updateCategory:function(e) {
			if(e.target !== this.form) {
				return;
			}
			
			// the form is never submitted
			e.preventDefault();
		
			// find the right panel, and send the form. Fires validation automatically.
			var pois = NS.getApplication('pois');
			var panel = pois.findPanel(this.origin);
			var self = this;

			NS.XHR.sendForm(this.form, null, function(xml){
				NS.DOM.write(panel, $(xml).find('response').text());
				self.close();
			});
		}
	}));

	/**
	 * The POI Stores dialog requests a list of locations associated with the 
	 * current advice, and enables searching them for different points of interest.
	 */
	NS.Dialogs.register('poistores', NS.Class.extend(
		POIDialog,
		function(){
			this.content = $('#poi-stores');
			NS.relateLink(/poi-location/, this.handleClick.bind(this));
		}, {
			
		// temp overwrite to provide links with rel attributes.
		// this should be removed in favor of a server side solution
		write:function() {
			NS.Dialog.prototype.write.apply(this, arguments);
			this.content.find('li a').attr('rel', 'poi-location');
		},
		
		handleClick:function(link, rel) {
			var pois = NS.getApplication('pois');
			if(pois) {
				var panel = pois.findPanel(this.origin);
				pois.updatePOIPanel(panel, link.href);
				this.close();
			}
			
			return true;
		}
	}));

	
	/**
	 * bind to NS.initialize
	 */
	NS.subscribe('initialize', function(){
		NS.addApplication('pois', new Pois());
	});

});
