/**
 * 	Date			: May 13, 2009
 *		Author		: Paul Warelis
 *		Copyright	: Dine.TO (www.dine.to)
 *		Description	: Theater map plugin
 */

(function($) {

	$.fn.theaterMap = function() {
		return this.each(function() {
			var $this = $(this);
			// Initialize the google map
			
			var mapDiv = $this.get(0);

			mapDiv.gMap = new GMap2(mapDiv);
			mapDiv.gMap.addControl(new GSmallMapControl());
			mapDiv.gMap.setCenter(new GLatLng(43.680101, -79.33964), 14);
			
			mapDiv.firstShow = true;
			mapDiv.disabled = true;
			mapDiv.isVisible = false;
			
			mapDiv.loadNewMarkers = false;
			mapDiv.loadNewEst = false;
			mapDiv.postalGeo = null;
			
			mapDiv.theaterMarkers = null;
			mapDiv.estMarkers = null;
			mapDiv.parkingMarkers = null;
			mapDiv.postalMarker = null;
			
		});
	};

	// Private functions //
	function gMapZindex() { return 10; }
	
	function createMarker(lat, lon, img, zIndex, parentTab) {
		var point = new GLatLng(lat, lon);
		
		var icon = new GIcon();
		icon.image = "images/movies/"+ img;
		icon.shadow = "images/movies/shadow.png";
		icon.shadowSize = new GSize(59, 32);
		icon.iconSize = new GSize(24, 38);
		icon.iconAnchor = new GPoint(12, 38);
		var options = { icon:icon, clickable:true };
		if (zIndex > 0) {
			// Theater icons go on top of establishment icons
			options["zIndexProcess"] = gMapZindex;
		}
		var marker = new GMarker(point, options);
		marker.zIndex = zIndex;
		marker.parentTab = parentTab;
		return marker;
	};
	
	function createMapMarkers($this) {
		var mapDiv = $this.get(0);
		if (!mapDiv.isVisible) return;

		var gMap = mapDiv.gMap;
		var boundry = new GLatLngBounds();
		var parentTab = $this.parents(".movieTabPage");

		if (mapDiv.loadNewMarkers) {
			// Remove previous markers
			if (mapDiv.theaterMarkers != null) {
				for (var i=0; i<mapDiv.theaterMarkers.length; i++) {
					mapDiv.theaterMarkers[i].tooltip.remove();
				}
			}
			gMap.clearOverlays();

			var theaterList = mapDiv.currentTheaters;
			var markers = [];
			for (var i=0; i<theaterList.length; i++) {
				var id = theaterList[i];
				var marker = createMarker(theaterInfo[id]['lat'], theaterInfo[id]['lon'], "gmIcon_movie.png", 10, parentTab);
				// Save theater id with every marker
				marker.theaterId = id;
				marker.type = 1;	// theater
	
				var tooltip = "<div><b>"+theaterInfo[id]['name']+"</b><br/>"+theaterInfo[id]['city']+"</div>";
				marker.tooltip = new Tooltip(marker, tooltip, 0);
				marker.tooltip.initialize(gMap);
				
				GEvent.addListener (marker, 'mouseover', $.fn.theaterMap.handleMarkerHover);
				GEvent.addListener (marker, 'mouseout', $.fn.theaterMap.handleMarkerUnHover);
				GEvent.addListener (marker, 'click', $.fn.theaterMap.handleMarkerClick);
				
				markers.push(marker);
				gMap.addOverlay(marker);
				// Extend the visible boundry to include the new point
				boundry.extend(marker.getLatLng());
			}
			
			mapDiv.loadNewMarkers = false;
			mapDiv.theaterMarkers = markers;

			if (mapDiv.postalGeo != null) {
				var marker = createMarker(mapDiv.postalGeo[0], mapDiv.postalGeo[1], "green-dot.png", 0, parentTab);
				gMap.addOverlay(marker);
				boundry.extend(marker.getLatLng());
				mapDiv.postalMarker = marker;
			} else {
				mapDiv.postalMarker = null;
			}
			
			// Change the zoom level for theaters, just to show the surrounding area
			var zoomLevel = gMap.getBoundsZoomLevel(boundry);
			if (zoomLevel > 13) zoomLevel = 13;
		} else {
			if (mapDiv.theaterMarkers != null) {
				for (var i=0; i<mapDiv.theaterMarkers.length; i++) {
					mapDiv.theaterMarkers[i].tooltip.hide();
				}
			}
		}
		
		// Load establishments if zoomed in
		var markers = [];
		if (mapDiv.currentEstablishments != null) {
			boundry = new GLatLngBounds();
			// if a new establishment list exists, load that and zoom in
			if (mapDiv.estMarkers != null) {
				// Remove previous markers
				for (var i=0; i<mapDiv.estMarkers.length; i++) {
					gMap.removeOverlay( mapDiv.estMarkers[i] );
				}
			}
			
			var estList = mapDiv.currentEstablishments;

			var estImage = {
				1 : "gmIcon_rest.png",
				2 : "gmIcon_cafe.png",
				3 : "gmIcon_bar.png"
			}
			for (var i=0; i<estList.length; i++) {
				var id = estList[i];
				var marker = createMarker( estInfo[id]['lat'], estInfo[id]['lon'], estImage[estInfo[id]['type']], 0, parentTab );
				// Save theater id with every marker
				marker.estId = id;
	
				var tooltip = "<div><b>"+estInfo[id]['name']+"</b><br/>"+estInfo[id]['address']+"<div style='text-align:right;color:green'>Click to view profile</div></div>";
				marker.tooltip = new Tooltip(marker, tooltip, 0);
				marker.tooltip.initialize(gMap);
				marker.profileUrl = estInfo[id]['profile'];
				
				GEvent.addListener (marker, 'mouseover', $.fn.theaterMap.handleMarkerHover);
				GEvent.addListener (marker, 'mouseout', $.fn.theaterMap.handleMarkerUnHover);
				GEvent.addListener (marker, 'click', $.fn.theaterMap.handleEstProfile);
				
				markers.push(marker);
				gMap.addOverlay(marker);
				// Extend the visible boundry to include the new point
				boundry.extend(marker.getLatLng());
			}
			if (mapDiv.postalMarker != null) {
				boundry.extend(mapDiv.postalMarker.getLatLng());
			}
			mapDiv.estMarkers = markers;
			mapDiv.loadNewEst = false;
		}

		// Load parking locations
		var markers = [];
		if (mapDiv.currentParking != null) {
			// if a new establishment list exists, load that and zoom in
			if (mapDiv.parkingMarkers != null) {
				// Remove previous markers
				for (var i=0; i<mapDiv.parkingMarkers.length; i++) {
					gMap.removeOverlay( mapDiv.parkingMarkers[i] );
				}
			}
			
			var parkList = mapDiv.currentParking;

			for (var i=0; i<parkList.length; i++) {
				var id = parkList[i];
				var marker = createMarker( parkInfo[id]['lat'], parkInfo[id]['lon'], "gpIcon.png", 0, parentTab );
	
				var type = (parkInfo[id]['type'] != 0) ? "Surface" : "Garage";
				var tooltip = "<div><b>"+parkInfo[id]['address']+"</b><br/>Type: "+type+"</div>";
				marker.tooltip = new Tooltip(marker, tooltip, 0);
				marker.tooltip.initialize(gMap);
				
				GEvent.addListener (marker, 'mouseover', $.fn.theaterMap.handleMarkerHover);
				GEvent.addListener (marker, 'mouseout', $.fn.theaterMap.handleMarkerUnHover);
				
				markers.push(marker);
				gMap.addOverlay(marker);
				// Extend the visible boundry to include the new point
				boundry.extend(marker.getLatLng());
			}
			mapDiv.parkingMarkers = markers;
		}
		
		
		var selectedTheater = $this.parent().find(".movieRowTheaterSelected:visible");
		if (selectedTheater.length > 0) {
			// Add the current theater marker to the boundry
			var theaterId = selectedTheater.get(0).theaterId;
			currentTheater = $this.getTheaterMarker(theaterId);
			if (currentTheater != null) {
				boundry.extend(currentTheater.getLatLng());
	
				var zoomLevel = gMap.getBoundsZoomLevel(boundry);
				
				if (markers.length == 0) {
					// If the establishment list is empty, zoom into the theater at a certain zoom level
					zoomLevel = 15;
				} else {
					// For the establishment list don't go deeper than 17
					if (zoomLevel > 17) zoomLevel = 17;
					zoomLevel--;
				}
			}
		}
		
		var centerPoint = boundry.getCenter();
		gMap.setCenter(centerPoint, zoomLevel);
	};

	function getMissingTheaters(theaterList, $this) {
		// Cake a call to the server to get the info
		callInProgress = true;
		$this.disableMap("<img src='images/indicator.gif'>");
		$.post(ajaxFile, {
				action		: "getMissingTheaterInfo",
				theaterList	: theaterList.join(",")
			}, function (data) {
				$this.enableMap();
				if (errorDetected(data)) return;
				// Server returns: theaterData (js array in string form, need to eval() it)
				
				// Evaluate theaterData, and insert into theaterInfo
				eval(data.theaterData);
				for (var j in theaterData) theaterInfo[j] = theaterData[j];
				
				// map the theaters
				createMapMarkers($this);
			},
		"json");
	};

	function getCloseByEstablishments(theaterId, $this) {
		if (callInProgress) return false;
		$this.disableMap("<img src='images/indicator.gif'>");
		callInProgress = true;
		$.post(ajaxFile, {
				action		: "getEstablishments",
				theaterId	: theaterId
			}, function (data) {
				$this.enableMap();
				if (errorDetected(data)) return;
				// Server returns: estData (js array in string form, need to eval() it)
				
				eval(data.estData);
				currentEstList = [];
				for (var j in estData) {
					currentEstList.push(j);
					estInfo[j] = estData[j];
				}
				// Green pee parking
				eval(data.parkData);
				currentParkList = [];
				for (var j in parkData) {
					currentParkList.push(j);
					parkInfo[j] = parkData[j];
				}
				
				// Stick the establishment list into the map object just in case it's hidden
				$this.get(0).currentEstablishments = currentEstList;
				$this.get(0).currentParking = currentParkList;

				// Save it with the theater record too
				theaterInfo[ theaterId ].estList = (estData.length == 0) ? null : currentEstList;
				theaterInfo[ theaterId ].parkList = (parkInfo.length == 0) ? null : currentParkList;
				
				// map the establishments
				createMapMarkers($this);
			},
		"json");
	};

	/* Public functions */
	$.fn.toggleMapVisibility = function() {

		var mapDiv = this.get(0);

		mapDiv.isVisible = !mapDiv.isVisible;
		this.toggle();
		
		if (mapDiv.isVisible) {
			mapDiv.gMap.checkResize();
			if (mapDiv.firstShow) {
				// When the map is shown for the first time, do some initialization
				var offset = this.offset();
				this.next().css({
					// Map cover size and position
					"top"		: offset.top,
					"left"	: offset.left,
					"width"	: this.width(),
					"height"	: this.height()
				}).fadeTo("fast", 0.7).next().css({
					// map message position
					"top"		: offset.top,
					"left"	: offset.left,
					"width"	: this.width()
				});
				mapDiv.firstShow = false;
			}
		}

		if (mapDiv.disabled) {
			// Map is disabled: if visible, cover the map div
			if (mapDiv.isVisible) this.disableMap();
			else this.enableMap(true);
		}
		
		if (mapDiv.isVisible && (mapDiv.loadNewMarkers || mapDiv.loadNewEst)) createMapMarkers(this);
	};
	
	// Maps a list of theaters
	$.fn.mapTheaters = function(theaterList) {

		var mapDiv = this.get(0);
		// Reset the establishment list
		mapDiv.currentEstablishments = null;
		mapDiv.currentParking = null;
		// Save the theater list with the map, just in case it's hidden
		mapDiv.currentTheaters = theaterList;
		mapDiv.loadNewMarkers = true;
		
		// Scan the list, and see what theaters are missing from the cache, then get their details
		var missingIds = [];
		// Check if the list is in the cache
		for (var i=0; i<theaterList.length; i++) {
			var itemId = theaterList[i];
			if (typeof(theaterInfo[ itemId ]) == "undefined") {
				missingIds.push(itemId);
			}
		}

		if (missingIds.length == 0) {
			// Everything is there, pass them to the map
			createMapMarkers(this);
		} else {
			// Get the missing info
			getMissingTheaters(missingIds, this);
		}
		return this;
	};

	$.fn.enableMap = function(hideCover){
		// Hide mapCover and mapMsg
		this.next().hide().next().hide();
		var mapDiv = this.get(0);
		mapDiv.mapMessage = null;
		if (typeof hideCover == "undefined") {
			mapDiv.disabled = false;
		}
		return this;
   };

	$.fn.disableMap = function(content){
		var mapDiv = this.get(0);
		
		mapDiv.disabled = true;
		
		if (typeof content != "undefined") {
			// New message coming in. Save it just in case the map is not visible
			mapDiv.mapMessage = content;
			if (!mapDiv.isVisible) return this;
		}
		
		var mapCover = this.next();
		var mapMsg = mapCover.next();
		
		if (mapDiv.mapMessage == null) {
			// We already calculated sizes, so just show the message
			mapCover.show();
			mapMsg.show();
		} else {
			// First time for this map message. Calculate the div size and show it
			mapMsg.html(mapDiv.mapMessage);
			mapDiv.mapMessage = null;
			mapCover.show();
			var offset = mapCover.offset();
			
			var top = Math.round( (mapCover.outerHeight() - mapMsg.outerHeight()) / 2 )+offset.top;
			var left = Math.round( (mapCover.outerWidth() - mapMsg.outerWidth()) / 2 )+offset.left;
			
			mapMsg.css({
				"top"		: top,
				"left"	: left
			}).show();
		}
		return this;
   };
	
	// Zooms in on one theater, will get closest establishments and change the view to show all of them
	$.fn.zoomInOnTheater = function(theaterId) {
		this.get(0).loadNewEst = true;
		// If the theater is missing a list of establishments

		if (typeof(theaterInfo[ theaterId ]) == "undefined" ||
			typeof(theaterInfo[ theaterId ].estList) == "undefined") {
			// Make a call to the server and get them
			getCloseByEstablishments(theaterId, this);
		} else {
			// Set the establishment list to match the theater's
			this.get(0).currentEstablishments = theaterInfo[theaterId].estList;
			this.get(0).currentParking = theaterInfo[theaterId].parkList;
			
			// Display the establishments and zoom in (or out, whatevah)
			createMapMarkers(this);
		}
		return this;
	};
	
	// Zooms out the view to show all theaters currently on the map
	$.fn.zoomOut = function() {
		var mapDiv = this.get(0);
		var gMap = mapDiv.gMap;
		mapDiv.currentEstablishments = null;
		mapDiv.currentParking = null;

		var markers = mapDiv.theaterMarkers;
		if (markers == null) return this;
		
		// Change the visible boundry to include all theater markers
		var boundry = new GLatLngBounds();
		for (var i=0; i<markers.length; i++) {
			boundry.extend(markers[i].getLatLng());
			markers[i].tooltip.hide();
		}

		if (mapDiv.postalMarker != null) {
			boundry.extend(mapDiv.postalMarker.getLatLng());
		}

		var zoomLevel = gMap.getBoundsZoomLevel(boundry);
		if (zoomLevel > 13) zoomLevel = 13;

		var centerPoint = boundry.getCenter();
		gMap.setCenter(centerPoint, zoomLevel);

		// Get rid of establishment markers
		var markers = mapDiv.estMarkers;
		if (markers != null) {
			for (var i=0; i<markers.length; i++) {
				markers[i].tooltip.remove();
				gMap.removeOverlay( markers[i] );
			}
			mapDiv.estMarkers = null;
		}
		// And parking locations
		var markers = mapDiv.parkingMarkers;
		if (markers != null) {
			for (var i=0; i<markers.length; i++) {
				markers[i].tooltip.remove();
				gMap.removeOverlay( markers[i] );
			}
			mapDiv.parkingMarkers = null;
		}

		return this;
	};

	$.fn.getTheaterMarker = function(theaterId) {
		var theaterMarkers = this.get(0).theaterMarkers;
		for (var i=0; i<theaterMarkers.length; i++) {
			if (theaterMarkers[i].theaterId == theaterId) return theaterMarkers[i];
		}
		return null;
	};

	$.fn.setPostalCode = function(postalGeo) {
		var mapDiv = this.get(0);
		mapDiv.postalGeo = postalGeo;
	};


	$.fn.theaterMap.handleMarkerHover = function() {
		this.tooltip.show();
		this.tooltip.redraw(true);
		if (typeof this.theaterId == "undefined") return;
		
		var theaterId = this.theaterId;

		if (this.parentTab.attr("id") == "tabTheaters") {
			$(this.parentTab).find(".resultBox").find("#mth"+theaterId).trigger("mouseover");
		} else {
			// make sure the correct movie is selected !!
			$(this.parentTab).find(".movieRowSelected").next().find("#mth"+theaterId).trigger("mouseover");
		}
	};
	
	$.fn.theaterMap.handleMarkerUnHover = function() {
		this.tooltip.hide();
		
		if (typeof this.theaterId == "undefined") return;
		// simulate theater row un-hover, again depending on the tab
		var theaterId = this.theaterId;
		$(this.parentTab).find(".movLocationHover").trigger("mouseleave");
	};

	$.fn.theaterMap.handleMarkerClick = function() {
		var theaterId = this.theaterId;
		
		// Tab dependent
		if (this.parentTab.attr("id") == "tabTheaters") {
			var theaterRow = $(this.parentTab).find(".resultBox").find("#mth"+theaterId);
			if (theaterRow.length == 0) {
//				alert("dude");
			} else {
				theaterRow.trigger("click");
			}
		} else {
			// make sure the correct movie is selected !!
			$(this.parentTab).find(".movieRowSelected").next().find("#mth"+theaterId).trigger("click");
		}
		
	};

	$.fn.theaterMap.handleEstProfile = function() {
		var newWindow = window.open("http://www.dine.to/"+this.profileUrl, '_blank');
		newWindow.focus();
	};
	
})(jQuery);
