//
// File : rtwgmap-core.js
//
// Description : Core Javascript functions for an RTWGMap implementation. 
//
// Contents    : 
//               getFilters - 
//                                       
//
//

/***
 * google.maps.Map.prototype.clearOverlays()
 * This function is needed in v3 to replicate the behavior that was removed in v2
 * - markerObjs - an Array of google.maps.Marker
 ***/

//TODO - Does the map actually have a markers array anymore?  I don't think it does.

google.maps.Map.prototype.clearOverlays = function() {
    for(var i=0; i < this.markers.length; i++){
        this.markers[i].setMap(null);
    }
    //this.markers = new Array();
};

//var infoWindow = new google.maps.InfoWindow();  //Global InfoWindow Object - This ex
var infoWindow = new InfoBubble();  //This is a 3rd party library that is needed to reproduce the google v2 info tabs.

var gmarkers = [];			//array of google.maps.Marker objects
var markerObjs = [];		//array of gov.agric.map.beans.Marker.java objects
var bounds = [];				//array of ??google.maps.LatLngBounds objects ??
var markerMgr;
//var listings = [];
var regions = [];				//not sure
var map = null;					// google.maps.Map
var globalRegion = new Object();
var directionsPanel;
var directions;
var showDirections = true;
var startAddress = getCookie("startAddress");
var startCity = getCookie("startCity");
var PROV = "AB";
var zoomToId = "";
var markerInfo = {
	markerTypeLabel : ""
};
var printableMarkers = [];
var loading = 0;

//
// initialize the map and other required objects
//
function initMap() {
	//DWRUtil.useLoadingMessage();
	loading = 1;
	getMarkerInfo();

	getMarkers();
	createMap();
	getRegions();
	getFilters();

	var mapDiv = document.getElementById("map");
	recenterMap();
	addOverlays();
	loading = 0;
};

function addOverlays() {

}

//
// get the marker info (or metadata)
//
function getMarkerInfo() {
	eval(getDataProviderClassName()).getMarkerInfo(returnMarkerInfo);
}

//
// get all the gmarkers for the map
//
function getMarkers() {
	eval(getDataProviderClassName()).getMarkers(returnMarkers);
}

//
// get all the regions for the map
//
function getRegions() {
	eval(getDataProviderClassName()).getRegions(returnRegions);
}

//
// get all the gmarkers for the specified region
//
function getMarkersForRegion(regionId) {
	currentRegionId = regionId;
	//map.closeInfoWindow();
	if(infoWindow && infoWindow.isOpen())//infoWindow.getMap())
		infoWindow.close();
	
	closeDirections();

	for ( var i = 0; i < regions.length; i++) {
		if (regions[i].id == regionId) {
			globalRegion = regions[i];

			//map.setCenter(new GLatLng(regions[i].latitude, regions[i].longitude), regions[i].zoomLevel)
			map.setCenter(new google.maps.LatLng(regions[i].latitude, regions[i].longitude));
			map.setZoom(regions[i].zoomLevel);
			break;
		}
	}
}

//
// set a cookie
//
function setCookie(name, value) {
	var today = new Date();
	var cookie_expire_date = new Date(today.getTime() + (30 * 7 * 86400000));

	var cookieString = name + "=" + escape(value) + ";expires="
			+ cookie_expire_date.toGMTString();
	document.cookie = cookieString;
}

//
// get a cookie
//
function getCookie(name) {
	var start = document.cookie.indexOf(name + "=");
	var len = start + name.length + 1;
	if ((!start) && (name != document.cookie.substring(0, name.length)))
		return null;
	if (start == -1)
		return null;
	var end = document.cookie.indexOf(";", len);
	if (end == -1)
		end = document.cookie.length;
	var value = unescape(document.cookie.substring(len, end));
	if (value == null || value == "null")
		value = "";
	return value;
}

//
// Delete a cookie
//
function Delete_Cookie(name, path, domain) {
	if (Get_Cookie(name))
		document.cookie = name + "=" + ((path) ? ";path=" + path : "")
				+ ((domain) ? ";domain=" + domain : "")
				+ ";expires=Thu, 01-Jan-70 00:00:01 GMT";
}

//
// Unapply any filters being applied
function unapplyFilter() {
	if (isFiltering()) {
		//map.clearOverlays();
		clearInnerHTML(document.getElementById("sideListing"));
		showAllMarkers();
		recenterMap();
		selectedFilters = [];
	}
}

//
// Show (unhide) all the known markers
//
function showAllMarkers() {
	for ( var m = 0; m < markerObjs.length; m++) {
		//gmarkers[markerObjs[m].id].show();
		gmarkers[markerObjs[m].id].setVisible(true);
	}
	initSideListing();
}

//
// shows only the Markers that match a filter
//
function applyFilter(filterName) {
	//TESTING
	//alert('applyFilter called');
	//TESTING
	var filteredMarkers = [];
	var gmarker = 0;

	//map.clearOverlays();  // don't clear, just hide the markers
	if (directions != null)
		//directions.clear();
		directions.setMap(null);

	var j = 0;
	var filter = null;

	// get a reference to the filter
	for ( var i = 0; i < filters.length; i++) {
		if (filters[i].label == filterName) {
			filter = filters[i];
			//alert("Filter : "+ filter);
			break;
		}
	}

	if (filter == null)
		alert('no filter found for ' + filterName);

	// special case - if the filter doesn't have a property map, show all
	if (!filter.propertyMap) {
		unapplyFilter();
		if(!isFiltering())
			initSideListing(); // unapplyFilter already calls initSideListing();
		return;
	}

	var filterPropertyName = filter.propertyMap.key;
	var filterPropertyValue = filter.propertyMap.value;

	for ( var m = 0; m < markerObjs.length; m++) {
		if (!markerObjs[m].additionalInfo)
			continue;

		var value = eval("markerObjs[m]." + filterPropertyName);

		if (value == filterPropertyValue) {
			// include this gmarker in the resultset
			var info = markerObjs[m].infoHtml;
			info += "<p/>";
			info += "<span class=\"smallTextCenter\"><a href=\"javascript:zoomIn('"
					+ markerObjs[m].id + "');\">Zoom In</a>" + "</span>&nbsp;&nbsp;";

			//gmarker = createGMarker(markerObjs[m]);
			//gmarkers[markerObjs[m].id] = gmarker;
			//gmarkers[markerObjs[m].id].show();
			gmarkers[markerObjs[m].id].setVisible(true);

			//map.addOverlay(gmarker); 
			filteredMarkers[j++] = markerObjs[m];
		} else {
			if (gmarkers[markerObjs[m].id])
				//gmarkers[markerObjs[m].id].hide();
				gmarkers[markerObjs[m].id].setVisible(false);
		}
	}
	globalRegion = filter;
	//        returnFilteredMarkers(filteredMarkers);

	recenterMap();
}

//
// Recenter the map
//
function recenterMap() {
	//map.setCenter(new GLatLng(54.6, -113.0), 5);
	map.setCenter(new google.maps.LatLng(54.6, -113.0));
	map.setZoom(5);
}

//
// Get all the gmarkers
//    
function getAllMarkers() {

	var gmarker = 0;
	//map.clearOverlays();
	//this is the new way to clear the markers.
	for ( var i = 0; i < markerObjs.length; i++) {
		gmarkers[markerObjs[i].id].setMap(null);
	}
	
	for ( var i = 0; i < markerObjs.length; i++) {
		gmarker = createGMarker(markerObjs[i]);
		//map.addOverlay(gmarker); not sure if this is right...
		gmarker.setMap(map);
	}
	//recenterMap();
}

//
// callback for getMarkerInfo()
//
var returnMarkerInfo = function(data) {
	if (data != null) {
		markerInfo = data;
	}
}

//
// callback for getMarkers()
//
var returnMarkers = function(data) {
	if (data != null) {
		var gmarker = 0;
		var count = 0;
		for ( var i = 0; i < data.length; i++) {
			if (data[i].latitude != null) {
				var markerObj = data[i];
				markerObjs[count] = markerObj;

				gmarker = createGMarker(markerObj);
				gmarkers[markerObj.id] = gmarker;

				markerObj.isAddedToMap = false;
				count++;
			}
		}

	}

	if (zoomToId != null && zoomToId != "")
		zoomIn(zoomToId);
	zoomToId = null;

	loading = 0;
	setDefaultFilter();

	manageMarkers(null, null);
}

//
// Provided for implementors to utilize 
// - called from returnMarkers at the point where the
// available markers have been added to the map (and should
// be filtered by the default filter as needed on startup)
//
function setDefaultFilter() {

}

//
// callback for getRegions()
//
var returnRegions = function(data) {
	if (data != null) {
		var htmlList = '<span class="smallText" ><b>Choose Region:</b></span>';
		for ( var i in data) {
			regions[i] = data[i];
			htmlList = htmlList + renderRegion(regions[i]);
			//var sw = new GLatLng(regions[i].envelope.x + regions[i].envelope.height, regions[i].envelope.y);
			var sw = new google.maps.LatLng(regions[i].envelope.x + regions[i].envelope.height, regions[i].envelope.y);
			//var ne = new GLatLng(regions[i].envelope.x, regions[i].envelope.y + regions[i].envelope.width);
			var ne = new google.maps.LatLng(regions[i].envelope.x, regions[i].envelope.y + regions[i].envelope.width);

			//console.debug("region : " + regions[i].name + " x=" + regions[i].envelope.x + " y=" +regions[i].envelope.y + " w="+regions[i].envelope.width + " h=" +regions[i].envelope.height);                
			//console.debug("  sw="+sw);
			//console.debug("  ne="+ne);

			//bounds[regions[i].id] = new GLatLngBounds(sw, ne);
			bounds[regions[i].id] = new google.maps.LatLngBounds(sw, ne);

		}

		htmlList = htmlList + '<br/>';
		document.getElementById("regions").innerHTML = htmlList;

		initSideListing();
	}
}

//
// 
// Loads the rendered markers that match the filter
// into the "sideListing' element
//
// See also 
//   renderMarkerForSideListing(marker)
//   applySelectedFilter()
//
var returnFilteredMarkers = function(data) {
	var htmlList = '<div class="smallTextCenter">';

	var label = getSideListingsLabel();
	if (document.getElementById('sideListingHeader')) {
		document.getElementById('sideListingHeader').innerHTML = label;
	}

	htmlList += getPrintUrl(label);

	printableMarkers = data;
	if (data != null) {
		htmlList = htmlList + '<br/>';
		for ( var i = 0; i < data.length; i++) {
			htmlList = htmlList + renderMarkerForSideListing(data[i]);
		}

		htmlList = htmlList + '</div>';

		document.getElementById("sideListing").innerHTML = htmlList;
	}
}

//
// Clear the html for an obj/div/other
// 
function clearInnerHTML(obj) {
	// remove child objects
	while (obj.firstChild)
		obj.removeChild(obj.firstChild);
}

//
// Get the url to print the current markers/listings
//
function getPrintUrl(label) {
	//print link
	var printIcon = "/app21/rtw/icons/maps/printer2.gif";
	return "<center><a href='javascript:printCurrentListings(\"" + label
			+ "\");'><img src='" + printIcon + "' border='0'/></a></center>";
}

//
// print the current listings
// see printableMarkers, returnFilteredMarkers
//
function printCurrentListings(title) {
	top.consoleRef = window.open('', 'myconsole', 'width=600,height=400'
			+ ',menubar=0' + ',toolbar=1' + ',status=0' + ',scrollbars=1'
			+ ',resizable=1');

	var content = "<h1>" + title + "</h1>";
	for ( var i = 0; i < printableMarkers.length; i++) {
		content += "<br/>" + printableMarkers[i].infoHtml;
		//content += printableMarkers[i].equipHtml;
	}

	top.consoleRef.document
			.writeln('<html><head><title>'
					+ title
					+ '</title></head>'
					+ '<body style="font-size: 0.86em;" bgcolor=white onLoad="self.focus(); window.print();">'
					+ content + '</body></html>');

	top.consoleRef.document.close();
}

//
// Initialization for the Map
//
function createMap() {
	
		var mapDiv = document.getElementById("map");
		
		//map = new GMap2(mapDiv);
		
		var mapOptions = {
				center: new google.maps.LatLng(54.6, -113.0),
				mapTypeId: google.maps.MapTypeId.ROADMAP,
				zoom: 5,
	      streetViewControl:false,
	      zoomControl:true,
	      zoomControlOptions:{
	      	style:google.maps.ZoomControlStyle.LARGE
	      },
	      panControl:true
		}
			
		map = new google.maps.Map(mapDiv, mapOptions);
		
		google.maps.event.addListener(map, "dragend", function(oldLevel, newLevel) {
			manageMarkers(null, null);
			manageMarkers(oldLevel, newLevel);
			checkBounds();
			globalRegion = null;
		});
		
		google.maps.event.addListener(map, "idle", function(){
			checkBounds();
		});

		//GEvent.addListener(map, "zoomend", function(oldLevel, newLevel) {
//		google.maps.event.addListener(map, "zoomend", function(oldLevel, newLevel) {
//			manageMarkers(oldLevel, newLevel);
//		});
//		
//		//GEvent.addListener(map, "moveend", function() {
//		google.maps.event.addListener(map, "moveend", function() {
//			manageMarkers(null, null);
//		});
//		
//		//GEvent.addListener(map, "dragend", function() {
//		google.maps.event.addListener(map, "dragend", function() {
//			globalRegion = null;
//		}); // user moved the map, there is no region now

		//map.enableContinuousZoom();  ** No longer supported in v3 **

		//Initialize directions
		//directions = new GDirections(map);//, directionsPanel);
		directions = new google.maps.DirectionsRenderer();
		//directions.isVisible = false;  ** doesn't look liek this maps to anything.
		//GEvent.addListener(directions, "error", handleErrors);
		google.maps.event.addListener(directions, "error", handleErrors);

//		GEvent.addListener(directions,"load", function() {
//			setTimeout('renderDirections(map,"map",directions,document.getElementById("sideListing"))', 1);
//		});

//		var mt = map.getMapTypes();
//		//Overwrite min and max resolution parameters
//		for ( var i = 0; i < mt.length; i++) {
//			mt[i].getMinimumResolution = function() {
//				return 5;
//			}
//			mt[i].getMaximumResolution = function() {
//				return 17;
//			}
//		}

		//The above is no longer allowed in v3.  Now we have to set a listener to see when the zoom has changed on the map.
		
		google.maps.event.addListener(map, 'zoom_changed', function() { 
		  if (map.getZoom() < 5) { 
		    map.setZoom(5); 
		  } else if (map.getZoom() > 17) {
		  	map.setZoom(17);
		  }
		}); 
		
		//map.addControl(new GLargeMapControl()); ** The default works fine for this.

		//recenterMap;
		recenterMap();

		//               map.getPane(G_MAP_FLOAT_SHADOW_PANE).style.visibility="hidden"; 

		//GEvent.addListener(map, "move", function() {
//		google.maps.event.addListener(map, "move", function() {
//			checkBounds();
//		});

		//var allowedBounds = new GLatLngBounds(new GLatLng(48.5, -120.0), new GLatLng(60.9, -109.0));
		var allowedBounds = new google.maps.LatLngBounds(new google.maps.LatLng(48.5, -120.0), new google.maps.LatLng(60.9, -109.0));

		function checkBounds() {
			if (allowedBounds.contains(map.getCenter())) {
				return;
			}
			var c = map.getCenter();
			var xcoord = c.lng();
			var ycoord = c.lat();

			var aMaxX = allowedBounds.getNorthEast().lng();
			var aMaxY = allowedBounds.getNorthEast().lat();
			var aMinX = allowedBounds.getSouthWest().lng();
			var aMinY = allowedBounds.getSouthWest().lat();

			if (xcoord < aMinX) {
				xcoord = aMinX;
			}
			if (xcoord > aMaxX) {
				xcoord = aMaxX;
			}
			if (ycoord < aMinY) {
				ycoord = aMinY;
			}
			if (ycoord > aMaxY) {
				ycoord = aMaxY;
			}
			//map.setCenter(new GLatLng(ycoord, xcoord));
			map.setCenter(new google.maps.LatLng(ycoord, xcoord));

		}
	
}

//
// show the markerObj's info window/balloon
//
function myclick(id) {
	//GEvent.trigger(gmarkers[id], "click");
	google.maps.event.trigger(gmarkers[id], "click");
}

//
// Zoom in to a gmarker
//
function zoomIn(id) {
	//gmarkers[id].show();
	//map.setCenter(new GLatLng(gmarkers[id].getPoint().lat(), gmarkers[id].getPoint().lng()), 14);
	//GEvent.trigger(gmarkers[id], "click");

	gmarkers[id].setVisible(true);
	map.setCenter(new google.maps.LatLng(gmarkers[id].getPosition().lat(), gmarkers[id].getPosition().lng()))
	map.setZoom(14);
	google.maps.event.trigger(gmarkers[id], "click");
	
}

function closeDirections() {
	//if (directions != null && directions.isVisible == true) {
	if (directions != null && directions.getMap() != null) {
		//directions.isVisible = false;
		//directions.clear();
		directions.setMap(null);
		manageMarkers(null, null);
	}
}

//
// Get the directions to a marker using the start address provided
// Utilizes DOM to get values from the ui form elements : 'startAddressTxt' & 'startCityTxt'
//
// Called when the user presses the "Get Directions" Button on the gmarker's Direction tab
//
function getDirections(id) {
	/**
	 * 
	 *   This has been commented out until it is needed again
	 
	directions.isVisible = true;
	map.getInfoWindow().hide();

	var currentmarker = gmarkers[id];
	var currentListing = getMarkerObj(id);

	//alert("get directions to " +currentmarker.getPoint().lat() + " " + currentmarker.getPoint().lng() );
	var lat = currentmarker.getPoint().lat();
	var lng = currentmarker.getPoint().lng();
	var endlatlng = lat + "," + lng;

	//get the start address & town entered
	startAddress = document.getElementById("startAddressTxt").value;
	startCity = document.getElementById("startCityTxt").value;

	// save start address in cookies for the next session
	setCookie("startAddress", startAddress);
	setCookie("startCity", startCity);

	//build the url to the printer friendly page
	var prstart = encodeURIComponent(startAddress) + ","
			+ encodeURIComponent(startCity) + "," + PROV;
	var prend = encodeURIComponent(currentListing.address) + ","
			+ encodeURIComponent(currentListing.town) + "," + PROV + "&sll="
			+ endlatlng;
	var printurl = "http://maps.google.com/maps?f=d&hl=en&geocode=&saddr="
			+ prstart + "&daddr=" + prend
			+ "&sspn=4.301366,10.283203&ie=UTF8&z=13&om=1&pw=2";

	var start = startAddress + " " + startCity + " " + PROV;
	var end = currentListing.address + "@" + endlatlng;

	//clear the previous directions and set the header for the sideListings 
	//space before GDirections will output/append to it
	directions.clear();
	clearInnerHTML(document.getElementById("sideListing"));
	var htmlList = '<div class="textBoldGrey">Directions to '
			+ currentListing.name + '</div><div class="smallTextCenter"><br/>';

	//close directions link
	htmlList = htmlList
			+ '<div style="align: right"><a href="javascript:closeDirections();">Close Directions</a></div><br/>';

	//print link
	htmlList = htmlList
			+ '<a target="_blank" href="'
			+ printurl
			+ '"><img border="0" src="/app68/listings/icons/maps/printer.gif"/></a><br/>';

	document.getElementById("sideListing").innerHTML = htmlList;

	//load the directions ! This will do the callback to rtwgmap-ui#renderDirections() that was setup earlier
	directions.load("from: " + start + " to: " + end, {
		getSteps : true
	});
	****/
}

//
// handle any/all errors returned from google
//
function handleErrors() {
	
	/****
	 *
	 * This has been commented out for now.  Will add functionality later
	 *
	 
	if (directions.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
		alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: "
				+ directions.getStatus().code);
	else if (directions.getStatus().code == G_GEO_SERVER_ERROR)
		alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: "
				+ directions.getStatus().code);

	else if (directions.getStatus().code == G_GEO_MISSING_QUERY)
		alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: "
				+ directions.getStatus().code);

	else if (directions.getStatus().code == G_GEO_BAD_KEY)
		alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: "
				+ directions.getStatus().code);

	else if (directions.getStatus().code == G_GEO_BAD_REQUEST)
		alert("A directions request could not be successfully parsed.\n Error code: "
				+ directions.getStatus().code);

	else
		alert("An unknown error occurred.");

	//reload the current map's region
	if (globalRegion != null) {
		getMarkersForRegion(globalRegion.id);
	} else {
		getAllMarkers();
	}****/
}

// 
// Show a marker
//
function show(markerObj) {
	var gmarker = gmarkers[markerObj.id];

	if (!markerObj.isAddedToMap){
		//map.addOverlay(gmarker);
		gmarker.setMap(map);
	}
	markerObj.isAddedToMap = true;
	//gmarker.show();
	gmarker.setVisible(true);
}

//
// Hide a marker
//
function hide(markerObj) {
	var gmarker = gmarkers[markerObj.id];
	if (gmarker)
		//gmarker.hide();
		gmarker.setVisible(false);
}

//
// Get a marker obj using it's unique id
//
function getMarkerObj(id) {
	for ( var m = 0; m < markerObjs.length; m++) {
		if (markerObjs[m].id == id)
			return markerObjs[m];
	}
	return null;
}

//
// move end occurred (drag, pan, programatic zoom, etc
// 
function manageMarkers(oldLevel, newLevel) {
	var gmarker = null;

	if (isFiltering() && !directions.isVisible) {
		applySelectedFilters();
	} else if ((newLevel == null || oldLevel == null) || oldLevel != newLevel) {
		//no real region now - just use the marker type label
		globalRegion = new Object();
		globalRegion.label = markerInfo.markerTypeLabel;
		globalRegion.id = -1;

		//show all the markers
		for (m in gmarkers) {
			//gmarkers[m].show();
			gmarkers[m].setVisible(true);
		}

		if (newLevel == null) {
			newLevel = map.getZoom();
		}

		//
		// manage which markers are viewable
		//            
		for ( var m = 0; m < markerObjs.length; m++) {
			var markerObj = markerObjs[m];
			gmarker = gmarkers[markerObj.id];

			//
			// Show the marker if the marker is in the current viewport 
			// and the map's zoom level is within it's viewable range, 
			// 
			//if (map.getBounds().contains(gmarker.getPoint())) {
			if (map && map.getBounds() && map.getBounds().contains(gmarker.getPosition())) {
				if (markerObj.visibleRange[0] <= newLevel
						&& markerObj.visibleRange[1] >= newLevel) {
					show(markerObj);
				} else
					hide(markerObj);
			}
		}

		// update the side listing for the markers shown
		//
		// (the code in applySelectedFilters() will update the list
		// with markers that match in alberta - not just in the current
		// view)
		//if (directions == null || directions.isVisible == false)
		if (directions == null || directions.getMap() == null)
			updateSideListingForCurrentView();
	}
}

//
// Returns all the marker objs (not gmarkers) in the current view
//
function getMarkersInCurrentView() {
	var markersInView = [];
	var gmarker = 0;
	var j = 0;

	// 
	// build a resultset of all
	// the markers in the current view
	//
	for ( var m = 0; m < markerObjs.length; m++) {
		gmarker = gmarkers[markerObjs[m].id];
		//if (!gmarker.isHidden() && map.getBounds().contains(gmarker.getPoint())) {
		if (gmarker.getVisible() && map && map.getBounds() && map.getBounds().contains(gmarker.getPosition())) {
			markersInView[j++] = markerObjs[m];
		}
	}

	return markersInView;
}

//
// update the side listing for all the gmarkers for the current view
//
function updateSideListingForCurrentView() {
	// list all the markers in the current view in the side listings    
	var markers = getMarkersInCurrentView();
	returnFilteredMarkers(markers);

	if (markers == null || markers.length == 0)
		initSideListing();
}
