// All URooms search code goes here because it's too big to put anywhere else.


URooms.Search.Context = Class.extend({

	init : function() {
		this._viewHandlers = {
			"map" : new URooms.Search.MapViewHandler(this, $("#searchResultView .map").first()),
			"list" : new URooms.Search.ListViewHandler(this, $("#searchResultView .list").first()),
			"grid" : new URooms.Search.GridViewHandler(this, $("#searchResultView .grid").first()),
			"ambig" : new URooms.Search.AmbiguityViewHandler(this, $("#searchResultView .ambig").first())
		};
		this._currViewHandler = undefined;
		this._currentBounds = undefined;
		this._currentLocationDesc = "";
		this._priceSlider = undefined;
	},

	setCurrentLocationDesc: function(val) { this._currentLocationDesc = val; },
	getCurrentLocationDesc: function() { return this._currentLocationDesc; },

	setCurrentBounds: function(bounds) { this._currentBounds = bounds; },
	getCurrentBounds: function() { return this._currentBounds; },

	setPriceSlider: function(slider) { this._priceSlider = slider; },
	getPriceSlider: function() { return this._priceSlider; },

	getCurrentViewHandler: function() {
		return this._currViewHandler;
	},

	getSearchFormValues: function() {
		var retval = {};
		//var searchForm = $("#searchForm");
		var sliderVals = this.getSliderVals();
		$(".ajaxSearch").each(function(){
			var name = $(this).attr("name");
			if(name) retval[name] = $(this).val();
		});
		return $.extend({}, retval, {
			priceLow: sliderVals.low,
			priceHigh: sliderVals.high,
			pageSize: 100
		});
	},

	setSearchFormValues: function(values) {
		$(".ajaxSearch").each(function(){
			var name = $(this).attr("name");
			if(name && values[name]) $(this).val(values[name]);
		});
		this.setSliderVals(values.priceLow, values.priceHigh);
		var lettingTypeVal = $('#searchLettingType').val().toLowerCase();
		if (lettingTypeVal == 'room')
		{
			$("#propertyTypeOptions").hide();
			$("#roomTypeOptions").show();
		}
		else if (lettingTypeVal == 'property')
		{
			$("#roomTypeOptions").hide();
			$("#propertyTypeOptions").show();
		}
		else
		{
			$("#roomTypeOptions").hide();
			$("#propertyTypeOptions").hide();
		}
	},

	getSliderVals: function() {
		var pslider1 = this._priceSlider.slider("values", 0);
		var pslider2 = this._priceSlider.slider("values", 1);
		return {
			low: Math.min(pslider1,pslider2),
			high: Math.max(pslider1, pslider2)
		};
	},

	setSliderVals: function(low,high) {
		$.log("Setting slider values to ["+low+","+high+"]");
		this._priceSlider.slider("values", 0, [low]);
		this._priceSlider.slider("values", 1, [high]);
	},

	refreshCurrentView: function(eventsource, extradata) {
		if(this.getCurrentViewHandler()) {
			$.log("Refreshing current view, which is "+this.getCurrentViewHandler().getName());
			this.getCurrentViewHandler().refresh(eventsource, extradata);
		}
	},

	switchTo: function(to, eventsource, data) {
		$.log("Switching view to "+to);
		var targetViewHandler = this._viewHandlers[to];
		if(targetViewHandler) {
			targetViewHandler.refresh(eventsource, {}, data);
			this._currViewHandler = targetViewHandler;

			$.each(this._viewHandlers, function(key,val){
				if(val==targetViewHandler) {
					val.show();
				} else {
					val.hide();
				}
			});
		} else {
			$.log("Failed to switch view to '"+to+"'");
		}
	},

	resultsAreAmbiguous: function(data) {
		$.log("Results are ambiguous, displaying disambiguation thing");
		this.switchTo("ambig", "ambigdata", data);
	}
});


URooms.Search.BaseViewHandler = Class.extend({
	init: function(context, element) {
		this._context = context;
		this._element = element;
	},
	getName: function() {
		return "BaseViewHandler";
	},
	refresh: function(eventsource, extradata) {

	},
	setLocationDesc: function(data) {
		if(data.locationDesc) {
			this._context.setCurrentLocationDesc(data.locationDesc);
		}
	},
	getLocationDesc: function() {
		return this._context.getCurrentLocationDesc();
	},
	getSearchFormValues: function() {
		return this._context.getSearchFormValues();
	},
	getCurrentBounds: function() {
		return this._context.getCurrentBounds();
	},
	setCurrentBounds: function(bounds) {
		this._context.setCurrentBounds(bounds);
	},
	checkForAmbiguous: function(data) {
		$.log("Checking search data for ambiguous locations");
		if(data.areaAmbiguities && data.areaAmbiguities.length>0) {
			this._context.resultsAreAmbiguous(data);
			return true;
		}
		return false;
	},
	show: function() {
		if(this._element) this._element.show();
	},
	hide: function() {
		if(this._element) this._element.hide();
	},
	persistQueryMemento: function(formValues) {
		$.log("persistQueryMemento");
		$.cookies.set('ur-search-memento', formValues);
	}
});


/**
 * Map view handler, looks after managing and refreshing the map view
 */
URooms.Search.MapViewHandler = URooms.Search.BaseViewHandler.extend({
	init: function(context, element) {
		this._super(context, element);
		this.mapNeedsInit = true;
		this.mapmanager = undefined;
	},
	initMap: function(target) {
		if(this.mapNeedsInit) {
			this.mapNeedsInit = false;
			$.log("Initialising map");
			var myOptions = {
				zoom: 5,
				mapTypeId: google.maps.MapTypeId.ROADMAP
			};
			var gMap = new google.maps.Map(target ? target : document.getElementById("resultMap"), myOptions);
			this.mapmanager = new URooms.Search.MapManager(gMap, this);
			this.mapmanager.registerListeners();
			$("body").unload(function(){ GUnload(); });
		}
	},
	getName: function() {
		return "MapViewHandler";
	},
	refresh: function(eventsource, extradata) {
		this._super(eventsource, extradata);
		$.log("Refreshing map view");

		var resetLocation = (eventsource=="initialsearch" || !this.getCurrentBounds());
		var formvalues = $.extend({}, this.getSearchFormValues(), ( resetLocation ? {} : this.getCurrentBounds() ), {
			eventSource: eventsource,
			includePoi: true,
			allowExpand: (eventsource && eventsource=="initialsearch"),
			mapView: true,
			hasUpgrade: "*"
		});

		var self = this;
		URooms.Ajax.json("/search/usersearch.json", formvalues,function(data, textStatus){
			self.setLocationDesc(data);
			if (!self.checkForAmbiguous(data))
			{
				var oldBounds = self.getCurrentBounds();
				if (data.box) {
					self.setCurrentBounds({ fixedSearchArea: {
						south: data.box.south,
						west: data.box.west,
						north: data.box.north,
						east: data.box.east
					}});
				}
				var newBounds = self.getCurrentBounds();
				var boundsChanged = (newBounds && oldBounds && (newBounds.fixedSearchArea.north!=oldBounds.fixedSearchArea.north || newBounds.fixedSearchArea.south!=oldBounds.fixedSearchArea.south || newBounds.fixedSearchArea.east!=oldBounds.fixedSearchArea.east || newBounds.fixedSearchArea.west!=oldBounds.fixedSearchArea.west));
				$("#searchProximity").val("");
				self.persistQueryMemento(formvalues);

				var mapNeedsRelocating = self.mapNeedsInit || resetLocation || boundsChanged;
				if(self.mapNeedsInit) {
					self.initMap();
				}

				// Only recenter the map if the user didn't actually move it themselves
				if(mapNeedsRelocating)
				{
					$.log("Map needs moving, do that");
					// Can use google to do zoom calculation
					self.mapmanager.moveMapTo(data.box);
				}
				else
				{
					$.log("Map does not need moving", data.eventSource, data.box);
				}

				$(".searchResultCount").text(data.resultCount);
				$(".currentSearchLocation").text(self.getLocationDesc());
				$(".searchLocationTerms").val("");

				var batch = {};

				// Generate listing markers
				$.each(data["results"], function(k,v){
					batch[v.id]=URooms.GMaps.createListingMarker(v);
				});

				// Generate POI markers
				$.each(data.pointsOfInterest, function(k,v){
					batch["POI_"+v.id]=URooms.GMaps.createPoiMarker(v);
				});

				self.mapmanager.addMarkers(batch);
			}
		});
	}
});

URooms.Search.AmbiguityViewHandler = URooms.Search.BaseViewHandler.extend({
	getName: function() {
		return "AmbiguityViewHandler";
	},
	refresh: function(eventsource, extradata, data) {
		this._super(eventsource, extradata);
		if(data) {
			$("#searchResultView .ambigOptions").html(ambiguous_areas_template(data));
		}
	}
});

URooms.Search.ListViewHandler = URooms.Search.BaseViewHandler.extend({
	getName: function() {
		return "ListViewHandler";
	},
	refresh: function(eventsource, extradata) {
		this._super(eventsource, extradata);
		$.log("Refresh the list view");
		var resetLocation = (eventsource=="initialsearch" || !this.getCurrentBounds());
		var formvalues = $.extend({}, extradata, this.getSearchFormValues(), ( resetLocation ? {} : this.getCurrentBounds() ), {
			eventSource: eventsource,
			pageSize: 9,
			allowExpand: (eventsource && eventsource=="initialsearch"),
			hasUpgrade: "*"
		});

		var self = this;
		URooms.Ajax.json("/search/usersearch.json", formvalues, function(data, textStatus){
			self.setLocationDesc(data);
			if (!self.checkForAmbiguous(data))
			{
				if (data.box) {
					self.setCurrentBounds({ fixedSearchArea: {
						south: data.box.south,
						west: data.box.west,
						north: data.box.north,
						east: data.box.east
					}});
				}
				self.persistQueryMemento(formvalues);

				$("#searchResultView .listStandardResults").html(list_view_template(data));
				bindToAddToFavourites();
				$("#searchResultView .listHeaderResults").html(search_header_template(data));
				document.title = 'Flats, houses and rooms to rent in ' + searchContext.getCurrentLocationDesc();
			}
		});

		var featuredFormValues = $.extend({}, formvalues, {hasUpgrade: "FeaturedListing", page: 1, pageSize: 100 });
		URooms.Ajax.json("/search/featuredListingSearch.json", featuredFormValues, function(data, textStatus){
			var markup = grid_view_featured_template(data);
			$(".list .searchFeaturedListings .clip").html(markup);
			jQuery(".superslider").sliderkit();
		});
	}
});


URooms.Search.GridViewHandler = URooms.Search.BaseViewHandler.extend({
	getName: function() {
		return "GridViewHandler";
	},
	refresh: function(eventsource, extradata) {
		this._super(eventsource, extradata);
		var resetLocation = (eventsource=="initialsearch" || !this.getCurrentBounds());
		var formvalues = $.extend({}, extradata, this.getSearchFormValues(), ( resetLocation ? {} : this.getCurrentBounds() ), {
			eventSource: eventsource,
			pageSize: 9,
			allowExpand: (eventsource && eventsource=="initialsearch"),
			hasUpgrade: "*"
		});

		var self = this;
		URooms.Ajax.json("/search/usersearch.json", formvalues, function(data, textStatus){
			self.setLocationDesc(data);
			if (!self.checkForAmbiguous(data))
			{
				if (data.box) {
					self.setCurrentBounds({ fixedSearchArea: {
						south: data.box.south,
						west: data.box.west,
						north: data.box.north,
						east: data.box.east
					}});
				}
				self.persistQueryMemento(formvalues);

				$.log(data);

				var markup = grid_view_template(data);
				$("#searchResultView .gridStandardResults").html(markup);
				bindToAddToFavourites();
				$("#searchResultView .gridHeaderResults").html(search_header_template(data));
				document.title = 'Flats, houses and rooms to rent in ' + searchContext.getCurrentLocationDesc();
                $(".searchLocationName").val(searchContext.getCurrentLocationDesc());
			}
		});


		var featuredFormValues = $.extend({}, formvalues, {hasUpgrade: "FeaturedListing", page: 1, pageSize: 100});
		URooms.Ajax.json("/search/featuredListingSearch.json", featuredFormValues, function(data, textStatus){
			var markup = grid_view_featured_template(data);
			$(".grid .searchFeaturedListings .clip").html(markup);
			jQuery(".superslider").sliderkit();
		});
	}
});


URooms.Search.MapManager = Class.extend({
	init: function(map, mapviewhandler) {
		this._map = map;
		this._mapviewhandler = mapviewhandler;
		this._activeMarkers = {};
		this._lastMapBounds = undefined;

		var self = this;
		google.maps.event.addListener(this._map, 'idle', function() {
			self.handleMapMoved.apply(self, arguments);
		});
	},
	registerListeners: function() {

	},
	getMap: function() { return this._map; },

	/* Gets called with "this" redefined in gmaps */
	handleMapMoved: function() {
		var bounds = this._map.getBounds();

		// During init the map is centered, which makes it fire a mapmoved event.
		// This causes a second search to be triggered.  To avoid this we track to see if *we* think it moved from the last time we requeried.
		if(this._lastMapBounds && bounds && !this._lastMapBounds.equals(bounds)){
			this.saveCurrentBounds(bounds);
			this._mapviewhandler.refresh("mapmoved");
		}
	},
	addMarkers: function(newMarkers) {
		var self = this;
		var result = {};
		$.log("Refreshing markers");

		var removed = 0;
		var added = 0;
		var retained = 0;
		$.each(self._activeMarkers, function(k,v) {
			if(!newMarkers[k]) {
				v.setMap(null);
				removed++;
			} else {
				result[k]=v;
				retained++;
			}
		});

		$.each(newMarkers, function(k,v){
			if(!self._activeMarkers[k]) {
				v.setMap(self._map);
				result[k]=v;
				added++;
			}
		});

		$.log("Markers refreshed: "+added+" added, "+removed+" removed, "+retained+" retained");
		this._activeMarkers = result;
	},
	saveCurrentBounds: function(bounds){
		this._lastMapBounds = bounds;

		var sw = bounds.getSouthWest();
		var ne = bounds.getNorthEast();
		this._mapviewhandler.setCurrentBounds({ fixedSearchArea: {
			south: sw.lat(),
			west: sw.lng(),
			north: ne.lat(),
			east: ne.lng()
		}});
	},
	moveMapTo: function(box) {
		$.log("Moving map to ", box);
		var centerPoint = undefined;
		var gbounds = undefined;

		if (box)
		{
			centerPoint = new google.maps.LatLng(box.centre.lat,box.centre.lng);
			gbounds = new google.maps.LatLngBounds(new google.maps.LatLng(box.south, box.west), new google.maps.LatLng(box.north, box.east));
		}
		else
		{
			// default to a map setting of the whole UK
			//lat//52.8226825580693
			//long//-1.307373046875
			centerPoint = new google.maps.LatLng('52.8226825580693','-1.307373046875');
			gbounds = new google.maps.LatLngBounds(new google.maps.LatLng('50.00773901463687', '-7.5146484375'), new google.maps.LatLng('58.859223547066584', '1.0107421875'));
		}
		// Work out the zoom level
		
		this._map.fitBounds(gbounds);
		this._map.setCenter(gbounds.getCenter());

		$.log("save new map bounds");
		this.saveCurrentBounds(gbounds);

	}
});
