/**
 * GMapManager v2
 * Changes
 * - Properties defined at the beggining of the class
 * - mapContainer renamed to canvas
 * - Fixed iconAnchor position (iconSize.x/2, iconSize.y)
 * - Added the activeWindow propertie to the GMap2 class
 * - This object is not longer passed to the InfoWindow
 * - Deleted default icon. Icons are now handled by the Icons class
 * - Deleted class propertie Bounds
 *
 * Required libraries:
 * - MarkerManager
 * - LabeledMarker
 * - InfoWindow
 * - ToolTip
 */

GMap2.prototype.activeInfoWindow = null;
var GMapManager = Class.create();

GMapManager.prototype = {
	
	canvas: null,
	markerManager: null,
	markers: new Array(),
	spots: new Hash(),
	routes: new Hash(),
	icon: null,
	
  initialize: function(canvas) {    
		this.canvas = canvas;
		this.map = new GMap2(canvas);
		this.map.setCenter(new GLatLng(0,0), 10);
		this.map.enableScrollWheelZoom();
		
		//Marker Manager
				   	
		var options = {trackMarkers: true};
		this.markerManager = new MarkerManager(this.map, options);
        
    this.map.activeInfoWindow = null;
    this.spots = new Hash();
    this.routes = new Hash();
    
		GEvent.addListener(this.map, "move", this.mapMoveEvent.bind(this));              
  },
  
  
  addSmallMapControl: function() {
    this.map.addControl(new GSmallMapControl());
  },

  addLargeMapControl: function() {
    this.map.addControl(new GLargeMapControl());
  },

  addGMapTypeControl: function() {
    this.map.addControl(new GMapTypeControl());
  },  
  
  addSpot: function(spot) {
  	this._setSpotEvents(spot);  	
  	this.spots[spot.id] = spot;
		
		this.map.setCenter(spot.marker.getLatLng());
  	this.markerManager.addMarker(spot.marker, 0);  	
  },
  
  addSpots: function(spots) {
		var length = spots.size();
		var markers = new Array();
		var bounds = new GLatLngBounds();
		
		for (var index = 0; index < length; ++index) {
		  var spot = spots[index];
			this._setSpotEvents(spot);			
			this.spots[spot.id] = spot;
			bounds.extend(spot.marker.getLatLng());
			markers.push(spot.marker);
		}
		
		this.focusArea(bounds);
		this.markerManager.addMarkers(markers, 0);
		this.markerManager.refresh();
  },
  
  addRoutes: function(routes) {
		var nRoutes = routes.size();
		var markers = new Array();
		var bounds = new GLatLngBounds();
				
		for (var x = 0; x < nRoutes; ++x) {
			route = routes[x];
			this.routes[route.id] = route;
			
			nSpots = route.spots.size();			
			for (var y = 0; y < nSpots; ++y) {
				spot = route.spots[y];
				this._setSpotEvents(spot);			
				this.spots[spot.id] = spot;
				bounds.extend(spot.point);
				markers.push(spot.marker);	    					
			}						
	    
	    if (route.path != null) {
				this.map.addOverlay(route.path);	    	
	    }	  	  				
		}
		
		this.focusArea(bounds);
		this.markerManager.addMarkers(markers, 0);
		this.markerManager.refresh();
  },
  
  drawRoutes: function(categories) {		
    this.map.clearOverlays();
    categories = categories == null ? new Array() : categories;
    
    var route = null;
    var spot = null;
    var bounds = new GLatLngBounds();    
    var markers = new Array();
    var nCategories = categories.size();
   
		this.routes.each((function(pair) {			
			route = pair.value;
			nSpots = route.spots.size();
			
    	for (var index = 0; index < nCategories; index++) {
    		category = categories[index];
    		if (category == route.category) {					
					for (var x = 0; x < nSpots; ++x) {
						spot = this.spots[route.spots[x].id];
						bounds.extend(spot.point);
						markers.push(spot.marker);	    					
					}						
			    
			    if (route.path != null) {
						this.map.addOverlay(route.path);	    	
			    }			    			    			
    		}
    	}						
		}).bind(this));                
    
    this.focusArea(bounds);
    this.markerManager.clearMarkers();    
    this.markerManager.addMarkers(markers, 0);
    this.markerManager.refresh();		
  },    
  
  focusSpot: function(id) {
  	var spot = this.spots[id];
  	
  	if (spot != null) {
			this.map.setCenter(spot.point); 
			GEvent.trigger(spot.marker, 'click');
  	}  	
  },
  
  focusArea: function(bounds) {
    this.map.setZoom(this.map.getBoundsZoomLevel(bounds) - 1);
    this.map.setCenter(bounds.getCenter());  	
  },
  
  zoom: function(zoom) {
  	this.map.setZoom(this.map.getZoom() + zoom);
  },    
  
  drawSpots: function(categories) {
    categories = categories == null ? new Array() : categories;
    
    var spot = null;
    var bounds = new GLatLngBounds();    
    var markers = new Array();
    var length = categories.size();    
        
    this.spots.each(function(pair) {
    	spot = pair.value;    	    	
    	for (var index = 0; index < length; index++) {
    		category = categories[index];
    		if (category == spot.category) {
    			markers.push(spot.marker);
    			bounds.extend(spot.point);
    		}
    	}
    });
    
    this.focusArea(bounds);
    this.markerManager.clearMarkers();    
    this.markerManager.addMarkers(markers, 0);
    this.markerManager.refresh();    	        
  },
  
  drawAllSpots: function() {    
    var bounds = new GLatLngBounds();    
    var markers = new Array();
    
    this.spots.each(function(pair){
    	markers.push(pair.value.marker);
    	bounds.extend(pair.value.marker.getLatLng());
    });
    
    this.focusArea(bounds);
    this.markerManager.clearMarkers();        
    this.markerManager.addMarkers(markers, 0);
    this.markerManager.refresh();    	        
  },      
  
  /**
   * Private
   */
	
	_setSpotEvents: function(spot) {
		if (spot.tooltip != null) {
	    GEvent.addListener(spot.marker, "mouseover", this.markerMouseOverEvent.bind(this, spot.tooltip));    
	    GEvent.addListener(spot.marker, "mouseout", this.markerMouseOutEvent.bind(this, spot.tooltip));			
		}		
		if (spot.window != null) {
    	GEvent.addListener(spot.marker, "click", this.markerClickEvent.bind(this, spot.window));
    }    		
	},	   
  
  isMarkerVisible: function(marker) {
  	icon = $(marker.div_).previous();
  	map = $(this.canvas);
  		  
		//Element and container (X,Y) position
		var iPos = Position.cumulativeOffset(icon);
		var cPos = Position.cumulativeOffset(map);
		
		//Element and container width and height
		
		var iDim = icon.getDimensions();
		var cDim = map.getDimensions();		

		//Verify if the element is inside the container by analizing the borders		
		var top = (iPos[1] < cPos[1]);
		var right = (iPos[0] + iDim.width  > cPos[0] + cDim.width );
		var bottom = (iPos[1] + iDim.height > cPos[1] + cDim.height);
		var left = (iPos[0] < cPos[0]);

		if(top || right || bottom || left)
		{
			return false;
		}
		
		return true;			  
     	
  },
  
  closeActiveWindow: function() {
    if (this.map.activeInfoWindow != null) {
    	this.map.removeOverlay(this.map.activeInfoWindow);
    	this.map.activeInfoWindow = null;
    }  	
  },      


  /**
   * Events Handlers
   */ 

  mapMoveEvent: function() {
    if (this.map.activeInfoWindow != null) {
      if (this.isMarkerVisible(this.map.activeInfoWindow.marker_)) {
      	this.map.activeInfoWindow.redraw(true);
      } else {
      	this.closeActiveWindow();
      }       	
    }
  },  

  markerClickEvent: function(infoWindow) {
    this.closeActiveWindow();
    this.map.addOverlay(infoWindow);
    this.map.activeInfoWindow = infoWindow;
  },

  markerMouseOverEvent: function(tooltip) {
    this.map.addOverlay(tooltip);
  },

  markerMouseOutEvent: function(tooltip) {
    this.map.removeOverlay(tooltip);
  }
};
 
