function checkEmails (selector, checkNull) {
	j = selector;
	if (j.inputError == null) {
		setupInputError (j, 'Invalid email address');
	}
	var emails = j.val();
	if (emails.length == 0) {
		if (checkNull) {
			return j.doit();
		}
		return j.undoit();
	}
	emails = emails.replace(/ /g, "");
	emails = emails.split(',');
	var validEmails = [];
	for ( var i = 0; i < emails.length; ++i) {
		if (/^([A-Za-z0-9_\-\.\+])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/.test(emails[i]) === false) {
			return j.doit();
		}
	}
	return j.undoit();
}

function checkPrintFormat (j) {
	if (j.inputError == null) {
		setupInputError (j, 'Please select PDF, PNG, JPG, or all three.');
	}
	var pdfChecked = data.pdfInput.is(':checked');
	var pngChecked = data.pngInput.is(':checked');
	var jpgChecked = data.jpgInput.is(':checked');
	if (pdfChecked || pngChecked || jpgChecked) {
		return j.undoit();
	}
	return j.doit();
}

function setupInputError (j, errorText) {
	j.inputError = $('<div/>');
	j.inputError.addClass ('alertDialogPopup');
	j.inputError.text (errorText);
	$('#alertDialogContent').append(j.inputError);
	j.doit = function () {
		var pos = this.position();
		this.inputError.css ({
			'top': pos.top - ((this.inputError.outerHeight() - this.outerHeight()) / 2),
			'left': pos.left - (this.inputError.outerWidth()) - 10
		});
		this.addClass('inputError');
		this.inputError.show();
		return false;
	};
	j.undoit = function () {
		this.removeClass('inputError');
		this.inputError.hide();
		return true;
	};
}
/*
 * This is the callback that existed 20 times (That I have found so far). Now
 * condensed into one.
 */
function genericPrePrint (callback) {
	if (map != null) {
		var indicator = map.getIndicator();
		if (indicator) {
			var jsonbreaks = indicator.createCustomBreaksJSON (session2.get('nb') ? session2.get('nb') : DEFAULT_NUMBREAKS,	true);
			if (jsonbreaks) {
				var obj = {};
				obj[indicator.id] = jsonbreaks;
				return PAsync2.call(PEnvironment.stringstoreUrl + '?str=' + MochiKit.Base.serializeJSON(obj), callback);
			}
		}
	}
	return callback();
}

function genericPrint (data, callback) {
	var linkManager = new PLinkManager();
	data.link.name = data.name;
	if(data.template == 'map' || data.template == 'analytic') {
		// Parameters are now different depending on the print type for maps
		// and analytics, so they are regnerated with each print.
		data.parms = genMapJpgLink();
		
		// Two of the parameters from genMapJpgLink are imgheight and imgwidth.
		// They're based on the size of the map on the user's screen, but this
		// is generally always smaller than the space we're looking to fill
		// on the page for a printed map. This means the maps on prints need to
		// be blown up to fit the page and they won't look so good (especially
		// if the user has a small screen resolution). To fix this, we'll
		// replace the height and width arguments with ones of a fixed size
		// (that matches the space we're looking for fill on the page).
		
		// The fixed sizes will be the same between regular map and analytic
		// prints, as they both conveniently have roughly the same amount of
		// maximum vertical space that can potentially be taken up by other
		// stuff. "fillmap" was added to the Java to indicate whether to resize
		// the rendered map to fill the page, or just draw it as is.
		
		// We're only doing this for PNG prints! Using these fixed sizes
		// generally increases the extent of the maps in prints, and our JPG
		// and PDF prints are intended to be more of a WYSIWYG kind of thing
		// (and they are also intended to be lower quality anyway).
		if(data.printType == 'png') {
			data.parms += "&fillmap=false";
			var newWidth, newHeight;
			if(data.link.url.indexOf("or=landscape") != -1) {
				newWidth = PrintSizes.map.landscape.width;
				newHeight = PrintSizes.map.landscape.height;
			} else if(data.link.url.indexOf("or=portrait") != -1) {
				newWidth = PrintSizes.map.portrait.width;
				newHeight = PrintSizes.map.portrait.height;
			}
			if(newWidth && newHeight) {
				data.parms = data.parms.replace(/imgwidth=\d+/, "imgwidth=" + newWidth);
				data.parms = data.parms.replace(/imgheight=\d+/, "imgheight=" + newHeight);
			}
		} else {
			data.parms += "&fillmap=true";
		}
	}
	
	if (data.action == 'print') {
		if (data.printType == 'jpg') {
			linkManager.printJPG (
				data.link,
				callback,
				data.parms,
				data.printTemplate
			);
		} else if (data.printType == 'png') {
			linkManager.printPNG(
				data.link,
				callback,
				data.parms,
				data.printTemplate
			);
		} else if (data.printType == 'pdf') {
			linkManager.printPDF(
				data.link,
				callback,
				data.parms,
				data.printTemplate
			);
		} else if (data.printType == 'csv') {
			linkManager.printCSV(
				data.link,
				callback,
				data.printTemplate
			);
		}
	} else if (data.action == 'email') {
		linkManager.emailLink(
			data.link, 
			callback, 
			data.emails,
			data.message,
			data.emailFromValue
		);
	} else if (data.action == 'save') {
		linkManager.add(
			data.link,
			callback,
			data.printTemplate
		);
	}
};

function genericPrintStatusMessage (data, status, msg) {
	var text;
	data.header = null;
	if (data.status != null) {
		data.previousStatus = data.status;
	}
	data.status = status;
	if (status == 307) {
		text = "Retrieved saved " + data.printType.toUpperCase() + " " + data.template + ".";
		window.location = msg;
	} else if (status == 202 || status == 200) {
			text = msg;
	} else if (status == 403 && PEnvironment.siteId != 1) {
		window.location = "/redirect.jsp"; 
	} else {
		var action = data.action == 'print' ? 'printing' : 'saving';
		if (data.printType == 'email') {
			text = "There was a problem sending the email: " + msg;
		} else if (data.printType == 'map') {
			text = "There was a problem " + action + " the map: " + msg;
		} else {
			text = "There was a problem " + action + " the " + data.printType + " " + data.template + ": " + msg;
		}
	}
	// Check to see if this message has already been added to the alert dialog.
	// If so, ignore it. (This is to prevent multiple identical messages.)
	var addMessage = true;
	if(data.statusMessages == null) {
		data.statusMessages = [];
	} else {
		for(var i=0; i<data.statusMessages.length; i++) {
			if(data.statusMessages[i] == text) {
				addMessage = false;
				break;
			}
		}
	}
	if(addMessage) {
		if (data.okText == null) {
			data.okText = text;
		} else if (text != null) {
			data.okText += "<br><br>" + text;
		}
		data.statusMessages.push(text);
	}
	return data;
}

function genericPrintCheck (data) {
	data.name = $('#editTitleInput').val();
	if (data.action == 'print') {
		if (data.template == 'map' || data.template == 'analytic') {
			if ($("input[name='orientation']:checked")) {
				data.link.url += "&or=" + $("input[name='orientation']:checked").val();
				printOrientation = $("input[name='orientation']:checked").val();
			}
		} else if (data.template == 'chart') {
			data.parms += "&or=landscape";
		}
		data.name = $('#editTitleInput').val();
		var pdfChecked = $('#pdfCheckbox').is(':checked');
		var pngChecked = $('#pngCheckbox').is(':checked');
		var jpgChecked = $('#jpgCheckbox').is(':checked');
		// If island printing was selected, turn it on. We're going to turn
		// it back off immediately after receiving the response to the last
		// print request, as we don't want the live map using it.
		var islChecked = $("input[name='island']:checked").val();
		if(islChecked == "region") {
			islandPrintEnabled = true;
			data.link.url += "&island=true";
		} else {
			islandPrintEnabled = false;
		}
		
		// Add each requested print type to the array of types. When
		// finished, pass it (with the data) to sendPrintRequests.
		var printTypes = [];
		if(pdfChecked || data.printType == "pdf") {
			printTypes.push("pdf");
		}
		if(pngChecked || data.printType == "png") {
			printTypes.push("png");
		}
		if(jpgChecked || data.printType == "jpg") {
			printTypes.push("jpg");
		}
		if(printTypes.length > 0) {
			sendPrintRequests(data, printTypes);
		} else {
			checkPrintFormat(data.pdfInput);
			return false;
		}
	} else {
		genericPrePrint (function () {
			genericPrint (
				data,
				function (status, msg) {
					data = genericPrintStatusMessage (data, status, msg);
					genericAlertDialog ({template: 'generic', data: data});
				}
			);
		});
	}
	return true;
}

function sendPrintRequests(data, printTypes) {
	// Sends a request for each print needed. Works one a time; calls
	// itself again after receiving the backend's response to each
	// print request until there are no more print types left.
	if(printTypes.length > 0) {
		// At least one more print request still needs to be sent.
		genericPrePrint(function() {
			data.printType = printTypes.shift();
			genericPrint(data, function(status, msg) {
				data = genericPrintStatusMessage(data, status, msg);
				sendPrintRequests(data, printTypes);
			});
		});
	} else {
		// All requests have been sent.
		// In case island printing was turned on, turn it back off so
		// the live map doesn't use it.
		islandPrintEnabled = false;
		// Display the alert.
		genericAlertDialog({template: 'generic', data: data});
	}
}

function checkPlaceInd () {
	var place = null;
	var ind = null;
	var pins = null;
	// check global arrays in tables page
	if (PEnvironment.pageName == 'tables') {
		if (global_places.length > 0) {
			place = global_places[0];
		}
		if (global_indicators.length > 0) {
			ind = global_indicators[0];
		}
	}
	else {
		// for map page find the current place and the current indicator
		if (mapstates.currentplace && mapstates.currentplace.getType()) {
			place = mapstates.currentplace;
		}
		if (map.getIndicator()) {
			ind = map.getIndicator();
		}
	}

	// check global table object on charts page to see if there are any pins currently in it
	// this is used just for when trying to save a list of pins and no indicator is on.
	// For map page check map for pins.
	if (table && table.overlaysets && table.overlaysets.length > 0)
		pins = table.overlaysets;
	else if (map && map.getOverlaySets().length > 0)
		pins = map.getOverlaySets();

	return { place: place, ind: ind, pins: pins };
}

/**
* Implement a standard print dialog with templates.
* 
* @param template - String: analytics, chart, generic, map, report
* @param action - save, print, email
* @param data - Object. Used only for generic dialogs (i.e. results)
* 
* @return void
*/
function genericAlertDialog (object) {
	if (object.data == null) {
		data = new Object ();
		// Some defaults
		data.action = '';
		data.cancelButton = "Cancel";
		data.emailFrom = false;
		data.emailTo = false;
		data.emailMultiTo = false;
		data.emailToMessage = false;
		data.format = false;
		data.island = false;
		data.setName = false;
		data.okButton = "Save";
		data.orientation = false;
		data.print = false;
		data.printTemplate = 'PolicyMapMapPage';
		data.printType = '';
		data.checkForCustomBreaks = false;
	}
	data.template = object.template;
	if (object.action != null) {
		data.action = object.action;
	}
	// Analytics and maps share the same code, so analytics are down by maps
	if (data.template == 'chart') {
		var p = checkPlaceInd ();
		if (p.place && p.ind) {
			if (data.action == 'print') {
				var indicators = table.cube.getIndicators();
				var indicator = indicators[0];
				var periods = table.cube.getPeriods();
				var aPeriods = new String(periods).split(",");
				var period = aPeriods[0];
				var places = [];
				var predefined_places = [];
				var getplaces = table.cube.getPlaces();
				var stuff = "";
				var dataCount = 0;
				// Accrue places.
				for( var i = 0; i < getplaces.length; ++i ) {
					var place = getplaces[i];
					places.push(place);
					if(place.getType() != PPlaceType.CUSTOM && place.getType() != PPlaceType.POLYGON) {
						predefined_places.push(place);
					}
				}
				// Accrue data
				for( var i = 0; i < aPeriods.length; ++i ) {
					var year = aPeriods[i];
					for( var j = 0; j < getplaces.length; ++j ) {
						var place = getplaces[j];
						var value = cube.values[year][place.id][indicator.id];
						var color = '#' + cube.charts[0].ogColors[j%8].getColor();
						if( value == null) { // ignore n/a values.
							continue;
						}
						stuff += '&p_' + dataCount + '=' + encodeURIComponent(place.getLabel() + place.getDisplayState() + ' (' + place.getType().getName() + ')' )
						+ '&d_' + dataCount + '=' + encodeURIComponent(value)
						+ '&y_' + dataCount + '=' + year
						+ '&c_' + dataCount + '=' + encodeURIComponent(color);
						++dataCount;
					}
				} 
				var ticks = "";
				for(var i=0; i<chart.plotkitLayout.yticks.length; i++) {
					if( i>0 && chart.plotkitLayout.yticks[i][1] == chart.plotkitLayout.yticks[i-1][1]) {
						break;
					}
					ticks += chart.plotkitLayout.yticks[i][1].replace(/[^\d&^\.^\-]/g, '')+',';
				}
				ticks = "&ticks=" + encodeURIComponent(ticks.substr(0,ticks.length-1));
				// Chart colors are passed to the Java renderer in the order they fall in the
				// colorramp. This may not match the colors currently in the table. Replace the
				// colors in the table with the colorramp colors in order (so they match the chart).
				var originalTableHtml = document.getElementById("createTableHeader").innerHTML;
				var colorRegEx = /background\-color\: rgb\([0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}\)/;
				var colorMatch;
				var i = 0;
				while (originalTableHtml.match(colorRegEx)) {
					colorMatch = originalTableHtml.match(colorRegEx);
					originalTableHtml = originalTableHtml.replace(colorMatch, "background-color: #" + cube.charts[0].ogColors[i%8].getColor());
					i++;
				}
				var title = '?title=' + encodeURIComponent( indicator.getFullDisplayName() );
				var dataSize = "&ds=" + dataCount;
				var description = '&desc=' + encodeURIComponent( indicator.getDescription() );
				var tableTitle = '&tt=' + encodeURIComponent( indicator.getLabel() );
				var tableHtml = '&table=' + encodeURIComponent("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body><div id=\"createTableHeader\" style=\"width: 100%;\">" + originalTableHtml + "</div></body></html>");
				var sources = '&sources=' + encodeURIComponent(indicator.getSourceList());
				var aggregate = '&a=' + encodeURIComponent( table.calculateColumn( indicator, period ) );
				var dataType = '&dt=' + indicator.getMeasurement(); 
				var unit = '&ut=' + encodeURIComponent(indicator.unit);
				data.link = new PChartLink(predefined_places, indicators, periods, session2.data, custom_places, ppolygon);
				data.parms = 'http://BarChartPage/'
					+ title
					+ sources
					+ aggregate
					+ stuff
					+ ticks
					+ dataSize
					+ tableTitle
					+ tableHtml
					+ dataType
					+ description
					+ unit;
				data.header = "You will be notified once your table is available. It will also be saved to My PolicyMap.";
				data.format = true;
				data.print = true;
				if (PEnvironment.siteId == 1) {
					data.okButton = 'Print';
				}
				data.printTemplate = aPeriods.length > 1 ? 'TrendChartPage' : 'BarChartPage';
				data.name = data.link.name;
				data.okCallback = function() {
					return genericPrintCheck (data);
				};
		  } else if (data.action == 'save') {
				var places = [];
				var getplaces = table.cube.getPlaces();
				for (var i=0; i<getplaces.length; i++) {
					if (getplaces[i].getType() != PPlaceType.CUSTOM && getplaces[i].getType() != PPlaceType.POLYGON) {
						places.push(getplaces[i]);
					}
				}
				var indicators = table.cube.getIndicators();
				var periods = table.cube.getPeriods();
				data.header = 'Your chart will be saved to My PolicyMap.';
				data.link = new PChartLink(places, indicators, periods, session2.data, custom_places, ppolygon);
				data.name = data.link.name;
				data.okCallback = function() {
					return genericPrintCheck (data);
				};
	  	}
		} else {
			if (place && !ind) {
				data.warning = "To " + data.action + " a table, choose data above. To make a comparative table, add other locations and click GO.";
			} else if (!place && ind) {
				data.warning = "To " + data.action + " a table, add a location. To make a comparative table, add other locations and click GO.";
			} else if (!place && !ind) {
				data.warning = "To " + data.action + " a table, first add a location and choose data above. To make a comparative table, add other locations and click GO.";
			}
			data.okButton = null;
			data.cancelButton = "OK";
		}
	} else if (data.template == 'csv' && data.action == 'save') {
		var p = checkPlaceInd ();
		if (p.place && p.ind || p.pins) {
			// For tables page get the info from the cube object
			if (PEnvironment.pageName == 'tables') {
				var indicators = table.cube.getIndicators();
				var periods = table.cube.getPeriods();
				var getplaces = table.cube.getPlaces();
				var places = [];
				// Accrue places.
				for( var i = 0; i < getplaces.length; ++i ) {
					var place = getplaces[i];
					places.push( place );
				}
			}
			else {
				var indicators = [];
				var periods = [];
				if (p.ind) {
					indicators = [p.ind];
					periods = p.ind.getPeriods();
				}
				var places = [p.place];
			}
			data.link = new PChartLink(places, indicators, periods, session2.data, custom_places, ppolygon, "list");
			data.name = data.link.name;
			data.printTemplate = 'SiteList';
			data.printType = 'csv';
			data.okCallback = function() {
				return genericPrintCheck (data);
			};
		} else {
			if (place && !ind) {
				data.warning = "To save a table, choose data above. To make a comparative table, add other locations and click GO.";
			} else if (!place && ind) {
				data.warning = "To save a table, add a location. To make a comparative table, add other locations and click GO.";
			} else if (!place && !ind) {
				data.warning = "To save a table, first add a location and choose data above. To make a comparative table, add other locations and click GO.";
			}
			data.okButton = null;
			data.cancelButton = "OK";
		}
	} else if (data.template == 'ranks' && data.action == 'print') {
		// Ranking box print.
		var p = checkPlaceInd();
		// Get the info on the table as a whole from the cube object.
		// This is needed to create the link for My PolicyMap.
		var indicators = table.cube.getIndicators();
		var periods = table.cube.getPeriods();
		var getplaces = table.cube.getPlaces();
		var places = [];
		// Accrue places.
		for(var i=0; i<getplaces.length; ++i) {
			var place = getplaces[i];
			places.push(place);
		}
		data.link = new PChartLink(places, indicators, periods, session2.data, custom_places, ppolygon, "ranks");
		data.name = data.link.name;
		data.printTemplate = 'RankingBoxPage';
		// Set the options for this print dialog.
		data.header = "You will be notified once your ranking print is available. It will also be saved to My PolicyMap.";
		data.format = true;
		data.print = true;
		data.okButton = "Print";
		// Put together the parameters specific to the ranking box print generation.
		var indicator = "?ind=" + rRanks.ind.getID();
		var period = "&per=" + rRanks.period;
		var place = "&p=" + rRanks.place.getID();
		var placeType = "&pt=" + rRanks.place.getType().getPluralName();
		var displayName = "&dn=" + rRanks.ind.fullDisplayNames[rRanks.ind.curPerIndex];
		var source = "&s=" + rRanks.ind.getSourceList();
		data.parms = 'http://RankingBoxPage/'
			+ indicator
			+ period
			+ place
			+ placeType
			+ displayName
			+ source;
		data.okCallback = function() {
			return genericPrintCheck(data);
		};
	} else if (data.template == 'generic') {
		data.cancelButton = "OK";
		data.print = false;
		data.island = false;
		data.emailFrom = false;
		data.emailTo = false;
		data.emailMultiTo = false;
		data.emailToMessage = false;
		data.format = false;
		data.okButton = null;
		data.okCallback = null;
		data.orientation = false;
		data.name = null;
		data.checkForCustomBreaks = false;
	} else if ((data.template == 'map' || data.template == 'analytic') && data.action == 'email') {
		var good = true;
		var indicator = map.getIndicator();
		var period = session2.get("period");
		var legend = null;
		var indicators = [];
		if (PEnvironment.pageName == 'analytics') {
			for(var i=0; legend=map.getLegendMerger().getLegend(i); i++){
				if( legend.getIndicator() ) {
					indicators.push( [legend.getIndicator(),legend.getIndicator().getPeriod()] );
				}
			}
		} else if (indicator) { // assume map page
			indicators.push( [indicator,period] );
		}

		if (indicators.length)	{
			for( var i = 0; i < indicators.length; ++i ) {
				var ind = indicators[i][0];
				var per = indicators[i][1];
				var indid = ind.getID();
				var einds = [9633216, 9633236, 9633244, 9633249, 9633251, 9633212, 9633248, 9633247, 9633250, 9633243, 9633242, 9633234, 9633233, 9633231, 9633229, 9633239, 9633223, 9633219, 9633252, 9633253, 9633214, 9633213, 9633200, 9633232, 9633202, 9633203, 9633204, 9633205, 9633206, 9633207, 9633208, 9633215, 9633218, 9633220, 9633222, 9633225, 9633224, 9633235, 9633210, 9633201, 9633230, 9633211, 9633228, 9633227, 9633246, 9633241, 9633238, 9633237, 9633226, 9633217, 9633209, 9633240, 9633245, 9633221];
				var inh = false;
				for(var j=0; j<einds.length; j++) {
					if(einds[j] == indid) {
						inh = true;
						break;
					}
				}
				if (ind && per && ((ind.containsSource(/nielsen/i, true) && per != 2000)
						|| PMapLayer.UMTRANSIT.isOn()
						|| ind.containsSource(/boxwood means/i, true)
						|| ind.containsSource(/greatschools/i, true)
						|| inh == true)
				) {
					data.okButton = null;
					data.cancelButton = "OK";
					if(session2.get('cp')) {
						data.warning = "Currently maps with custom regions cannot be e-mailed.";
					} else {
						data.warning = "Currently maps and tables of proprietary data cannot be e-mailed.";
					}
					good = false;
					break;
				}
			}
		}
		if(session2.get('cp')) {
			data.okButton = null;
			data.cancelButton = "OK";
			data.warning = "Currently maps with custom regions cannot be e-mailed.";
			good = false;
		}

		if (good == true) {
			var f = function(cb) {
				if (PEnvironment.siteId == 1) {
					data.emailFromValue = 'policymap'; // This should be done via some configuration variable
				} else {
					data.emailFrom = true;
				}
				data.emailTo = true;
				data.emailMultiTo = true;
				data.emailToMessage = true;
				data.okButton = 'Send';
				data.printType = 'email';
				data.link = new PMapLink(cb);
				var centerPoint = map.getCenterLatLng();
				data.link.url += "&cx=" + centerPoint.x + "&cy=" + centerPoint.y;
				data.link.url += "&cz=" + map.getZoom();
				data.link.url += "&siteId=" + PEnvironment.siteId;
				data.okCallback = function() {
					if (session2.get('studentEmail') != null) { // This should be done via some configuration variable
						good = checkEmails (data.emailFromInput, true);
						if (good == false) {
							return false;
						}
						data.emailFromValue = data.emailFromInput.val();
					}
					good = checkEmails (data.emailToInput, true);
					if (good == false) {
						return false;
					}
					var emails = data.emailToInput.val();
					emails = emails.replace(/ /g, "");
					data.emails = emails.split(',');
					data.message = data.emailToMessageTextarea.val();
					return genericPrintCheck (data);
				};
				addAlerterContent(data);
			};
			// set to true so alert content will be added in callback
			data.checkForCustomBreaks = true;
			checkIfCustomBreaks(f);
		}
	} else if ((data.template == 'map' || data.template == 'analytic') && data.action == 'print') {
		var f = function(cb) {
			// An active place or custom region on the map is no longer required for a print.
			if(session2.get('cp')) {
				place = session2.get('cp');
			} else if(session2.get('place') && map.infoWindowType == "address") {
				place = session2.get('place');
			} else if(mapstates.currentplace && mapstates.currentplace.getType()) {
				place = mapstates.currentplace;
			}
			
			data.header = "You will be notified once your " + data.template + " is available. It will also be saved to My PolicyMap.";
			if (googleMap.showing)
				data.header += "<br /><br />Please note: aerials can not be printed, due to licensing restrictions. You will receive a shaded map only.";

			data.format = true;
			data.orientation = true;
			data.print = true;
			if (PEnvironment.siteId == 1) {
				data.okButton = 'Print';
			}
			data.link = new PMapLink(cb);
			data.name = data.link.name;
			if (data.template == 'map') {
				data.printTemplate = 'PolicyMapMapPage';
				if (session2.get("i") && (session2.get("p") || session2.get("cp"))) {
					data.island = true;
				}
			} else if (data.template == 'analytic') {
				data.printTemplate = 'PolicyMapAnalyticsPage';
			}
			data.okCallback = function() {
				return genericPrintCheck (data);
			};
			addAlerterContent(data);
		};
		// set to true so alert content will be added in callback
		data.checkForCustomBreaks = true;
		checkIfCustomBreaks(f);
	} else if ((data.template == 'map' || data.template == 'analytic') && data.action == 'save') {
		var f = function(cb) {
			var place = null;
			if (custom_place) {
				place = custom_place;
			} else if (session2.get('place') && map.infoWindowType == "address") {
				place = session2.get('place');
			} else if (mapstates.currentplace && mapstates.currentplace.getType()) {
				place = mapstates.currentplace;
			}
			
			data.printType = 'map';
			data.header = 'Your ' + data.template + ' will be saved to My PolicyMap.';
			data.link = new PMapLink(cb);
			data.name = data.link.name;
			data.okCallback = function () {
				return genericPrintCheck (data);
			};
			addAlerterContent(data);
		};
		// set to true so alert content will be added in callback
		data.checkForCustomBreaks = true;
		checkIfCustomBreaks(f);
	} else if (data.template == 'report' && data.action == 'print') {
		if (PAsync.activeRequests) {
			data.warning = 'Please wait until the report finishes loading before printing.';
			data.okButton = null;
			data.cancelButton = "OK";
		} else {
			data.link = new PReportLink();
			data.name = data.link.name;

			// hud and wells fargo report use a different template
			if (isCompTypeReport()) {
				data.parms = 'http://HudReportPage/?';
			} else {
				data.parms = 'http://ReportPage/?';
			}

			data.parms += "html=" + encodeURIComponent("<html>" + document.body.parentNode.innerHTML + "</html>");
			// Building map image link
			var mapParms= "";
			// Don't URI encode the key. It returns a second appended argument, and encoding
			// it leads the API to thinking that the encoded "&iv=" for the second argument
			// is part of the key. Neither argument contains any special characters, so it's ok.
			mapParms += "key=" + PWebUtil.getAuthKey();
			mapParms += "&lat=" + encodeURIComponent(map.getCenter().lat());
			mapParms += "&long=" + encodeURIComponent(map.getCenter().lng());
			mapParms += "&scale=" + encodeURIComponent(map.getScale());
			mapParms += "&imgwidth=" + encodeURIComponent($("#map").width());
			mapParms += "&imgheight=" + encodeURIComponent($("#map").height());

			// Retrieving layer information
			var mapLayers = map.getCurrentMapType().getMapLayers();
			if( mapLayers != null && mapLayers.length > 0 ){
				mapParms += "&layers=";
					for(var i=0; i<mapLayers.length; i++) {
						mapParms += encodeURIComponent(mapLayers[i].name + ",");
					}
				mapParms = mapParms.slice(0,-3); // remove encoded ,
			}
			// Retrieving boundary information
			var getParms = getUrlParams();
			if(getParms.cpid) {
				// Custom Boundary Report
				mapParms += "&cpid=" + getParms.cpid;
			} else {
				if(getParms.area == "polygon" || getParms.area == "pradius") {
					// Polygon report. Polygon info needs to be passed.
					mapParms += "&bid=" + getParms.bid + "&pname=" + encodeURIComponent(getParms.name) + "&plat=" + getParms.plat + "&plng=" + getParms.plng;
				}
				if(getParms.pid || (getParms.radius && getParms.location)) {
					var boundary = new Array(new Object());
					if(getParms.pid){
						mapParms += "&ps=";
						boundary[0].id = getParms.pid;
					} else if(getParms.radius && getParms.location) {
						mapParms += "&rs=";
						var locPoint = (new PMarker(map.radiuscenter)).getPoint();
						boundary[0].radius = getParms.radius;
						boundary[0].lat = locPoint.lat();
						boundary[0].lng = locPoint.lng();
					}
					// Set fill information
					boundary[0].f = new Object();
					boundary[0].f.r = 243;
					boundary[0].f.g = 161;
					boundary[0].f.b = 46;
					boundary[0].f.a = 178;
					mapParms += encodeURIComponent(serializeJSON(boundary));
				}
			}

			data.header = "You will be notified once your " + data.template + " is available. It will also be saved to My PolicyMap.";
			data.parms += "&mparms=" + encodeURIComponent(mapParms);

			data.print = true;
			data.printType = 'pdf';
			data.printTemplate = "ReportPage";

			// Add the map params from the hud and wells report and change the template since they use a different one
			if (isCompTypeReport()) {
				data.parms += "&hudparms=" + encodeURIComponent(currentReport.hudmaps);
				data.printTemplate = "HudReportPage";
			}

			if (PEnvironment.siteId == 1) {
				data.okButton = 'Print';
			}
			data.okCallback = function() {
				return genericPrintCheck (data);
			};
		}
	} else if (data.template == 'report' && data.action == 'save') {
		if (PAsync.activeRequests) {
			data.warning = 'Please wait until the report finishes loading before saving.';
			data.okButton = null;
			data.cancelButton = "OK";
		} else {
			data.header = 'Your report will be saved to PolicyMap';
	    data.link = new PReportLink();
	    data.name = data.link.name;
			data.okCallback = function() {
				return genericPrintCheck (data);
			};
		}
	} else if (data.template == 'mypolicymap' && data.action == 'shareregion') {
		data.cpid = object.cpid;
		data.regionname = object.regionname;
		data.emailTo = true;
		data.emailMultiTo = false;
		data.emailToMessage = true;
		data.header = 'Sharing a region allows you to send a region you have created to another PolicyMap subscriber. The subscriber will be notified via email and the region will appear in their My PolicyMap. To continue, please enter the email address of the PolicyMap subscriber you wish to share the following region with.<br /><br />Region: ' + data.regionname;

		data.okButton = "Send";
		data.okCallback = function() {
			good = checkEmails (data.emailToInput, true);
			if (good == false) {
				return false;
			}
			var emails = data.emailToInput.val();
			data.emails = emails.replace(/ /g, "");
			data.message = data.emailToMessageTextarea.val();

			var message = $('textarea[id=message]').val();
			var f = function(msg) {
				var alerter = new PAlerter2();
				alerter.popup(msg, null, null, "OK");
			};

			polycreator.sharePoly(data.cpid, data.regionname, data.emails, data.message, f);
			return;
		};
	} else if (data.template == 'mypolicymap' && data.action == 'rename') {
		// Used to rename items in My PolicyMap.
		data.setName = true;
		data.id = object.id;
		data.oldName = object.name;
		data.type = object.type;
		// Nice up the name for certain types.
		var niceType = data.type;
		if(niceType == "region") {
			niceType = "custom region";
			// Custom region names cannot exceed 64 characters.
			data.setNameLength = 64;
		} else if(niceType == "analyticslist") {
			niceType = "analytic list";
		} else if(niceType == "tablelist") {
			niceType = "table list";
		}
		data.header = 'Please enter a new name for this ' + niceType + '.';
		data.okButton = "Rename";
		
		var responseAlert = function(msg) {
			// If the response is "OK", the rename was successful.
			// We only display a message if there was a problem.
			if(msg == "OK") {
				// Update the item instantly in My PolicyMap.
				updateItemTitle(data.id, data.type, data.newName);
			} else {
				// Display the message returned.
				var alerter = new PAlerter2();
				alerter.popup(msg, null, null, "OK");
			}
		};
		
		data.okCallback = function() {
			// Called when the user clicks the 'Rename' button.
			data.newName = data.setNameInput.val();
			// Determine what it is we're renaming.
			// If it's not a region, then it's a link.
			if(data.type == "region") {
				polycreator.renamePoly(object.id, data.newName, responseAlert);
			} else {
				linkManager.renameLink(object.id, data.newName, responseAlert);
			}
			return;
		};
	}
	
	// if custom breaks are being saved/printed then the alerter content will be added in a callback and not here
	if(!data.checkForCustomBreaks) {
		addAlerterContent(data);
	}
}

function addAlerterContent(data) {
	var content = $('<div/>');
	content.attr ('id', 'alertDialogContent');
	
	// Eliminate the library-specific text from normal policymap
	if (PEnvironment.siteId == 1) {
		data.print = false;
	}
	// Eliminate normal policymap stuff from the library version
	if (PEnvironment.siteId != 1) {
		data.header = null;
	}
	if (data.warning != null) {
		data.header = data.warning + ((data.header) ? "<br/>" + data.header : "");
	}

	var theTable = $('<table/>');
	$(theTable).addClass('printDialogTable');

	if (data.header != null) {
		var tr = $('<tr/>');
		var td = $('<td/>');
		var headerTextSpan = $('<span/>');
		$(headerTextSpan).addClass('printDialogText');
		$(headerTextSpan).html(data.header);
		$(td).append(headerTextSpan);
		$(td).attr ('colSpan', '2');
		$(tr).append(td);
		$(theTable).append(tr);
	}

	if (data.name != null) {

		var tr = $('<tr/>');
		var td = $('<td/>');
		// Temporary hack to make it look good.
		var nameText = $('<span/>');
		$(nameText).addClass('printDialogHeader');
		$(nameText).text('Name: ');
		$(td).append(nameText);
		$(tr).append(td);

		td = $('<td/>');
		var dummySpan = $('<span/>');
		$(dummySpan).text(' ');
		$(td).append(dummySpan);

		var reportTitle = $('<span/>');
		$(reportTitle).addClass('printDialogText');
		$(reportTitle).attr({
			id: 'reportTitle'
		});
		$(reportTitle).text(data.name);
		$(td).append(reportTitle);

		var editTitleInput = $('<input/>');
		$(editTitleInput).addClass('changeSaveName');
		$(editTitleInput).attr({
			type: 'text',
			name: 'edit_report_title',
			id: 'editTitleInput',
			value: data.name
		});

		var setTitle = function (e) {
			var text = $(editTitleInput).val();
			$(reportTitle).text(text);
			$(reportTitle).show();
			$(editTitleSpan).show();
			$(editTitleInput).hide();
			e.stopPropagation();
			e.preventDefault();
			return false;
		};

		$(editTitleInput).bind('keyup', function (e) {
			if (e.keyCode == 13) {
				setTitle(e);
			}
		});

		$(editTitleInput).bind('focus', function() {
		  $(this).setCursorPosition($(this).val().length);
		});

		$(editTitleInput).bind('blur', function (e) {
			setTitle(e);
		});

		$(editTitleInput).hide();
		$(td).append(editTitleInput);

		// (change name)

		var editTitleSpan = $('<span/>');
		var openParen = $('<span/>');
		$(openParen).text (' (');
		$(editTitleSpan).append(openParen);

		var editTitleLink = $('<span/>');
		$(editTitleLink).addClass('pagelinks');
		$(editTitleLink).addClass('simulink');

		$(editTitleLink).text('change name');
		$(editTitleLink).click(function(e) {
			$(reportTitle).hide();
			$(editTitleSpan).hide();
			$(editTitleInput).show();
			$(editTitleInput).focus();
			e.stopPropagation();
			e.preventDefault();
			return false;
		});
		$(editTitleSpan).append(editTitleLink);

		var closeParen = $('<span/>');
		$(closeParen).text (')');
		$(editTitleSpan).append(closeParen);

		$(td).append(editTitleSpan);

		$(tr).append(td);
		$(theTable).append(tr);

	} else if (data.okText != null) {

		var tr = $('<tr/>');
		var td = $('<td/>');
		var okText = $('<span/>');
		$(okText).addClass('printDialogText');
		$(okText).html (data.okText);
		$(td).append(okText);
		$(td).attr('colSpan', '2');
		$(tr).append(td);
		$(theTable).append(tr);

	}
	
	if (data.setName == true) {
	
		var tr = $('<tr/>');
		var td = $('<td/>');
		var setNameSpan = $('<span/>');
		$(setNameSpan).addClass('printDialogText');
		$(setNameSpan).html('Name:');
		$(td).append(setNameSpan);
		$(tr).append(td);
		var br = $('<br/>');
		$(td).append (br);
		
		data.setNameInput = $('<input/>');
		$(data.setNameInput).attr({
			type: 'text',
			size: '40',
			id: 'setNameInput'
		});
		if(data.setNameLength) {
			$(data.setNameInput).attr('maxlength', data.setNameLength);
		}
		
		if(data.oldName != null) {
			$(data.setNameInput).val(data.oldName);
		}
		
		$(td).append(data.setNameInput);
		$(tr).append(td);
		$(theTable).append(tr);
	
	}
	
	if (data.emailFrom == true) {

		var fromAddress = "";
		var fromDisabled = false;
		if (session2.get('studentEmail') != null) {
			fromAddress = session2.get('studentEmail');
		} else {
			fromAddress = session2.get('libraryMailFrom');
			fromDisabled = true;
		}

		var tr = $('<tr/>');
		var td = $('<td/>');
		var emailFromSpan = $('<span/>');
		$(emailFromSpan).addClass('printDialogText');
		$(emailFromSpan).text('From: ');
		$(td).append(emailFromSpan);
		$(tr).append(td);
		var br = $('<br/>');
		$(td).append (br);

		data.emailFromInput = $('<input/>');
		$(data.emailFromInput).attr({
			type: 'text',
			size: '40',
			id: 'emailFromInput',
			value: fromAddress,
			disabled: fromDisabled
		});

		$(data.emailFromInput).bind('blur', function () {
			checkEmails (data.emailFromInput);
		});

		$(td).append(data.emailFromInput);
		$(tr).append(td);
		$(theTable).append(tr);
		
	}

	if (data.emailTo == true) {

		var tr = $('<tr/>');
		var td = $('<td/>');
		var emailToSpan = $('<span/>');
		$(emailToSpan).addClass('printDialogText');
		if(data.emailMultiTo) {
			$(emailToSpan).html('Email To:<br/>(Use commas to separate multiple addresses)');
		} else {
			$(emailToSpan).html('Email To:');
		}
		$(td).append(emailToSpan);
		$(tr).append(td);
		var br = $('<br/>');
		$(td).append (br);
		
		data.emailToInput = $('<input/>');
		$(data.emailToInput).attr({
			type: 'text',
			size: '40',
			id: 'emailToInput'
		});

		$(data.emailToInput).bind('blur', function () {
			checkEmails (data.emailToInput);
		});
		
		$(td).append(data.emailToInput);
		$(tr).append(td);
		$(theTable).append(tr);
		
	}

	if (data.emailToMessage == true) {

		var tr = $('<tr/>');
		var td = $('<td/>');
		var emailToMessageSpan = $('<span/>');
		$(emailToMessageSpan).addClass('printDialogText');
		var emailToMessageHTML = 'Message: (Optional) ';
		$(emailToMessageSpan).html(emailToMessageHTML);
		$(td).append(emailToMessageSpan);
		$(tr).append(td);
		var br = $('<br/>');
		$(td).append (br);

		data.emailToMessageTextarea = $('<textarea/>');
		$(data.emailToMessageTextarea).attr({
			cols: '40',
			rows: '5',
			id: 'emailToMessageTextarea'
		});

		$(data.emailToMessageTextarea).bind('keyup', function (e) {
			$(emailToMessageSpan).html(emailToMessageHTML + (data.emailToMessageTextarea.val()).length + ' characters');
		});

		$(td).append(data.emailToMessageTextarea);
		$(tr).append(td);
		$(theTable).append(tr);
		
	}

	if (data.format == true) {
		var pdfString = "PDF";
		var pngString = "High Resolution (PNG)";
		var jpgString = "Low Resolution (JPG)";
		// Chart prints don't come in low/high resolution. They're
		// the same image, just saved as either a JPG or PNG.
		if(data.template == 'chart' || data.template == 'ranks') {
			pngString = "PNG";
			jpgString = "JPG";
		}
		
		var tr = $('<tr/>');
		var td = $('<td/>');
		var format = $('<span/>');
		$(format).addClass('printDialogHeader');
		$(format).text('Format: ');
		td = $('<td/>');
		$(td).append(format);
		tr = $('<tr/>');
		$(tr).append(td);

		var formatSpan = $('<span/>');
		$(formatSpan).addClass('printDialogText');

		data.pdfInput = $('<input/>');
		$(data.pdfInput).attr ({
			id: 'pdfCheckbox',
			name: 'pdf',
			type: 'checkbox',
			checked: ''
		});
		$(data.pdfInput).attr ('name', 'pdf');
		$(data.pdfInput).attr ('type', 'checkbox');
		$(data.pdfInput).attr ('checked', '');
		var pdfLabel = $('<label/>');
		$(pdfLabel).append(data.pdfInput);
		var pdfText = document.createTextNode(pdfString);
		$(pdfLabel).append(pdfText);
		$(formatSpan).append(pdfLabel);
		$(formatSpan).append('<br />');
		
		data.pngInput = $('<input/>');
		$(data.pngInput).attr ({
			id: 'pngCheckbox',
			name: 'png',
			type: 'checkbox',
			checked: ''
		});
		var pngLabel = $('<label/>');
		$(pngLabel).append(data.pngInput);
		var pngText = document.createTextNode(pngString);
		$(pngLabel).append(pngText);
		$(formatSpan).append(pngLabel);
		$(formatSpan).append('<br />');
		
		data.jpgInput = $('<input/>');
		$(data.jpgInput).attr ({
			id: 'jpgCheckbox',
			name: 'jpg',
			type: 'checkbox',
			checked: ''
		});
		var jpgLabel = $('<label/>');
		$(jpgLabel).append(data.jpgInput);
		var jpgText = document.createTextNode(jpgString);
		$(jpgLabel).append(jpgText);
		$(formatSpan).append(jpgLabel);
		
		$(data.pdfInput).bind("click", function () {
			checkPrintFormat (data.pdfInput);
		});
		$(data.pngInput).bind("click", function () {
			checkPrintFormat (data.pdfInput);
		});
		$(data.jpgInput).bind("click", function () {
			checkPrintFormat (data.pdfInput);
		});
		td = $('<td/>');
		$(td).append(formatSpan);
		$(tr).append(td);
		$(theTable).append(tr);

	}

	if (data.format == true && data.orientation == true) {

		var tr = $('<tr/>');
		var td = $('<td/>');

		var orientation = $('<span/>');
		$(orientation).addClass('printDialogHeader');
		$(orientation).text('Orientation: ');
		$(td).append(orientation);
		$(tr).append(td);

		var orientationSpan = $('<span/>');
		$(orientationSpan).addClass('printDialogText');
		
		// Fucked up IE hack incoming...FIXME

//		var landscapeInput = $('<input/>');
//		$(landscapeInput).attr ('name', 'orientation');
//		$(landscapeInput).attr ('value', 'landscape');
//		$(landscapeInput).attr ('type', 'radio');
//		$(landscapeInput).attr ('checked', 'checked');
		var landscapeLabel = $('<label/>');
		$(landscapeLabel).html ("<input type='radio' name='orientation' value='landscape' checked>");
//		$("<input type='radio' name='orientation' value='landscape'>").prependTo(landscapeLabel);
//		$(landscapeLabel).append(landscapeInput);
		var landscapeText = document.createTextNode('Landscape');
		$(landscapeLabel).append(landscapeText);
		$(orientationSpan).append(landscapeLabel);

//		var portraitInput = $('<input/>');
//		$(portraitInput).attr ('name', 'orientation');
//		$(portraitInput).attr ('value', 'portrait');
//		$(portraitInput).attr ('type', 'radio');
		var portraitLabel = $('<label/>');
		$(portraitLabel).html ("<input type='radio' name='orientation' value='portrait'>");
//		$("<input type='radio' name='orientation' value='portrait'>").prependTo(portraitLabel);
//		$(portraitLabel).append(portraitInput);
		var portraitText = document.createTextNode('Portrait');
		$(portraitLabel).append(portraitText);
		$(orientationSpan).append(portraitLabel);

		td = $('<td/>');
		$(td).append(orientationSpan);
		$(tr).append(td);
		$(theTable).append(tr);

	}

	if (data.island == true) {

		var tr = $('<tr/>');
		var td = $('<td/>');

		var island = $('<span/>');
		$(island).addClass('printDialogHeader');
		$(island).text('Shading: ');
		$(td).append(island);
		$(tr).append(td);

		var islandSpan = $('<span/>');
		$(islandSpan).addClass('printDialogText');
		
		// Fucked up IE hack incoming...FIXME

//		var landscapeInput = $('<input/>');
//		$(landscapeInput).attr ('name', 'orientation');
//		$(landscapeInput).attr ('value', 'landscape');
//		$(landscapeInput).attr ('type', 'radio');
//		$(landscapeInput).attr ('checked', 'checked');
		var allLabel = $('<label/>');
		$(allLabel).html ("<input type='radio' name='island' value='' checked>");
//		$("<input type='radio' name='orientation' value='landscape'>").prependTo(landscapeLabel);
//		$(landscapeLabel).append(landscapeInput);
		var allText = document.createTextNode('Shade entire map');
		$(allLabel).append(allText);
		$(islandSpan).append(allLabel);
		var br = $('<br/>');
		$(islandSpan).append(br);

//		var portraitInput = $('<input/>');
//		$(portraitInput).attr ('name', 'orientation');
//		$(portraitInput).attr ('value', 'portrait');
//		$(portraitInput).attr ('type', 'radio');
		var islandLabel = $('<label/>');
		$(islandLabel).html ("<input type='radio' name='island' value='region'>");
//		$("<input type='radio' name='orientation' value='portrait'>").prependTo(portraitLabel);
//		$(portraitLabel).append(portraitInput);
		var islandText = document.createTextNode('Only shade selected region(s)');
		$(islandLabel).append(islandText);
		$(islandSpan).append(islandLabel);

		td = $('<td/>');
		$(td).append(islandSpan);
		$(tr).append(td);
		$(theTable).append(tr);

	}

	if (data.print == true) {
		var print = $('<span/>');
		$(print).addClass('printDialogHeader');
		$(print).text('Print: ');
		td = $('<td/>');
		$(td).append(print);
		tr = $('<tr/>');
		$(tr).append(td);

		var printCopy = $('<span/>');
		$(printCopy).addClass('printDialogText');
		$(printCopy).text('Click save and then go to ' + session2.get('libraryName') +
				' My Policymap and click the icon on the right of the title. Then, select print.');
		td = $('<td/>');
		$(td).append(printCopy);
		$(tr).append(td);
		$(theTable).append(tr);
	}

	content.append(theTable);

	var alerter = new PAlerter2();
	alerter.popup(
		content,
		null,
		null,
		data.cancelButton,
		data.okButton,
		data.okCallback,
		function() {
			content.remove();
		}
	);
}

// Save/Print custom breaks if they're on
function checkIfCustomBreaks(f) {
	var indicator = map.getIndicator();
	if (indicator) {
		var jsonbreaks = indicator.createCustomBreaksJSON(session2.get('nb') ? session2.get('nb') : DEFAULT_NUMBREAKS, true);
		if (jsonbreaks) {
			var obj = {};
			obj[indicator.id] = jsonbreaks;
			PAsync2.call(PEnvironment.stringstoreUrl + '?str=' + MochiKit.Base.serializeJSON(obj), f);
		} else {
			f();
		}
	} else {
		f();
	}
}

function isCompTypeReport() {
	if (currentReport.reportType == "hud" || currentReport.reportType == "wellsfargo") {
		return true;
	} else {
		return false;
	}
}

