/**
 * Webbase Map Manager
 * Requires following libraries: Ajax, default, json, notifier
 *
 */

var MapManager = function()
{
	this.maps = new Object();
	
	this.setMap = function(mapref, map)
	{
		this.maps[mapref] = map;
	}
	
	this.getMap = function(mapref)
	{
		return this.maps[mapref];
	}
	
	/**
	 * Loop through all registered maps, and initialise them
	 */
	this.initMaps = function()
	{
		//Make sure Google Maps GBrowserIsCompatible() function exists before we try to init.
		if(window.GBrowserIsCompatible)
		{
			for(var mapkey in this.maps)
			{
				this.maps[mapkey].init();
			}
		}
		else
		{
			//alert('Google Maps failed to load!');
			for(var mapkey in this.maps)
			{
				this.maps[mapkey].drawDisabledState();
			}
		}
	}
	/**
	 * Loop through all registered maps, and clear their info window caches
	 */
	this.clearCache = function()
	{
		for(var mapkey in this.maps)
		{
			this.maps[mapkey].setInfoWindowCache(new Object());
		}
	}
}
//MapManager.prototype = new DomModel();

var Map = function()
{
	var ref = this;//internal reference
	this.map; //google map object
	
	//map constants - avoid using actual equivalent google map constants, 
	//to prevent problems if there is a delay downloading the external javascript
	this.G_PHYSICAL_MAP = "G_PHYSICAL_MAP";
	this.G_HYBRID_MAP = "G_HYBRID_MAP";
	this.G_NORMAL_MAP = "G_NORMAL_MAP";
	this.G_SATELLITE_MAP = "G_SATELLITE_MAP";
	
	//Size to open the info window
	this.INFOSIZE_NORMAL = 'normal';
	this.INFOSIZE_MAX = 'max';
	
	
	this.zoom = 10;
	this.center = { 'lat':1, 'lng':1 };
	this.infoAPI = false;
	this.infoSize = this.INFOSIZE_NORMAL; //default to opening info window at normal size
	this.type = this.G_NORMAL_MAP;
	this.root = 'map';
	this.currentFetchID = 0; //the ID of the item info being fetch, used to prevent problems when frantically clicking on lots of markers
	this.disabledBody = ''; //HTML string to display inside the map container if the map fails to load
	this.googleBar = false;
	
	//before init, markers should be set up with "Lat" and "Lng"
	/* var singlemarker = {
				'Lat':Latitude coordinate, //needs to be present before this.init() is called
				'Lng':Longitude coordinate, //needs to be present before this.init() is called
				'LatLng':GLatLng, //google maps coordinate object, created by this.init()
				'Marker':GMarker, //google maps marker object, created by this.init()
				}*/
	this.markers = new Object();
	
	//Info cache for HTML to display on map info windows. Pre-populate 
	this.infoWindowCache = new Object();
  
	this.setZoom = function(zoom){ this.zoom = zoom; }
	this.getZoom = function(){ return this.zoom; }
	this.setCenter = function(center){ this.center = center; }
	this.getCenter = function(){ return this.center; }
	this.setInfoAPI = function(infoAPI){ this.infoAPI = infoAPI; }
	this.getInfoAPI = function(){ return this.infoAPI; }
	this.setInfoSize = function(infoSize){ this.infoSize = infoSize; }
	this.getInfoSize = function(){ return this.infoSize; }
	this.setType = function(type){ this.type = type; }
	this.getType = function(){ return this.type; }
	this.setRoot = function(root){ this.root = root; }
	this.getRoot = function(){ return this.root; }
	this.setDisabledBody = function(disabledBody){ this.disabledBody = disabledBody; }
	this.getDisabledBody = function(){ return this.disabledBody; }
	this.setInfoWindowCache = function(infoWindowCache){ this.infoWindowCache = infoWindowCache; }
	this.getInfoWindowCache = function(){ return this.infoWindowCache; }
	this.setMarkers = function(markers){ this.markers = markers; }
	this.getMarkers = function() { return this.markers; }
	this.enableGoogleBar = function() { this.googleBar = true; }
	this.hasGoogleBar = function() { return this.googleBar; }
	
  this.tooltip = document.createElement("div");

	/**
	 * Set a marker with a particular reference
	 */
	this.setMarkerInfo = function(markerref, marker)
	{
		this.markers[markerref] = marker;
	}
	/**
	 * Get a marker against a particular reference
	 */
	this.getMarkerInfo = function(markerref, marker)
	{
		return this.markers[markerref];
	}
	
	/**
	 * Open a info window against a particular marker
	 */
	this.openInfoWindow = function(itemID)
	{
		var dom_info = document.createElement('div');
		dom_info.innerHTML = this.infoWindowCache[itemID];
		var options = [];
		var enableMaximise = false;
		
		if(this.infoWindowCache[itemID]['maxContent'])
		{
			options['maxContent'] = this.infoWindowCache[itemID]['maxContent'];
			enableMaximise = true;
			//if a title has been specified (to show on maximised info window)
			if(this.infoWindowCache[itemID]['title'])
			{
				options['maxTitle'] = this.infoWindowCache[itemID]['title'];
			}
			//if we have content for the maximised popup, ensure maximising is enabled
			this.map.getInfoWindow().enableMaximize();
		}
		
		//If opening info window at full size, maximise straight after the window opens.
		if(this.getInfoSize() == this.INFOSIZE_MAX)
		{
			//maximize() the infowindow after the 'infowindowopen' event
			var oninfowindowopen = function()
			{
				ref.map.getInfoWindow().maximize();
			}
			GEvent.addListener(this.map, 'infowindowopen', oninfowindowopen);
		}
		
		//open the info window
		this.map.openInfoWindow(this.markers[itemID]["LatLng"], this.infoWindowCache[itemID]['content'], options);
		
	}
	
	this.maximiseInfoWindow = function()
	{
		this.map.getInfoWindow().maximize();
	}
  
  this.showTooltip = function(itemID) 
  {
    if(this.markers[itemID]["tooltipON"] && this.markers[itemID]["tooltipON"]===true)
    {
      this.tooltip.innerHTML =this.markers[itemID]['title'];
    	var point=this.map.getCurrentMapType().getProjection().fromLatLngToPixel(this.map.getBounds().getSouthWest(),this.map.getZoom());
    	var offset=this.map.getCurrentMapType().getProjection().fromLatLngToPixel(this.markers[itemID]["Marker"].getPoint(),this.map.getZoom());

      var anchor=this.markers[itemID]["Marker"].getIcon().iconAnchor;
    	var width=this.markers[itemID]["Marker"].getIcon().iconSize.width;

      var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(offset.x - point.x - anchor.x + width,- offset.y + point.y +anchor.y)); 
    	pos.apply(this.tooltip);

    	this.tooltip.style.visibility="visible";
    }
  }
	/**
	 * Fetch content for a map info window (if not loaded already), then display the info window against a marker
	 */
	this.initInfoWindow = function(itemID, uniLatLng)
	{
		//API callback
		var onFetchInfo = function(info_innerHTML)
		{
			ref.infoWindowCache[itemID] = info_innerHTML;
			//ref.infoWindowCache[itemID] = "<h1>Uni ["+itemID+"] info</h1>";
			if(ref.currentFetchID != itemID) return false;
			//map.openInfoWindow(uniLatLng, document.createTextNode("Clicked marker "+itemID+"!"))
			ref.openInfoWindow(itemID);
		}
		
		//set the ID of the item we are fetching for
		this.currentFetchID = itemID;
		//If we CAN fetch from an AJAX API, *AND* we havnt already got the data we need, then request it
		if(this.infoAPI && !this.infoWindowCache[itemID])
		{
			var ticket = requestProcess.add(new Request('POST', this.infoAPI, 'itemID='+itemID, onFetchInfo, function(){}));
			//setTimeout(onFetchInfo, 1500);
		}
		else if(this.infoWindowCache[itemID])
		{
			this.openInfoWindow(itemID);
		}
		//else { //ERROR: we have nothing to put into the info window, so dont bother drawing it }
	}
  
	/***
	 * Initialize the Google Map based on current
	 *
	 */
	this.init = function()
	{
		if(GBrowserIsCompatible())
		{
			//Initialise the map
			this.map = new GMap2(document.getElementById(this.root));
			
			//Set the center coordinates
			this.map.setCenter(new GLatLng(this.center['lat'], this.center['lng']), this.zoom); //coords and zoom level
			
			//set map type
			var mapType;
			switch(this.type)
			{
				case this.G_PHYSICAL_MAP: mapType = G_PHYSICAL_MAP; break;
				case this.G_HYBRID_MAP: mapType = G_HYBRID_MAP; break;
				case this.G_SATELLITE_MAP: mapType = G_SATELLITE_MAP; break;
				case this.G_NORMAL_MAP:
				default:
				{
					mapType = G_NORMAL_MAP; break;
				}
			}
			this.map.setMapType(mapType);
			//add basic zoom controls
			this.map.addControl(new GSmallMapControl());

			// GoogleBar
			if(this.hasGoogleBar())
			{
				this.map.enableGoogleBar();
			}
      
      document.getElementById(this.root).appendChild(this.tooltip);
      this.tooltip.style.visibility="hidden";  
      this.tooltip.className = "tooltip";
      /*.tooltip {
                    background-color:#ffffff;
                    border:1px #ABABAB solid;
                    padding: 2px 4px 2px 4px;
                    }*/

			
			//Add ALL of the markers to the map
			for(var markerkey in this.markers)
			{
				//temporary object to handle the marker's onclick event
				var tmpMarkerClicker = function(mkkey, mkLatLng)
				{
					this.clickMarker = function()
					{
						ref.initInfoWindow(mkkey, mkLatLng);
						return false;
					}
          
          this.mouseoverMarker = function()
					{
						ref.showTooltip(mkkey);
						return false;
					}

          this.mouseoutMarker = function()
					{
            ref.tooltip.style.visibility="hidden";
						return false;
					}

				}
        
				//skip the markers that have lat and lng set to 0, this was done for open university.
        if(this.markers[markerkey]["Lat"]==0 || this.markers[markerkey]["Lng"]==0)
        {
          continue;
        }
        
				//set up a coordinate object from the supplied coords
				var point = new GLatLng(this.markers[markerkey]["Lat"], this.markers[markerkey]["Lng"]);
				this.markers[markerkey]["LatLng"] = point;
        //set up marker options, use a small icon image
				var iconRed = new GIcon(); 
				if(this.markers[markerkey]["image"])
				{
					iconRed.image = this.markers[markerkey]["image"];
				}
				else
				{
					iconRed.image = '/res/mm_20_red.png';
				}
				if(this.markers[markerkey]["shadow"])
				{
					iconRed.shadow = this.markers[markerkey]["shadow"];
				}
				else
				{
					iconRed.shadow = '/res/mm_20_shadow.png';
				}
				iconRed.iconSize = new GSize(12, 20);
				iconRed.shadowSize = new GSize(22, 20);
				iconRed.iconAnchor = new GPoint(6, 20);
				iconRed.infoWindowAnchor = new GPoint(5, 1);
        
        
        
				var markerOptions = { icon: iconRed };
				
				//If zIndex override is set, define a callback function to get the zIndex value and add to makerOptions
				if(this.markers[markerkey]["zIndex"])
				{
					var zIndexFunc = function(zIndex)
					{
						this.getZIndex = function()
						{
							return zIndex;
						}
					}
					var tmp = new zIndexFunc(this.markers[markerkey]["zIndex"]);
					markerOptions['zIndexProcess'] = tmp.getZIndex;
				}
				
				//store the marker object for later
				this.markers[markerkey]["Marker"] = new GMarker(point, markerOptions);

				var tmp = new tmpMarkerClicker(markerkey, point);
				//Add event listener for the marker
				GEvent.addListener(this.markers[markerkey]["Marker"], 'click', tmp.clickMarker);
        
        GEvent.addListener(this.markers[markerkey]["Marker"], "mouseover", tmp.mouseoverMarker); 

        GEvent.addListener(this.markers[markerkey]["Marker"], "mouseout", tmp.mouseoutMarker);

				//Add this marker to map
				this.map.addOverlay(this.markers[markerkey]["Marker"]);
			}
		}
	}
	
	
	/***
	 * Draw disabled state
	 *
	 */
	this.drawDisabledState = function()
	{
		document.getElementById(this.root).innerHTML = this.disabledBody;
	}
}
