/******************************************************************************
 * File Name: markerController.js
 * Purpose: Code for markerController class
 * Author: C.Bateman
 * Date Created: 28.Oct.2008
 * Revision History:
 * Date:		Modified By:	Description:
 *
 *****************************************************************************/


/*********************************************************************************
* Name:			markerController (class constructor)
* Attributes:
*	name				- String - The name given to the instance of this class
*	map					- GMap2 - map object
*	markers				- Array of Marker objects - all marker info.
*	gmarkers			- Array of GMarkers - all markers which are currently visible
*	visibleLiList		- Array - indexes are the ids of currently visible markers
*	newVisibleLiList	- Array - populated when the map is updated
*	curRequestId		- Integer - tracks which request was last sent
*	parseActive			- Boolean - used to disable or enable parsing of markers
*	colList				- String - holds last value for new page requests
*	search				- String - holds last value for new page requests
*	sw					- GLatLng - holds last value for new page requests
*	ne					- GLatLng - holds last value for new page requests
*	getViewPages		- Boolean - if true, only currently visible markers will be listed.  List will update as map moves.
*									This is currently always false, but may be implemented with a checkbox or similar.
*
* Inputs:		String 'name', GMap2 'map'
* Returns:		itself
*********************************************************************************/
function markerController(name, map) {
	this.name = name;
	this.map = map;
	
	this.markers = [];
	this.gmarkers = [];
	
	this.visibleLiList = [];
	this.newVisibleLiList = [];
	
	this.curRequestId = 0;
	this.parseActive = true;
	
	this.colList = '';
	this.search = '';
	this.sw = null;
	this.ne = null;
	
	this.getViewPages = false;
	
	// Listener to update map when it moves and only if at least one 'points' collection is checked
	var that = this;
	this.moveListener = GEvent.addListener(this.map,"moveend", function() {
		that.parse(false, false, false);
		if (that.getViewPages) {
			that.getPage(1);
		}
	});
	
}



/*******************************************************************
* Name:		getMarkerThumb (markerController class method)
* Purpose:	Returns link the thumbnail image for given marker.
* Inputs:	Int 'id'
* Returns:	-
*******************************************************************/
markerController.prototype.getMarkerThumb = function(id) {
	var marker = this.markers[id];
	//return "http://contentdm.lib.byu.edu/cgi-bin/thumbnail.exe?CISOROOT=/"+marker.cisoroot+"&CISOPTR="+marker.cisoptr;
	return "http://files.lib.byu.edu/cdmmaps/cache/"+marker.cisoroot+"_"+marker.cisoptr+"_thumb.jpg";
}



/*******************************************************************
* Name:		parse (markerController class method)
* Purpose:	Sends AJAX request to server with map viewport and 
*			search data.  Parses list of markers to show in sidebar.
* Inputs:	Boolean 'newView' - whether to reset map position and 
*								update the side list - this is true
*								when the collection, date, or search
*								parameters are changed.
*			Boolean 'newDates' - whether to update date slider - this
*								 is true when collections are changed.
*			Boolean 'newList' - update the list of markers
*			Function 'callback' - executed on completion of function
* Returns:	-
*******************************************************************/
markerController.prototype.parse = function(newView, newDates, newList, callback) {
	if (!this.parseActive) return;
	
	// new id for each request
	this.curRequestId++;
	
	$("#loading").show();
	var that = this;
	
	var url = "serverCluster.php";
	var bounds = that.map.getBounds();
	this.sw = bounds.getSouthWest();
	this.ne = bounds.getNorthEast();
	
	this.colList = "";
	$("#colList input:checkbox:checked").each(function() {
		that.colList += $(this).attr("value") + ",";
	});
	this.colList = this.colList.slice(0,-1);
	
	this.search = $("input#search").val();
	
	var minRes = null;
	var maxRes = null;
	var mapWidth = null;
	var mapHeight = null;
	// If the position is to be reset, we get the available zoom levels
	// and the size of the map container
	if (newView) {
		var mapType = this.map.getCurrentMapType();
		minRes = mapType.getMinimumResolution();
		maxRes = mapType.getMaximumResolution();
		mapWidth = this.map.getContainer().clientWidth;
		mapHeight = this.map.getContainer().clientHeight;
	}
	
	$.get(
		url, 
		{
			reqId:		that.curRequestId,
			zoom:		that.map.getZoom(),
			s:			that.sw.lat(),
			w:			that.sw.lng(),
			n:			that.ne.lat(),
			e:			that.ne.lng(),
			col:		that.colList,
			sDate:		sDate,
			eDate:		eDate,
			search:		that.search,
			newView:	newView,
			newDates:	newDates,
			minRes:		minRes,
			maxRes:		maxRes,
			mapWidth:	mapWidth,
			mapHeight:	mapHeight
		},
		function(data) {
			//	The beginning of the data will include text like this: "/*req=12*/"
			//	If this number is not equal to the current request id, it means that
			//	another request was sent after this one - meaning that this request
			//	should be ignored.
			regexSlice = data.slice(0,12);
			var pat = new RegExp(/req=(\d*)/);
			if (pat.exec(regexSlice)[1] == that.curRequestId) {
				// clear markers individually so InfoWindows aren't removed
				var i = that.gmarkers.length
				while(i--) {
					that.map.removeOverlay(that.gmarkers[i]);
				}
				that.gmarkers = [];
				
				// This eval will add single and cluster markers, 
				// possibly change the view, and possibly change the date range
				eval(data);
				
				
				if (newList) {
					that.getPage(1);
				}
				
				$("#loading").fadeOut(100);
				
				if (newDates) {
					var cookieList = '';
					$("#colList input:checkbox:checked").each(function() {
						cookieList += $(this).attr("value") + ";";
					});
					cookieList = cookieList.slice(0,-1);
					
					$.cookie("collections", cookieList, { path: "/DigitalMaps/", expires: 30 });
				}
			}
			if (typeof callback == "function") callback();
		}
	);
	
}



markerController.prototype.getPage = function(page) {
	var that = this;
	var url = "page.php";
	if (this.getViewPages) {
		$.get(
			url,
			{
				col:		that.colList,
				sDate:		sDate,
				eDate:		eDate,
				search:		that.search,
				page:       page,
				s:			that.sw.lat(),
				w:			that.sw.lng(),
				n:			that.ne.lat(),
				e:			that.ne.lng()
			},
			function(data) {
				$("#ajaxListDiv").html(data);
				listTooltips();
			}
		);
	} else {
		$.get(
			url,
			{
				col:		that.colList,
				sDate:		sDate,
				eDate:		eDate,
				search:		that.search,
				page:       page
			},
			function(data) {
				$("#ajaxListDiv").html(data);
				listTooltips();
			}
		);
	}
}



/*******************************************************************
* Name:		setDates (markerController class method)
* Purpose:	Called from eval in parse(), when collections have changed.
*			Sets the range for the date slider.
* Inputs:	Float 'lat', Float 'lng', Integer 'id'
* Returns:	-
*******************************************************************/
markerController.prototype.setDates = function(newSDate,newEDate) {
	sDate = newSDate;
	eDate = newEDate;
	
	
	$("#dateStartSelect option").show();
	$("#dateEndSelect option").show();
	
	$("#dateStartSelect option").each(function() {
		if ($(this).val() < sDate || $(this).val() > eDate) {
			$(this).hide();
		}
	});
	
	$("#dateEndSelect option").each(function() {
		if ($(this).val() < sDate || $(this).val() > eDate) {
			$(this).hide();
		}
	});
	
	$("#dateStartSelect").val(sDate);
	$("#dateEndSelect").val(eDate);
	
}



/*******************************************************************
* Name:		setNewBounds (markerController class method)
* Purpose:	Called from eval in parse() when collections, dates, or
*			keywords have changed.  Given a bounding box, moves the
*			map to the position and zoom that best fits the box.
* Inputs:	Float 's', Float 'w', Float 'n', Float 'e'
* Returns:	-
*******************************************************************/
markerController.prototype.setNewBounds = function(centerLat,centerLng,zoom) {
	// Disable parsing while we move the map
	this.parseActive = false;
	this.map.setCenter(new GLatLng(centerLat,centerLng), zoom);
	this.parseActive = true;
}


/*******************************************************************
* Name:		addSM (markerController class method)
* Purpose:	Called from eval in parse().  Adds a single marker to 
*			the map.
* Inputs:	Float 'lat', Float 'lng', Integer 'id'
* Returns:	-
*******************************************************************/
markerController.prototype.addSM = function(lat,lng,id) {
	var point = new GLatLng(lat,lng);
	var gmarker = new MarkerLight(point, {image: "images/newnewmarker2.png", height:24, width:12, leftOffset:6, bottomOffset:1, title:this.markers[id].name });
	
	var that = this;
	GEvent.addListener(gmarker,"click",function() {
		that.popUp(id);
	});
	this.map.addOverlay(gmarker);
	
	this.gmarkers.push(gmarker);
}

/*******************************************************************
* Name:		addCM (markerController class method)
* Purpose:	Called from eval in parse().  Adds a cluster marker to 
*			the map
* Inputs:	Float 'lat', Float 'lng', Array 'markerIds'
* Returns:	-
*******************************************************************/
var addingNewEffect = false;
markerController.prototype.addCM = function(lat,lng,markerIds) {
	var that = this;
	var len = markerIds.length;
	
	var point = new GLatLng(lat,lng);
	var gmarker = new MarkerLight(point, {image: "images/chart3.png", height:40, width:40, leftOffset:20, bottomOffset:20, title: len, cluster:true});
	
	var that = this;
	GEvent.addListener(gmarker,"click",function() {
		var zoom = map.getZoom();
		var maxZoom = map.getCurrentMapType().getMaximumResolution();
		if (len > 120 && zoom < maxZoom) {
			var newZoom = 0;
			if (maxZoom - zoom > 3) {
				newZoom = zoom + 3;
			} else {
				newZoom = maxZoom;
			}
			map.setCenter(point, newZoom);
		} else {
			that.clusterPopUp(markerIds,point);
		}
	});
	
	this.map.addOverlay(gmarker);
	
	this.gmarkers.push(gmarker);
}





/*******************************************************************
* Name:		popUp (markerController class method)
* Purpose:	Opens an InfoWindow for the specified marker. Called from
*			listener instantiated in addSM(), from a cluster window, 
*			or from the marker list.
* Inputs:	Integer "id"
* Returns:	-
*******************************************************************/
markerController.prototype.popUp = function(id,source, callback) {
	var marker = this.markers[id];
	var point = new GLatLng(marker.lat,marker.lng);
	var divClass = "iwMainDiv";
	if (marker.streetview) divClass = "iwMainDivStreet";
	var windowHtml = "<h5>"+marker.name+"</h5><span style='font-style:italic;'>"+$("#"+marker.cisoroot).val()+"</span><div class='"+divClass+"'><div id=\"imgDiv\"><a href='http://files.lib.byu.edu/cdmmaps/cache/"+marker.cisoroot+"_"+marker.cisoptr+"_display.jpg' onclick='return showShadowbox(this)' title='"+marker.name+"' rel='shadowbox'><img class='iwThumb' src='"+this.getMarkerThumb(id)+"'/><p>Click to enlarge</p></a></div>"+marker.description+"</div><span style='float:left;'><span style='font-weight:bold;'>"+marker.date+"</span>";
	
	if (marker.accuracy != '') {
		windowHtml += "<br/>Accuracy: " + marker.accuracy;
	}
	
	windowHtml += "</span><span style='float:right'><a id='originalLink' target='_blank' href='http://contentdm.lib.byu.edu/u?/"+marker.cisoroot+","+marker.cisoptr+"' >More Details</a></span>";
	
	if (marker.streetview) {
		var tabs = [];
		tabs.push(new GInfoWindowTab("Description", windowHtml));
		var tab2 = "<div id=\"pano\" style=\"height:250px;width:400px;\"></div>";
		tabs.push(new GInfoWindowTab("Street View", tab2));
		this.map.openInfoWindowTabsHtml(point, tabs, {
			maxWidth:300,
			onOpenFn: function() {
				if (typeof callback == "function") callback();
				var pano = new GStreetviewPanorama(document.getElementById("pano"));
				pano.setLocationAndPOV(point);
			}
		});
		
	} else {
		this.map.openInfoWindowHtml(point, windowHtml,{
			maxWidth: 350, 
			onOpenFn: function() {
				if (typeof callback == "function") callback();
			}
		});
	}
	
	var feature = "markerPopup";
	if (source == 'list') {
		feature = "markerPopup-list";
	} else if (source == 'cluster') {
		feature = "markerPopup-cluster";
	}
	
	// Omniture
	var s=s_gi("byuhbll");
	s.linkTrackVars="None";
	s.linkTrackEvents="None";
	s.tl(true, "o", "Mappify: " + marker.cisoroot+","+marker.cisoptr);
}




/*******************************************************************
* Name:		clusterPopUp (markerController class method)
* Purpose:	Opens an InfoWindow containing a list of the identified 
*			markers. Called from listener instantiated in addCM().
* Inputs:	Array 'markerIds', GLatLng 'point'
* Returns:	-
*******************************************************************/
markerController.prototype.clusterPopUp = function(markerIds, point) {
	
	var clusterWindowList = "";
	for (var i=0;i<markerIds.length;i++) {
		var id = markerIds[i];
		clusterWindowList += "<li id='"+id+"'><a href='javascript:"+this.name+".popUp("+id+",\"cluster\")'>" + this.markers[id].name + "</a></li>";
	}
	
	this.map.openInfoWindowHtml(
		point, 
		"<h5>CLUSTER</h5><div class='clusterWindow'><ul>"+clusterWindowList+"</ul></div>",
		{ maxWidth:300, onOpenFn: function() { clusterWindowTooltip(); }	}
	);
	
}

