
var ps = {};
ps.mapping = {};

/*
*	ps.mapping.MapView
*	
*	Events: 
*/
ps.mapping.MapView = new Class({

	gmap : null,
	marker_manager: null,
	connector : null,

	infowindow : null,
	iconfactory : null,

	initialize : function(map_element, marker_manager, connector)
	{
		this.infowindow = new ps.mapping.infowindow.DefaultInfoWindow(this);
		this.iconfactory = new ps.mapping.DefaultIconFactory(this);
		
		map_element = $(map_element);
		
		this.gmap = new GMap2(map_element);
	
		//this.gmap.enableGoogleBar();
		this.gmap.setCenter(new GLatLng(0,0), 1);
		
		this.gmap.addMapType(G_PHYSICAL_MAP);
		
		this.marker_manager = marker_manager;
		this.marker_manager.setMapView(this);
		
		this.connector = connector;
		this.connector.setMapView(this);
		//var ads = new GAdsManager(this.gmap, 'ca-pub-3742318957108929');
		//ads.enable();
	
		this.updateMarkers();
		
		GEvent.addListener(this.gmap, 'dragend', this.moveEnd.bind(this));
		GEvent.addListener(this.gmap, 'zoomend', this.zoomEnd.bind(this));
		
	},
	
	getGMap : function()
	{
		return this.gmap;
	},
	
	getConnector : function()
	{
		return this.connector;
	},
	
	getMarkerManager : function()
	{
		return this.marker_manager;
	},
	
	updateMarkers : function()
	{
		this.getMarkerManager().setItems(this.getConnector().getItems());
	},
	
	closePopup : function()
	{
		this.getGMap().closeInfoWindow();
	},
	
	getInfoWindow : function()
	{
		return this.infowindow;
	},
	
	setInfoWindow : function(infowindow)
	{
		this.infowindow = infowindow;
	},
	
	getIconFactory : function()
	{
		return this.iconfactory;
	},
	
	setIconFactory : function(iconfactory)
	{
		this.iconfactory = iconfactory;
	},
	
	zoomToItem : function(item)
	{
		var latlng = new GLatLng(item.lat, item.lng);
		var zoom = this.getGMap().getZoom();
		
		zoom = Math.min(this.getGMap().getCurrentMapType().getMaximumResolution()-2, zoom+4);
		
		this.getGMap().setCenter(latlng, zoom);
	},
	
	zoomFromItem : function(item)
	{
		var latlng = new GLatLng(item.lat, item.lng);
		var zoom = this.getGMap().getZoom();
		
		zoom = Math.max(this.getGMap().getCurrentMapType().getMinimumResolution(), zoom-4);
		
		this.getGMap().setCenter(latlng, zoom);
	},
	
	
	zoomEnd : function(old_zoom, new_zoom)
	{
		this.fireEvent('zoomEnd', [old_zoom, new_zoom]);
	},
	
	moveEnd : function()
	{
		this.fireEvent('moveEnd', this.getGMap().getCenter());
	}
	
});
ps.mapping.MapView.implement(new Events);


ps.mapping.MarkerManager = new Class({
	
	options : {
		max_markers : 200
	},
	
	markers : [],
	items : [],
	map_view : null,
	
	filter : function(item, marker, bounds)
	{
		//item.is_visible = bounds.containsLatLng(marker.getLatLng());
		//item.is_hidden = false;
		return true;
	},
	
	//icon_manager : null,
	
	initialize : function()
	{
		//this.icon_manager = new ps.mapping.DefaultIconFactory();
	
	},
	
	setMapView : function(mv)
	{
		this.map_view = mv;
		this.createMarkers();
		
		var gmap = this.getMapView().getGMap();
	
		mv.addEvent('moveEnd', this.checkBounds.bind(this));
		mv.addEvent('zoomEnd', this.checkBounds.bind(this));
		
		//GEvent.addListener(gmap, 'dragend', this.checkBounds.bind(this));
	},
	
	getMapView : function()
	{
		return this.map_view;
	},
	
	createMarkers : function()
	{
		
		var icon_manager = this.map_view.getIconFactory();
		var icon = icon_manager.getBaseMarkerIcon();
		
		var gmap = this.getMapView().getGMap();
		this.markers = [];
		
		for (var i=0; i < this.options.max_markers; i++)
		{
			var marker = new mapsack.mapping.markers.MultiMarker(new GLatLng(0,0), {'icon' : icon, 'title' : 'Hello world'});
			//var marker = new GMarker(new GLatLng(0,0));
			marker._id = null;
			marker._mm = this;
			marker._hilight = false;
			this.markers[i] = marker;
		
			GEvent.addListener(marker, 'click', function(){

				this._mm.openInfoWindowById(this._id);
				
			});
			
			GEvent.addListener(marker, 'mouseover', function(){

				this._mm.hilightMarkerById(this._id);
				
			});
			
			GEvent.addListener(marker, 'mouseout', function(){

				this._mm.dehilightMarkerById(this._id);
				
			});
			
			gmap.addOverlay(marker);	
		}
	},
	
	setItems : function(items)
	{
		this.items = items;
		var max_markers = this.options.max_markers;
		var n_items = Math.min(items.length, max_markers);
		var bounds = this.getMapView().getGMap().getBounds();
		
		var icon_manager = this.map_view.getIconFactory();
		
		for (var i=0; i< n_items; i++)
		{
			var item = items[i];
			var marker = this.markers[i];
			
			var latlng = new GLatLng(item.lat, item.lng);
			item.is_visible = bounds.containsLatLng(latlng);
			item.is_hidden = false;
			
			icon_manager.setMarkerIcon(marker, item);
			marker.setTitle(item.title);
			marker.setPoint(latlng);
			marker._id = item.id; 
			marker.show();
		}
		
		for (var i=n_items; i< max_markers; i++)
		{
			this.markers[i].hide();
		}
		
		this.fireEvent('itemsUpdated');
		
	},
	
	filterAllItems : function()
	{
		var items = this.items;
		var bounds = this.getMapView().getGMap().getBounds();
		var n_items = Math.min(items.length, this.markers.length);
		
		for (var i=0; i< n_items; i++)
		{
			items[i].is_hidden = !this.filter(items[i], this.markers[i], bounds);
			//this.filter(items[i], this.markers[i], bounds);
			if (items[i].is_hidden) this.markers[i].hide(); else this.markers[i].show();
			items[i].is_visible = (!items[i].is_hidden) && bounds.containsLatLng(this.markers[i].getLatLng());
			
		}
		
		this.fireEvent('itemsUpdated');
	},
	
	checkBounds : function()
	{
		var items = this.items;
		var bounds = this.getMapView().getGMap().getBounds();
		var n_items = Math.min(items.length, this.markers.length);
		
		for (var i=0; i< n_items; i++)
		{
			items[i].is_visible = (!items[i].is_hidden) && bounds.containsLatLng(this.markers[i].getLatLng());
			//this.filter(items[i], this.markers[i], bounds);
			//if (items[i].is_hidden) this.markers[i].hide(); else this.markers[i].show();
		}
		
		this.fireEvent('itemsUpdated');
	},

	
	getItems : function()
	{
		return this.items;
	},
	
	addItem : function(item)
	{
		this.items.push(item);
		this.setItems(this.items); //Hack for now
	},
	
	updateItem : function(id, item)
	{
		var index = -1;
		for (var i = this.items.length-1;i>=0;i--)
		{
			if (this.items[i].id == id) index = i;
		}
		
		if (index == -1) return;
		
		this.items[index] = item;
		this.setItems(this.items); //Hack for now
	},
	
	updateAllItems : function()
	{
		this.setItems(this.items); //Hack for now
	},
	
	removeItem : function(id)
	{
		var item = this.getItemById(id);
		
		if (item) 
		{
			this.items.remove(item);
			this.setItems(this.items); //Hack for now
		}
	},
	
	getMarkerById : function(id)
	{
		for (var i = this.markers.length-1;i>=0;i--)
		{
			if (this.markers[i]._id == id) return this.markers[i];
		}
		
		return null;
	},
	
	getItemById : function(id)
	{
		for (var i = this.items.length-1;i>=0;i--)
		{
			if (this.items[i].id == id) return this.items[i];
		}
		
		return null;
	},
	
	openInfoWindowById : function(id)
	{
	
		//var info = new ps.mapping.infowindow.DefaultInfoWindow(this.getItemById(id), this.getMarkerById(id), this.map_view);
		var item = this.getItemById(id);
		var marker = this.getMarkerById(id);
		
		this.map_view.getInfoWindow().show(item, marker);
	},
	
	hlightMarkersByFilter : function(filter)
	{
		var max_markers = this.markers.length;
		var nitems = Math.min(this.items.length, max_markers);
		
		for (var i=0; i<nitems;i++)
		{
			var item = this.items[i];
			var marker = this.markers[i];
			
			if (filter(item, marker)) marker.hilight();
		}
		
	},
	
	hilightMarkerById : function(id)
	{
		var marker = this.getMarkerById(id);
		
		if (marker) marker.hilight();
		
		this.fireEvent('markerHover', id);
		
	},
	
	dehilightMarkerById : function(id)
	{
		var marker = this.getMarkerById(id);
		
		if (marker) marker.dehilight();
		
		this.fireEvent('markerDeHover', id);
	},
	
	dehilightAllMarkers : function()
	{
		for (var i = this.markers.length-1;i>=0;i--)
		{
			var marker = this.markers[i];
			marker.dehilight()
		}
	},
	
	computeBounds : function()
	{
		if (this.markers.length ==0) return null;
		
		var max_markers = this.markers.length;
		var nitems = Math.min(this.items.length, max_markers);
		
		var bounds = new GLatLngBounds(this.markers[0].getLatLng(), this.markers[0].getLatLng());
		
		for(var i=0; i<nitems; i++)
		{
			bounds.extend(this.markers[i].getLatLng());
		}
		
		return bounds;
	}
	
});
ps.mapping.MarkerManager.implement(new Events());

ps.mapping.connector = {};

ps.mapping.connector.StaticConnector = new Class({
	
	items : [],
	map_view : null,
	
	initialize : function(items)
	{
		this.items = items;
	},
	
	setMapView : function(mv)
	{
		this.map_view = mv;
	},
	
	getMapView : function()
	{
		return this.map_view;
	},
	
	getItems : function()
	{
		return this.items;
	}
	
});


ps.mapping.infowindow = {};

ps.mapping.infowindow.DefaultInfoWindow = new Class({
	
	map_view : null,
	
	initialize : function(map_view)
	{
		this.map_view = map_view;
	},
	
	show : function(item, marker)
	{
		
		var html = 	'<b>'+item.title+'</b>';

		this.map_view.getGMap().openInfoWindowHtml(marker.getPoint(), html);
		
	},
	
	hide : function()
	{
		this.map_view.getGMap().closeInfoWindow();
	}
	
});

ps.mapping.DefaultIconFactory = new Class({
	
	
	setMarkerIcon : function(marker, item)
	{

	},
	
	getBaseMarkerIcon : function()
	{
		return G_DEFAULT_ICON;
	}
	
});