/**
 *	GMenuHelper
 *	- this class implements 
 *		1) in-scene menu
 *		2) resize detection
 *		3) placemark click handling
 *		4) anchored, floating and in-scene placemarks
 */
GMenuHelper = (function() {
	
	// div selector
	var $germdiv;
	var $contentdiv;
	var $menudiv; // menudiv contains contentdiv, buttons, logo, etc.

	// jquery object
	var $menu;
	var $menuwrapper;

	// convenocore, convenogerm, germ objects, jsobj
	var $that;
	var $cvn;
	var $cgerm = null;
	var $germ;
	var $jsobj;
	
	// germ placemarks
	var $gpmkMenu = null;
	var $gpmkFloat = null;
	var $gpmkActive = null;

	// states
	var $bMouseDown = false;
	var $bShowMenu = true;
	

	var THRESHOLD=0.01;
	function $IsEyeParamEqual(a,b) {
		if (!a || !b) return false;
		var pos1 = a.GetPosition();
		var ort1 = a.GetOrientation();
		var pos2 = b.GetPosition();
		var ort2 = b.GetOrientation();
		return ((pos1.x-pos2.x<THRESHOLD) && (pos1.y-pos2.y<THRESHOLD) && (pos1.z-pos2.z<THRESHOLD) &&
						(ort1.x-ort2.x<THRESHOLD) && (ort1.y-ort2.y<THRESHOLD) && (ort1.z-ort2.z<THRESHOLD));
	}


	// @constructor
	function GMenuHelper(param) {
		$germdiv = param.germdiv;
		$contentdiv = param.contentdiv;
		$menudiv = param.menudiv;

		$menu = $(param.menudiv);
		$menuwrapper = $menu.parent();
		$that = this;
	}

	GMenuHelper.prototype.CreateConvenoInstance = function (contentdiv) {
		if (typeof window.CreateConvenoInstance != 'function') {
			throw("Override CreateConvenoInstance before use");
			return null;
		}
		return CreateConvenoInstance(contentdiv);
	}

	GMenuHelper.prototype.Initialize = function (jsobj, webcontrol, fnSuccess, fnFailure) {
		$germ = webcontrol;

		$jsobj = jsobj;
		$cvn = $that.CreateConvenoInstance($contentdiv);

		$cgerm = new ConvenoGerm($cvn, webcontrol);
		$cgerm.Initialize(app_settings, function() {
			GMenuHelper.prototype.PostInitialize();
			if (typeof fnSuccess=="function") fnSuccess();				
		}, fnFailure);
	}

	GMenuHelper.prototype.DoPlacemarkActivated = function() {
		__log("DoPlacemarkActivated");
		GMenuHelper.prototype.AttachContent();
	}

	GMenuHelper.prototype.DoPlacemarkDeactivate = function() {
		__log("DoPlacemarkDeactivate");
		GMenuHelper.prototype.DetachContent();
	}

	GMenuHelper.prototype.DoEyeMoved = function() {
		if ($germ.IsCalloutOpen()) {
			$germ.CloseCallout();
		}
	}

	GMenuHelper.prototype.PostInitialize = function() {

		$germ.AddEventHandler(Germanium.Event.OnMouseDown, function() { $bMouseDown=true; });
		$germ.AddEventHandler(Germanium.Event.OnMouseUp, function() { $bMouseDown=false; });
//	$germ.AddEventHandler(Germanium.Event.OnGlideStarted, function() { $germ.UnsetActivePlacemark(); });
		$germ.AddEventHandler(Germanium.Event.OnGlideCompleted, GMenuHelper.prototype.OpenCalloutMenu);
		$germ.AddEventHandler(Germanium.Event.OnGlideCancelled, GMenuHelper.prototype.OpenCalloutMenu);
		$germ.AddEventHandler(Germanium.Event.OnEyeMoved, GMenuHelper.prototype.DoEyeMoved);
//	$cvn.AddListener("OnCameraStopped", GMenuHelper.prototype.OpenCalloutMenu);
		$cvn.AddListener("OnPlacemarkClicked", GMenuHelper.prototype.PlacemarkClicked);

		if (Germanium.GetAPIVersion()>$germ.CreateVersion(1,5,0,0)) {
			__log("Using API > 1.5");
			$germ.AddEventHandler(Germanium.Event.OnCalloutOpened, GMenuHelper.prototype.AttachContent);
			$germ.AddEventHandler(Germanium.Event.OnPlacemarkDeactivate, GMenuHelper.prototype.DetachContent);
		} else {
			$cvn.AddListener("OnPlacemarkActivated", GMenuHelper.prototype.DoPlacemarkActivated);
			$cvn.AddListener("OnPlacemarkDeactivate", GMenuHelper.prototype.DoPlacemarkDeactivate);
		}

//		$cvn.AddListener("OnPageBegin", function() { $germ.UnsetActivePlacemark(); });
		$cvn.AddListener("OnPageReady", GMenuHelper.prototype.ChooseCalloutPlacemark);

		// add placemark for CalloutMenu
		var dstyle = $germ.CreateDiamondStyle(null,0.0001,0.0001,0.0001);
		$gpmkMenu = $germ.CreatePlacemark("");
		$gpmkMenu.SetContent( "<div class='ConvenoGerm_Wrapper'></div>" );
		$gpmkMenu.GetStyleSet().SetGeometryStyle(dstyle);
		$germ.AddPlacemark($gpmkMenu);

		// create floating placemark
		dstyle = $germ.CreateDiamondStyle(null,0.0001,0.0001,0.0001);
		$gpmkFloat = $germ.CreatePlacemark("");
		$gpmkFloat.SetContent( "<div class='ConvenoGerm_Wrapper'></div>" );
		$gpmkFloat.GetStyleSet().SetGeometryStyle(dstyle);
		$germ.AddPlacemark($gpmkFloat);
		$gpmkFloat.Hide();

		$gpmkActive = $gpmkMenu;

		// set balloon style
		if ($germ.CreateBalloonStyle) {
			var balloonStyle = $germ.CreateBalloonStyle();
			balloonStyle.SetCloseButtonVisibility(false);
			balloonStyle.SetOutlineColor("cccccc");
			$gpmkMenu.GetStyleSet().SetBalloonStyle(balloonStyle);
			$gpmkFloat.GetStyleSet().SetBalloonStyle(balloonStyle);
		}

		// start polling
		this.timer = setInterval(function() { $that.PollStateChanges(); }, ConvenoConst.EYE_STABLE_PERIOD/2);


//TODO: remove this and put it after Initialize
		// add "Surrounding Places" to legend
		if (app_settings.showsurrounding) {

			var cb = $("#cbSamePmk");
			cb.click(function() {
				$cgerm.SetSameLevelVisibility( cb.attr("checked") );
				$cgerm.UpdatePlacemarksVisibility();
			});
			$("#aSamePmk").click(function() {
				$cgerm.SetSameLevelVisibility( cb.attr("checked") );
				$cgerm.UpdatePlacemarksVisibility();
			});

		}

		// bind show/hide menu button
		$("#btn_hidemenu").live("click", function() {
			$that.HideMenu();
		});

		$("#btn_showmenu").click(function() {
			$that.ShowMenu();
		});

	}

	GMenuHelper.prototype.Deinitialize = function() {
		clearInterval($that.timer);
		$cgerm.Deinitialize();
	}

	// states for tracking camera movement
	// as well as menu size changes
	var $lastEyeParam = null;
	var $eyeParamChanged = false;
	var $tmLastChanged = 0;
	var $lastMenuWidth = 0;
	var $lastMenuHeight = 0;

	GMenuHelper.prototype.PollStateChanges = function() {
		var eye = $germ.GetEye();
		var eyeParam = eye.GetParams();
		$eyeParamChanged = false;

		if ($IsEyeParamEqual(eyeParam, $lastEyeParam)) {
			var tmNow = new Date();
			if (tmNow - $tmLastChanged >= ConvenoConst.EYE_STABLE_PERIOD) {
				$eyeParamChanged = true;
			}
		} else {
			$tmLastChanged = new Date();
			$lastEyeParam = eyeParam;
		}

		if ($eyeParamChanged) {
			if (!$germ.GetActivePlacemark() && $bShowMenu) {
				$that.OpenCalloutMenu();
				return;
			}
		}

		if ($menu.outerWidth() != $lastMenuWidth ||
				$menu.outerHeight() != $lastMenuHeight) {
			__log("Size changed");
			$that.ResizeCalloutToFit();
			return;
		}

		// this is a fix for the odd case where callout doesn't have a size
		// style
		if ($germ.GetActivePlacemark()) {
			var gwrapper = $(".ConvenoGerm_Wrapper");
		 	if (!gwrapper.attr("style")) {
				__log("Ab case detected");
				$that.ResizeCalloutToFit();
			}
		}
	}

	var $timer 
	GMenuHelper.prototype.ResizeCalloutToFit = function() {
		if (!$gpmkActive) return;
		if (!$bShowMenu) return;

		$germ.UnsetActivePlacemark();
		if ($germ.IsCalloutOpen()) $germ.CloseCallout();

		$lastMenuWidth = $menu.outerWidth();
		$lastMenuHeight = $menu.outerHeight();

		var html = '<div class="ConvenoGerm_Wrapper" style="width:'+$lastMenuWidth+'px; height:'+$lastMenuHeight+'px;"></div>';
		$gpmkActive.SetContent( html );

		$that.OpenCalloutMenu();
	}

	GMenuHelper.prototype.ShowMenu = function() {
		$bShowMenu = true;
		$that.OpenCalloutMenu();
		$("#btn_showmenu").addClass("hidden");
	}

	GMenuHelper.prototype.HideMenu = function() {
		$bShowMenu = false;
		$germ.UnsetActivePlacemark();
		$("#btn_showmenu").removeClass("hidden");
	}
	
	GMenuHelper.prototype.OpenCalloutMenu = function() {
		__log("OpenCalloutMenu");
		var eye = $germ.GetEye();

		if (eye.IsGliding()) return;
		if (eye.IsRotating()) return;
		if ($cgerm.IsGliding()) return;
		if ($bMouseDown) return;
		if (!$bShowMenu) return;

		if ($gpmkActive==$gpmkMenu) {
			var geom = $gpmkMenu.GetGeometry();
			try {
				var x = 0; // $lastMenuWidth/2 + 30; //$germ.GetWidth()/2;
				var y = 0; //germ.GetHeight()/2;
				var inWindowPos = $germ.CreateCoordinates(x,y,1);
				var out3DPos = $germ.CreateCoordinates(0,0,0);
				eye.ConvertWindowTo3D(inWindowPos, out3DPos);
				geom.SetPosition(out3DPos);
			} catch (e) {
			}
		}
		$cgerm.SetActivePlacemark($gpmkActive);
	}

	GMenuHelper.prototype.PlacemarkClicked = function(event) {
//		__log("PlacemarkClicked: " + event.placemark);
		$gpmkActive = event.placemark;

//tw: 2010-04-07 - this was what causes the empty balloon problem. the
//callout was opened with empty contents, then only filled in when the
//polling kicks in	
//		$that.ShowMenu();
		$bShowMenu = true;
		$that.ResizeCalloutToFit();
		$("#btn_showmenu").addClass("hidden");
	}

	GMenuHelper.prototype.AttachContent = function() {
		__log("AttachContent");
		var wrapper = $(".ConvenoGerm_Wrapper");
		if (wrapper.length>0 && $menu) {
			$menu.appendTo(wrapper);
			$menu.css("visibility", "visible");
		} else {
///			setTimeout(GMenuHelper.prototype.AttachContent, 10); //TW: hack for API 1.4 and below
			return;
		}
		$(".Conveno_GettingHere select").css("visibility" , "visible"); // required for IE6
	}

	GMenuHelper.prototype.DetachContent = function() {
		__log("DetachContent"); // any way to detect if a user clicks on [x] to close placemark?
		if ($menuwrapper) {
			$menu.appendTo($menuwrapper);
			$menu.css("visibility" , "hidden");//2010-01-15
		}
		$(".Conveno_GettingHere select").css("visibility" , "hidden"); // required for IE6
	}

	GMenuHelper.prototype.ChooseCalloutPlacemark = function(name, param) {
		var tmp;

		if (name == "ConvenoPlacemark") {
				
			var pmk_id = param.pmk_id;
			var gpmk = $cgerm.GetGermPlacemarkById(pmk_id);
			tmp = gpmk;

		} else if (name == "ConvenoPath") {
			
			//option 1: set to source
			var src_pmk_id = $cgerm.GetPathSourcePlacemark(param.path_index);
			var gpmk = $cgerm.GetGermPlacemarkById(src_pmk_id);
			if (gpmk) {
				tmp = gpmk;
			} else {
				tmp = $gpmkMenu;
			}
/*
			//option 2: set to destination
			var path = $jsobj.path[param.path_index];
			var gpmk = $cgerm.GetGermPlacemarkById(path.dst_pmk_id);
			tmp = gpmk;
*/

		} else if (name == "ConvenoGuide") {
			
			var pos = $cgerm.GetGuidePosition(param.path_index, param.guide_index);
			if (pos) {
				var geom = $gpmkFloat.GetGeometry();
				geom.SetPosition(pos[0], pos[1], pos[2]);
				tmp = $gpmkFloat;
			} else {
				tmp = $gpmkMenu;
			}

		} else {
			tmp = $gpmkMenu;
		}

		// force a placemark refresh if a diff placemark is chosen
		if (tmp!=$gpmkActive) {
			$gpmkActive = tmp;
//			$that.ResizeCalloutToFit();
			$germ.UnsetActivePlacemark();
			$that.OpenCalloutMenu();
		} else {
			$that.OpenCalloutMenu();
		}
	}

	GMenuHelper.prototype.Run = function() {
		$cvn.Display();
	}

	GMenuHelper.prototype.GetConvenoCore = function() {
		return $cvn;
	}

	return GMenuHelper;
})();


