/**
 * MediaMap.js
 * Description: this is the main js file for Geolive package. 
 * To create a geolive instance... 
 * 	1. create an html block 'home' for geolive
 * 	2. instantiate google. (after including the google js api) call google.load("maps", "2.x",{uncompressed:true});'); <- or similar 'uncompressed:true' does nothing... 
 * 	3. create a new MediaMap object (with your custom options)  
 * **note step 2 and 3 probably should/could be interchanged - it would be bad if the google onload event occurred before MediaMap instance tried to listed for it
 * 
 * Author: Nicholas Blackwell UBC-Okanagan
 * 
 * License: MIT Style License
 * 
 * GettingStarted: 
 * 	this is the place to start, if you want to understand the Geolive package. A MediaMap is an
 * 	instance of the Geolive application. the html structure should be defined prior to creating a MediaMap instance. 
 * 			html should be something like this. <div id="parent" style="[static width...height]">
 * 											<div id="map" style="width:100% height 80%"></div>
 *  										<div id="timeline" style="width:100% height 20%"></div> //if you want a timeline 
 * 										</div>
 * 	multiple instances of a maps (same page) probaly wont work as of this writing, (due to unique id's, some global variables, short sightedness. ) 
 * 	
 *  MediaMap overview:
 *  	initialize method is called on instantiation. all settings are merged (users settings override default)
 *  	a ServerQuery instance is created. and attached to this Mediamap instance for later (controls all ajax)
 *  	MediaMap registers a load event and waits for google's onLoad callback. nothing else is done until this event occurs
 * 
 * 	 	onLoad: MediaMaps "start()" method is executed. this method creates the google map instance and 
 * 		adds all the components and controls according to the settings.
 * 				*all the methods that are defined between initialize and start are used to do this. 
 * 		the main components that are loaded are:
 * 		StackOrderer. manipulates z-index to move elements into view if they are partially obstructed by other
 * 			items in StackOrders queue. also provides fadeout during dragging...dropping. 
 * 		LayerManager - loads all layers kml and kmz (details explained in MediaGLayers.js.) 
 * 		MarkerManager - currently loads all markers but should be replaced with a clusterer. 
 * 		TabMenu - defined in MediaMenuControl.js which, in most cases (except the fullscreen button) load
 * 			a new Palet into the map on a click event.
 * 		InfoViewers which are defined in MediaGWindow, and they control the display of content in info windows/lightbox's
 * 		**Note Palets are defined in MediaGPalet.js, but they rely on the menuControl instances that are defined
 * 		in MediaMenuControl.js. 
 * 			MediaPalets provide content that fit into instances of MenuControls. while MEnuControls provide the
 * 			functionality for dragging, closing, snapping, [smart placement and tiling - not implemented yet]
 * 		MouseEvent Listeners are defined for clicks on poly,line,marker... items. 
 * 			however if a layer's items are geoloaded (optional or kmz) then these events are taken care of.
 * 		
 * 	Also defined in this file is:
 * 		fullscreen class that is just a event listener for fullcreen toggles
 * 		EventListener that sorts mouseEvents but is not very useful really. 	
 * 		mm_debug is defined in debug.js, and tries to use whatever devolper console is provided 
 * 		by whichever browser is available to print helpful info 
 * 
 * ****Note**** 
 * 			this is the first javascript project/anything I have attempted so my js skills have evolved 
 * 			somewhat awkwardly as i have developed geolive - and taught myself js. judge forgivingly.
 */


var MediaMapVersion="2.0.1";
var MediaMaps=[];
var MediaMap=new Class({

	/**
	 * options: the default map parameters, overriden by user values on initialize. 
	 * TODO: remove options that are no longer usefull. 
	 * 
	 */
	options:
	{
	user:"guest",
	userHistory:true,
	lat:49.9388,				/*UBC Okanagan lat lng and zoom is most of okanagan*/
	lng:-119.3987,
	zoom:8,
	type:'satellite',		//default map type
	dragEnabled:true,
	zoomEnabled:true,	
	showTabMenu:true,
	maximizeEnabled:true,
	showMapTypes:true,			//allow switching between terrain. satellite. etc.
	showMapControl:true,		//the normal google map controller (zoom pan)
	mapControlRight:true,		//just rearanges things on right insead of left
	smallMapControl:false,		//just rearanges things on right insead of left
	showLayers:false,
	paletOptions:null,
	showSearch:true,			
	showDiscussionMarkers:true,	//discussion marker creator
	showGeneralMarkers:true,	//marker creator
	showPolygons:false,			//poly creator
	combineMarkers:false,		//puts all marker creation tools into a dropdown (if 2 or more are active)
	kmlDir:"/components/com_mediamapserver/kmlDocs/",
	dir:"/GeoLive/js/",
	queryContent:true,
	contentServer:"http://geolive.ca?option=com_mediamapserver&format=raw",
	showMiniMap:true,
	showScale:true,
	containerName:"my_media_map", /*very important that this remains unique*/
	mapId:-1,
	title:"MediaMap", 
	description:"Google Map - Media",
	name:"my_GoogleMap",
	iconSets:{markers:null, discussions:null},
	layersMetadata:null,
	layerManager:null,
	markerManager:null,
	markerManagerOptions:null,
	fullscreenContainer:null, //string id of container to use as element(parent is ) ie :"area"
	urlLocation:{}
	
	},
	/**
	 * MediaMap Constructor. initializes the map and attaches layerManager, eventManager, fullscreen object, etc. 
	 * This method, creates a map using custom map settings. the options parameter holds all the available options 
	 * and their default values.
	 * An ajax request is sent to the server to test geolive client/server communication.
	 * 
	 */
	initialize:function(userOptions){		
		var me=this;
		MediaMaps.push(me); // global array of maps for external scripts
		mm_debug(["Geolive Initialization Part 1. Geolive Version:"+MediaMapVersion+'.', {me:me, mootools:(MooTools?true:false), defaultOptions:me.options, mapOptions:userOptions, time:userOptions.serverTime||false}]);
		$extend(me.options,userOptions);
		
		if(me.options.serverTime){
			var serverTime=new Date(me.options.serverTime.replace(/-/g,'/'));
			var nowTime=new Date();
			me.serverOffsetTime=nowTime.getTime()-serverTime.getTime();
		}
		
		me.serverClient=new ServerClient({
			server:me.options.contentServer,
			modulePath:me.options.dir,			
			mapId:me.options.mapId				
		});
		//ServerClient.Instance=me.serverClient; 		



		var testServer=new MetaDataRequest(me);	//the task is set to 'echo' by default so this will return the json parameters (mapId) that get ripped from MediaMap
		testServer.addEvent('onSuccess', function(data){
			if(data.mapId>=me.options.mapId)
				mm_debug(["Server Client Test Success", {serverQuery:this, response:data}]);
			else
				mm_debug(["Server Client Test Failed", {serverQuery:this, response:data}]);
		});
		testServer.addEvent('onFailure', function(){		
			mm_debug(["Ajax Query Test Failed!", {serverQuery:this}]);		
		});
		testServer.execute();


		var loaded={count:2,done:0};
		if(me.options.userHistory){
			me.mapState=new MapState(me);
			me.mapState.loadState(function(meta){
				if(meta){
					me.previousSession=meta;
				}
				loaded.done++;
				if(loaded.done==loaded.count){me.start();}
			});
		}else{
			me.previousSession=null;
			loaded.done++;
		}
		GoogleState.setOnLoadCallback(function(){
			loaded.done++;
			if(loaded.done==loaded.count){me.start();}
		});
		mm_debug(['Geolive Initialization Part 1 Complete. Waiting for resources.', {options:me.options, mapIndex:MediaMaps.indexOf(me)}]);
	},
	createElement:function(parent)
	{
		var me=this;
		return $(me.options.containerName+"_content");
	},
	setMapBehavior:function(){
		/*
		 * default center, zoom, type
		 */
		var me=this;
		var url=$merge({lat:null,lng:null,zoom:null,type:null},me.options.urlLocation);
		var last={lat:null,lng:null,zoom:null,type:null};
		if(me.previousSession&&me.previousSession.map){
			try{
				var last={
						lat:me.previousSession.map.center[0],
						lng:me.previousSession.map.center[1],
						zoom:me.previousSession.map.zoom
				};
			}catch(e){
				var last={lat:null,lng:null,zoom:null,type:null};
			}
		}
		if(me.previousSession&&me.previousSession.map){
			try{
				last.type=me.previousSession.map.type;
			}catch(e){
				last.type=false;
				
			}
		}

		me.mainMap.setCenter(new GLatLng(url.lat||last.lat||me.options.lat, url.lng||last.lng||me.options.lng), url.zoom||last.zoom||me.options.zoom);
		me.mainMap.setZoom(url.zoom||last.zoom||me.options.zoom);
		me.mainMap.setMapTypeId(google.maps.MapTypeId[(url.type||last.type||me.options.type||'satellite').toUpperCase()]);



	},
	loadLayers:function(){
		var me=this;
		//var markerManagerOptions=me.options.markerManagerOptions||{}; //TODO: MarkerManager might need parameters	
		//me.markerManager=me.options.markerManager||new MarkerManager(me.mainMap,markerManagerOptions);
		var layerManagerOptions={queryForMetaData:me.options.queryContent,layersMetaData:me.options.layersMetadata}; 
		if(me.previousSession&&me.previousSession.layers)
			layerManagerOptions.layersMetaData={layers:me.previousSession.layers};
		me.layerManager=new LayerManager(me,layerManagerOptions);
	},
	/**
	 *start: called by initialize method, creates and configures the map.
	 */
	start:function(){
		var me=this;
		me.fireEvent('onInitializeStart');
		mm_debug(["Geolive Initialization Part 2. Starting Main Application."]);
		me.element=me.createElement($(me.options.containerName));		/*attach element to mediaMap*/
		me.mapOptions={			
				disableDefaultUI:true,
				backgroundColor:'#FAFAFF' 
		};
		me.mainMap = new google.maps.Map(me.element, me.mapOptions); 		/*attach google map to element*/
		me.setMapBehavior();		/*default center zoom type*/
		me.loadLayers();		/*load map item layers and marker manager*/
		if(me.options.userHistory)
			me.mapState.startTracking();
		/*menuOrderer allows draggable and overlayed items to come into view on mouseover*/
		me.menuOrderer=new menuOrderManager();
		/*tiler adds functionality to groups of palets. palets will register themselves*/
		me.tiler=new PaletTiler({container:me.element}); //adds functions to palets like - tile glue stack

		/*  adds an html object to the menuOrder object if it exists. 
		 *	used with menuOrder to get tricky google elements
		 */
		me.grabber=MediaMap.ElementGrabber(me.menuOrderer);



		
		me.eventManager=new EventManager(me);
		me.eventManager.startListening();		
		mm_debug(["Created Geolive EventManager.", {eventManager:me.eventManager}]);

		me.templateManager=new TemplateManager(me,{});
		me.pageManager=new PageManager(me,{});
		me.infoWindowViewer=new InfoWindowViewer(me, me.templateManager,{});	
		me.squeezeViewer=new SqueezeViewer(me, me.templateManager,{});	
		mm_debug(["Created Geolive Content Viewers.", {templateManager:me.templateManager, pageManager:me.pageManager, infoWindowViewer:me.infoWindowViewer, squeezeViewer:me.squeezeViewer}]);
		
		me.eventManager.addEvent('onMarkerClick',function(marker){
			me.infoWindowViewer.open(new PageModule(me, MapFactory.AbstractItem(marker), {template:'geolive'}), MapFactory.AbstractItem(marker));
		});	

		//TODO: snap to markers coordinate, if overlay is a Marker

		me.eventManager.addEvent('onRightClick',function(overlay, point){me.infoWindowViewer.zoom(me.mainMap.fromContainerPixelToLatLng(point),{});});	

//Custom StreetView causes loss of marker sharing.
//		me.mainMap.setStreetView(new google.maps.StreetViewPanorama(me.mainMap.getDiv(), {visible:false, enableCloseButton,
//			addressControlOptions:{position:google.maps.ControlPosition['BOTTOM_RIGHT']},
//			zoomControlOptions:{position:google.maps.ControlPosition['RIGHT_TOP']},
//			panControlOptions:{position:google.maps.ControlPosition['RIGHT_TOP']}
//		}));


		me.fireEvent('onInitializeEnd'); 

		mm_debug(['Geolive Initialization Part 2 Complete. Ready for external manipulation.']);
		me.isLoaded=true;

		//me.mainMap.addControl(new TextualZoomControl());
	},
	checkResize:function(){
		var me=this;
		google.maps.event.trigger(me.mainMap, 'resize');
	}


});
MediaMap.implement(new Options(), new Events());
/**
 * function returns a grabber function which
 * actually returns a function also.. bla
 */
MediaMap.ElementGrabber=function(menuOrderer){
	return function(elId){
		return function(){
			var el= $(elId);
			if(el)
			{
				menuOrderer.addItem(el);
				mm_debug("Added "+elId+" to Geolive MenuOrderer");
				return true;
			}
			return false;	
		};
	};
};




























