/**
 * 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.0";

var MediaMap=new Class({

	/*default options are overridden by user.*/
	options:
	{
	user:"guest",
	userHistory:true,
	lat:49.9388,				/*UBC Okanagan lat lng and zoom is most of okanagan*/
	lng:-119.3987,
	zoom:8,
	type:G_PHYSICAL_MAP,		//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
	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
	
	
	},

	initialize:function(userOptions){		
		var me=this;

		mm_debug('***Debug System Version************'); //mm_debug is a browser specific debug console printer
		mm_debug("Initializing Geolive Version:"+MediaMapVersion);

		if(!MooTools)mm_debug("MooTools was not detected!");
		else mm_debug("Detected MooTools Version:"+MooTools.version);
		
		
		mm_debug('***********************************');
		mm_debug("Default Parameters");	mm_debug(me.options);
		mm_debug("Users Parameters..."); mm_debug(userOptions);
		mm_debug('***********************************');


		$extend(me.options,userOptions);
		me.serverClient=new ServerClient({
			server:me.options.contentServer,
			modulePath:me.options.dir,			
			mapId:me.options.mapId				
		});
		//ServerClient.Instance=me.serverClient; 		



		var testServer=new AjaxQuery.MetaData(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");
			else
				mm_debug("Server Client Test Failed");
		});
		testServer.addEvent('onFailure', function(){
			
			mm_debug("Ajax Query Test Failed!");
			
		});
		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++;
		}
		google.setOnLoadCallback(function(){
			loaded.done++;
			if(loaded.done==loaded.count){me.start();}
		});
		mm_debug("Initializing Done. Waiting for GoogleLoad...");
	},
	createElement:function(parent)
	{
		var me=this;
		return $(me.options.containerName+"_content");
	},
	setMapBehavior:function(){
		/*
		 * default center, zoom, type
		 */
		var me=this;

		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};
			}
		}

		me.mainMap.setCenter(new GLatLng(last.lat||me.options.lat, last.lng||me.options.lng), last.zoom||me.options.zoom);
		me.mainMap.setMapType(me.options.type);
		if(me.options.zoomEnabled)
		{
			me.mainMap.enableContinuousZoom();
			me.mainMap.enableScrollWheelZoom();
		}
		me.mainMap.addMapType(G_PHYSICAL_MAP);		//allows terrain (elevation) map
		//me.mainMap.addMapType(G_AERIAL_HYBRID_MAP);	

		//G_AERIAL_HYBRID_MAP
		if(me.previousSession&&me.previousSession.map){
			try{
				var type=me.mainMap.getMapTypes()[me.previousSession.map.type];
				me.mainMap.setMapType(type);
			}catch(e){}
		}

	},
	loadLayers:function(){
		//attaching managers!
		var me=this;
		mm_debug("Loading Layers");
		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);
	},
	addMapControl:function(){
		var me=this;
		var mapControl=new GLargeMapControl3D();
		if(me.options.mapControlRight)
			me.mainMap.addControl(mapControl,new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(25,25)));
		else
			me.mainMap.addControl(mapControl);
		/*
		 * 	runLater() <--- in HTMLObjects
		 * 	used here, adds the external custom controls into the the stack orderer. even if they
		 *  are not yet added to the map themselves  
		 *  also runLater is a small object that just runs it callback function (at a given interval) 
		 *  until it returns true.
		 */
		new runLater(me.grabber("lmc3d"),1000);	//check once a second until success

	},
	addMapTypes:function(){
		var me=this;
		if(me.options.mapControlRight&&me.options.showMapControl)
			me.mainMap.addControl(new GMenuMapTypeControl(),new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(100,10)));
		else
			me.mainMap.addControl(new GMenuMapTypeControl());
		new runLater(me.grabber("menumtctl"),1000);
	},
	addMiniMap:function(){
		var me=this;
		me.mainMap.addControl(new GOverviewMapControl());
		new runLater(me.grabber("my_map_content_overview"),1000);
	},
	addScale:function(){
		var me=this;
		if(!me.options.showMiniMap)
			me.mainMap.addControl(new GScaleControl,new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(25, 25)));
		else
			me.mainMap.addControl(new GScaleControl,new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(150, 25)));
	},
	addFullscreenTab:function(){
		var me=this;
		var tabElement=null;
		var afterClick=function()
		{
			//execute this after toggling fullscreen
		};
		var fScreen=new Fullscreen($(me.options.containerName),$(me.options.containerName+"Container"),afterClick);
		function fullscreenClick(){
			tabElement=this;
			fullscreenClick=function(){
				var c=me.mainMap.getCenter();
				fScreen.execute(fScreen);
				tabElement.fireEvent('mouseout');
				tabElement.fireEvent('mouseleave');
				me.mainMap.checkResize();
				me.mainMap.panTo(c);
			}();	//redefines this function so that tabElement is not set each time.
		}
		me.tabMenu.addTab("images/TabGreyExpand40_t.png", "fllsc",fullscreenClick,"Expand::click to fill the entire browser with this map. you can click again later to shrink");
		me.fullscreen=fScreen;
		me.fullscreen.addEvent("onResize",
				function(){me.tiler.setBounds();}
		);
		me.addEvent('onInitializeEnd', function(){me.tiler.setBounds();});
	},
	addLayersTab:function(){

		var me=this;
		//var layerPalet=new LayerPalet(me);
		var layerPaletOptions={title:"Layers", layerManager:me.layerManager};
		if(this.options.paletOptions&&this.options.paletOptions.layerPaletOptions){
			layerPaletOptions=$merge(layerPaletOptions,this.options.paletOptions.layerPaletOptions);		
		}
		var layerPalet=new Palet.Layers(me,layerPaletOptions);
		me.layerPalet=layerPalet;
		me.tabMenu.addTab("images/TabGreyLayers40_t.png","lyrs",function()
				{
			layerPalet.open();
				},"Layers::click to view and manipulate the current layers for this map");
	},
	addCreateTabs:function(){
		var me=this;
		if(me.options.showGeneralMarkers)
		{

			var markerIcons=(me.options.iconSets.markers||[GoogleIconSet,
			                                               new MIconSet.AjaxSet(
			                                            		   {
			                                            			   title:"Building Icons",
			                                            			   description:"",
			                                            			   url:me.options.contentServer+"&task=places_markers"
			                                            		   })
			]);
			var markerPalet=new Palet.Marker(me,{title:"Placemarks", iconSets:markerIcons
			});
			me.markerPalet=markerPalet;
		}


		if(me.options.showDiscussionMarkers){

			var discussionIcons=(me.options.iconSets.discussions||[new MIconSet.AjaxSet(
					{
						title:"Discussion Icons",
						description:"",
						url:me.options.contentServer+"&task=discussion_markers"
					})
			/* 
			 * ,GoogleIconSet
			 */
			]);

			var discussionPalet=new Palet.Marker(me,{
				title:"Discussions",
				tags:{discussion:true},
				iconSets:discussionIcons


			});
			me.discussionPalet=discussionPalet;
		}
		if(me.options.showPolygons)
		{
			var polygonPalet=new Palet.Polygon(me,{
				title:"Polygons"
			});
			me.polygonPalet=polygonPalet;

		}

		/*
		 * The following adds a drop-down menu to the map. a mouseover event the main tab displays them (fade) 
		 */

		var count=0;
		$each([me.options.showDiscussionMarkers,me.options.showGeneralMarkers,(false&&me.options.showPolygons)],function(val){if(val)count++;});


		if(count>=2&&me.options.combineMarkers) //need at least 2 to stack.
		{
			var palets=[];
			if(me.options.showGeneralMarkers)
				palets.push( me.tabMenu.generateTab("images/TabGreyMarker40_r.png","mrkrs",function()
						{markerPalet.open();},"Point of Interrest::click here to create a new marker"));
			if(me.options.showDiscussionMarkers)
				palets.push( me.tabMenu.generateTab("images/TabGreyDiscussion40_r.png","disc",function()
						{discussionPalet.open();},"Discussions::click here to create a new discussion marker"));
			if(me.options.showPolygons)
				palets.push(me.tabMenu.generateTab("images/TabGreyPoly40_r.png","ply",function()
						{polygonPalet.open();},"Polygons::click here to create a new shape, line, or route"));
			me.tabMenu.addDropDownTab("images/TabGreyPin40_t.png","mrkrs",null,"Markers and Discussion::Select from one of the following options to create a new marker",palets);
		}
		else
		{
			if(me.options.showGeneralMarkers)
				me.tabMenu.addTab("images/TabGreyMarker40_t.png","mkrs",function()
						{
					markerPalet.open();
						},"Point of Interrest::click here to create a new marker");
			if(me.options.showDiscussionMarkers)
				me.tabMenu.addTab("images/TabGreyDiscussion40_t.png","mkrs",function()
						{
					discussionPalet.open();
						},"Discussions::click here to create a new discussion marker");
			if(me.options.showPolygons)
				me.tabMenu.addTab("images/TabGreyPoly40_t.png","ply",function()
						{
					polygonPalet.open();
						},"Polygons::click here to create a new shape, line, or route");
		}
	},
	/**
	 * build the map.
	 */
	start:function(){
		var me=this;
		me.fireEvent('onInitializeStart');

		mm_debug('***Debug Geolive*******************');
		mm_debug("Geolive Application Started. Creating Map!");

		me.element=me.createElement($(me.options.containerName));		/*attach element to mediaMap*/
		me.mainMap = new google.maps.Map2(me.element); 		/*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);

		mm_debug("Adding Google Controls");

		try{
		if(me.options.showMapControl&&$defined(GLargeMapControl3D))
			me.addMapControl();
		}catch(e){}

		if(me.options.showMapTypes)
			me.addMapTypes();

		if(me.options.showMiniMap)
			me.addMiniMap();

		if(me.options.showScale)
			me.addScale();
		if(me.options.showTabMenu){
			mm_debug("Adding Geolive Controls");
			me.tabMenu=new tabbedMenuControl(me.options.title, me.options.description, me.options.dir);

			if(me.options.maximizeEnabled)
				me.addFullscreenTab();

			if(me.options.showLayers)
				me.addLayersTab();

			var admin=(me.options.user=="admin"?true:false);
			var member=(this.options.user=="member"?true:false);

			if(admin||member)
				me.addCreateTabs();


			if(this.options.showSearch){
				var searchPalet=new Palet.Search(this,{title:"Address Lookup"});
				this.searchPalet=searchPalet;
				me.tabMenu.addTab("images/TabGreySearch40_t.png", "srch",function(){searchPalet.open();},"Search::click to search locations on the map");
			}

			me.tabMenu.addDropDownTab("images/TabGreyHome40_t.png","mrkrs",function()
					{
				me.mainMap.setZoom(me.options.zoom);
				me.mainMap.panTo(new GLatLng(me.options.lat, me.options.lng));
					},"Home::click to move the map to the home position", 
					[]);

			/*
			 * 	tabMenu.generateTab("images/TabGreySave40_r.png","mrkrs",function()
			 *			{
			 *		//		TODO: uncomment this block and write serverside code to save location
			 *			},"Save Home::click here to save your home position and zoom level")
			 */
			//if(BrowserDetect.browser!="Explorer")	
			{	if(me.options.mapControlRight)
				me.mainMap.addControl(me.tabMenu, new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(25, -1)));
			else	
				me.mainMap.addControl(me.tabMenu);

			}
			me.menuOrderer.addItem(me.tabMenu.container);
		}

		mm_debug("Adding Geolive EventManager");
		me.eventManager=new EventManager(me);
		me.eventManager.startListening();		

		mm_debug("Adding Geolive TemplateManager and Content Viewers");


		me.templateManager=new TemplateManager(me,{});
		me.pageManager=new PageManager(me,{});
		me.infoWindowViewer=new InfoWindowViewer(me, me.templateManager,{});	
		me.squeezeViewer=new SqueezeViewer(me, me.templateManager,{});	
		//me.sidePanel=new SidePanel(me, me.templateManager,{});	
		mm_debug("Attaching User Interface Events");

		me.eventManager.addEvent('onMarkerClick',function(marker){me.infoWindowViewer.open(new PageModule(me, marker.wrapper, {template:'geolive'}), marker.wrapper);});	

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

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



		me.fireEvent('onInitializeEnd'); 

		mm_debug('Geolive Ready');
		me.isLoaded=true;
		mm_debug('***********************************');

		//me.mainMap.addControl(new TextualZoomControl());
	}


});
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;	
		};
	};
};



























