function handleCutPoints(select) {
	if( isSubscriber() ) {
		map.getLegend().setNumberOfBreaks(parseInt(select.value));
		session2.put('nb',parseInt(select.value));
		widget.refresh();
	} else {
		for (var i=0;i<select.options.length;i++) {
			if (select.options[i].defaultSelected) {
				select.options[i].selected = true;
			}
			else {
				select.options[i].selected = false;
			}
		}
		subscribeAlert();
	}
}

function displayEditRangesPanel() {
	if(!isSubscriber()) {
		widget.getIndicatorBreaks().setEditMode(false);
		subscribeAlert();
	} else {
		widget.getIndicatorBreaks().setEditMode(true);
	}
	return false;
}

/***
 * Class: PIndicatorBreaks
 */
PIndicatorBreaks = function(legend, options) {
	this.legend = legend;
	this.instanceId = (options && options.instanceId != null)? options.instanceId : "";
	this.sessionId = this.instanceId + "breaks";
	this.editmode = false;

	this.eventTypes = new Object();
	this.eventTypes.refresh = 'refresh';
	this.eventTypes.clear = 'clear';
	this.eventManager = new PEventManager();

	this.refresh();
}

//PBreaksWidget Options
PIndicatorBreaks.EDITSTATE = new Object();
PIndicatorBreaks.EDITSTATE.nonSubscriber = 1;
PIndicatorBreaks.EDITSTATE.currentlyEditing = 2;
PIndicatorBreaks.EDITSTATE.alreadyEdited = 4;
PIndicatorBreaks.EDITSTATE.zoomInFurther = 8;
PIndicatorBreaks.EDITSTATE.exactBreaks = 16;
PIndicatorBreaks.EDITSTATE.noBoundaryType = 32;
PIndicatorBreaks.EDITSTATE.noData = 128;
var editState = 0;

PIndicatorBreaks.prototype = {
	
	addListener : function(eventId, f, c) {
		this.eventManager.addListener(eventId, f, c);
	},
	
	clear : function() {
		session2.remove(this.sessionId);
		this.eventManager.triggerListeners(this.eventTypes.clear);
	},

	setEditMode : function(mode) {
		this.editMode = mode;
		this.refresh();
	},
	
	restoreBreaks : function() {
		if(editState & PIndicatorBreaks.EDITSTATE.exactBreaks) {
			// These are exact breaks; all layers need to be turned back on.
			// Remove the 'legendind' session variable and then refresh.
			// This will cause the map to default to showing all layers again.
			session2.remove("legendind");
			this.setEditMode(false);
			this.refresh();
			map.refresh();
		} else {
			// Regular breaks.
			var numBreaks = this.legend.getNumberOfBreaks();
			this.legend.getIndicator().restoreBreaks(this.legend.getIndicator().getPeriod(),this.legend.getBoundaryType(),numBreaks);
			this.createBreaksSession();
			this.refresh();
		}
	},
	
	refresh : function() {
		if (this.legend.getIndicator()) {
			var ind = this.legend.getIndicator();
			var placetype = this.legend.getBoundaryType();
			var numBreaks = this.legend.getNumberOfBreaks();
		
			var colors = this.legend.getColors();
			var incrementValue = PWebUtil.getBreakIncrement(this.legend.getBreaks());
			var breaks = this.legend.getFormattedBreaks(incrementValue);
			var incrementBreaks = this.legend.getIncrementedBreaks(incrementValue);
			editState = 0;

			// restore defaults
			if(this.editMode)
				editState |= PIndicatorBreaks.EDITSTATE.currentlyEditing;
			if(!isSubscriber())
				editState |= PIndicatorBreaks.EDITSTATE.nonSubscriber;
			if(placetype && ind.hasCustomBreaks(ind.getPeriod(),placetype,numBreaks))
				editState |= PIndicatorBreaks.EDITSTATE.alreadyEdited;
			if(placetype == null)
				editState |= PIndicatorBreaks.EDITSTATE.noBoundaryType;
			if(ind.nodata)
				editState |= PIndicatorBreaks.EDITSTATE.noData;
			if(ind.breakid == P_BREAKTYPE_EXACT_VALUE_ID || ind.breakid == P_BREAKTYPE_EXACT_VALUE_CUSTOM_ID)
				editState |= PIndicatorBreaks.EDITSTATE.exactBreaks;
			
			// Check if this is an exact break dataset. If so, we need to determine if 'Insufficient
			// Data' exists as one of the layers and increment the number of breaks by one if it does.
			var numExactBreaks = 0;
			if(editState & PIndicatorBreaks.EDITSTATE.exactBreaks) {
				if(editState & PIndicatorBreaks.EDITSTATE.noData)
					numExactBreaks = numBreaks + 1;
				else
					numExactBreaks = numBreaks;
			}
			
			// Check for 'lind' in the session. If it exists, then we're drawing a map with exact break
			// indicators based on the arguments in a URL. Process argument and determine visible layers.
			if(session2.get("lind") != null) {
				var layersString = session2.get("lind");
				// Make sure the number of layers passed >= number of layers of the current
				// indicator. Otherwise we're just going to default to displaying all layers.
				if(layersString.length >= numExactBreaks) {
					var mvaLayers = [];
					// Prevent the defaults below from overriding the mvaLayers set here.
					session2.put("legendind", ind.getID());
					// Step through the argument and covert it to the usual boolean array.
					for(var i=0; i<layersString.length; i++) {
						// If other than a 0 or 1, then invalid; default ALL layers to be displayed.
						if(layersString.charAt(i) == "0")
							mvaLayers[i] = false;
						else if(layersString.charAt(i) == "1")
							mvaLayers[i] = true;
						else
							session2.remove("legendind");
					}
					// Store the selected layers in the session.
					session2.put("mvalayers", mvaLayers);
				} else
					session2.remove("legendind");
				// Remove 'lind' from the session so it doesn't get counted again.
				session2.remove("lind");
			}
			
			// Determine if this is a new indicator (either the first indicator because there isn't
			// currently one stored in the session yet, or the indicator has changed.)
			if(session2.get("legendind") == null || session2.get("legendind") != ind.getID()) {
				// New indicator. Store it in the session.
				session2.put("legendind", ind.getID());
				if(editState & PIndicatorBreaks.EDITSTATE.exactBreaks) {
					// If this is an exact break legend (MVA Dataset), default the
					// selected layers, as we're dealing with a new indicator.
					var mvaLayers = [];
					for(var i=0; i<numExactBreaks; i++)
						mvaLayers[i] = true;
					session2.put("mvalayers", mvaLayers);
				}
			}
			
			// Determine if exact breaks have been changed. If so, enable Restore Defaults link.
			if(editState & PIndicatorBreaks.EDITSTATE.exactBreaks) {
				var breaksChanged = false;
				var mvaLayers = session2.get("mvalayers");
				for(var i=0; i<numExactBreaks; i++) {
					if(!mvaLayers[i])
						breaksChanged = true;
				}
				if(breaksChanged)
					editState |= PIndicatorBreaks.EDITSTATE.alreadyEdited;
			}
			
			this.eventManager.triggerListeners(this.eventTypes.refresh, breaks, incrementBreaks, numBreaks, colors, this.legend);
		}
	},
	
	createBreaksSession : function() {
		var ind = this.legend.getIndicator();
		var breaksobj = ind.createCustomBreaksJSON();
		var obj = session2.get(this.sessionId);
		if (obj == null)
			obj = {};
		obj[ind.id] = breaksobj;
		session2.put(this.sessionId, obj);
	},
	
	applyCustomBreaks : function(allPeriods) {
		var numBreaks = this.legend.getNumberOfBreaks();
		if(editState & PIndicatorBreaks.EDITSTATE.exactBreaks) {
			// We're editing the breaks of an MVA dataset
			var mvaLayers = [];
			// If 'Insufficient Data' exists, we need to add one to the number of breaks.
			if(editState & PIndicatorBreaks.EDITSTATE.noData)
				numBreaks++;
			// Exact breaks indicates MVA dataset. Store the layers that are to be displayed on the map in an
			// array of booleans that corresponds to the layer's order in the list.
			for(var i=0; i<numBreaks; i++)
				mvaLayers[i] = $("input[id=breakbox" + i + "][type=checkbox]").attr('checked');
			// Store the selected layers in the session so they are stored if the page changes.
			session2.put("mvalayers", mvaLayers);
			this.setEditMode(false);
			map.refresh();
		} else {
			// We're editing the breaks of a regular non-MVA dataset.
			var breaks = "";
			var curInd = this.legend.getIndicator();
			for(var i=0; i<numBreaks; i++) {
				var index;
				if(curInd.nodata) {
					index = i + 1;
				} else {
					index = i;
				}
				var rgx = /[^0-9\.-]/g;
				if(i == 0) {
					breaks = document.getElementById(this.instanceId + "breakbox" + index + "a").value.replace(rgx, "");
				}
				breaks += "," + document.getElementById(this.instanceId + "breakbox" + index + "b").value.replace(rgx, "");
			}
			if(allPeriods) {
				// Apply these custom breaks to all periods for the current indicator.
				curInd.setCustomBreaks(breaks, this.legend.getBoundaryType(), "all");
			} else {
				// Only apply these custom breaks to the current period for the current indicator.
				curInd.setCustomBreaks(breaks, this.legend.getBoundaryType());
			}
			this.createBreaksSession();
			this.setEditMode(false);
		}
	},
	
	checkBreakBoxes : function(id) {
		function getIncrement(dec) {
			if (dec == 0)
				return 1;
			else {
				var inc = "0.";
				for (var i=1; i<dec; i++)
					inc += "0";
				inc += "1";
				return Number(inc);
			}
		}
	
		var box = document.getElementById(id);
		var rgx = /[^0-9\.-]/g;
		var rgxNum = /[0-9]/g;
		var boxval = parseFloat(box.value.replace(rgx,""));
		var dec = PWebUtil.getDecimalPlaces(boxval);
		var inc = getIncrement(dec);
		var bordercolor = "1px solid #ff9900";
		var index = parseInt(id.charAt(id.length-2));
		var subindex = id.charAt(id.length-1);
		var unit = this.legend.getIndicator().unit;
		if (subindex == 'a') {
			var boxBprev = document.getElementById("breakbox" + (index-1) + "b");
			if (boxBprev) {
				var checkdec = PWebUtil.getDecimalPlaces(boxBprev.value.replace(rgx,""));
				if (checkdec > dec)
					dec = checkdec;
				var inc = getIncrement(dec);
				if (boxval.toString().match(rgxNum)) {
					var boxBprevval = boxval - inc;
					boxBprev.value = PWebUtil.formatNumber(boxBprevval, unit, dec);
					boxBprev.style.border = bordercolor;
					var boxAprev = document.getElementById("breakbox" + (index-1) + "a");
					var boxAprevval = parseFloat(boxAprev.value.replace(rgx,""));
					if (boxAprevval > boxBprevval) {
						boxAprev.value = PWebUtil.formatNumber(boxBprevval, unit, dec);
						this.checkBreakBoxes("breakbox" + (index-1) + "a");
					}
				} else
					boxval = parseFloat(boxBprev.value.replace(rgx,"")) + inc;
			} 
			var boxB = document.getElementById("breakbox" + index + "b");
			var boxBval = parseFloat(boxB.value.replace(rgx,""));
			if (boxval > boxBval) {
				boxB.value = PWebUtil.formatNumber(boxval, unit, dec);
				this.checkBreakBoxes("breakbox" + index + "b");
			}
			// check for first box with no value -- auto fill default
			if (!boxBprev && !boxval) {
				var breaks = this.legend.getBreaks();
				var breaksarr = breaks.split(",");
				var index = 0;
				if (this.legend.getIndicator().nodata)
					index = 1;
				boxval = breaksarr[index];
				dec = PWebUtil.getDecimalPlaces(boxB.value.replace(rgx,""));
			}
		} else if (subindex == 'b') {
			var boxAnext = document.getElementById("breakbox" + (index+1) + "a");
			if (boxAnext) {
				var checkdec = PWebUtil.getDecimalPlaces(boxAnext.value.replace(rgx,""));
				if (checkdec > dec)
					dec = checkdec;
				var inc = getIncrement(dec);
				if (boxval.toString().match(rgxNum)) {
					var boxAnextval = boxval + inc;
					boxAnext.value = PWebUtil.formatNumber(boxAnextval, unit, dec);
					boxAnext.style.border = bordercolor;
					var boxBnext = document.getElementById("breakbox" + (index+1) + "b");
					var boxBnextval = parseFloat(boxBnext.value.replace(rgx,""));
					if (boxBnextval < boxAnextval) {
						boxBnext.value = PWebUtil.formatNumber(boxAnextval, unit, dec);
						this.checkBreakBoxes("breakbox" + (index+1) + "b");
					}
				} else
					boxval = parseFloat(boxAnext.value.replace(rgx,"")) - inc;
			}
			var boxA = document.getElementById("breakbox" + index + "a");
			if (boxA) {
				var boxAval = parseFloat(boxA.value.replace(rgx,""));
				if (boxAval > boxval) {
					boxA.value = PWebUtil.formatNumber(boxval, unit, dec);
					this.checkBreakBoxes("breakbox" + index + "a");
				}
			}
			// check for last box with no value -- auto fill default
			if (!boxAnext && !boxval) {
				var breaks = this.legend.getBreaks();
				var breaksarr = breaks.split(",");
				boxval = breaksarr[breaksarr.length-1];
				dec = PWebUtil.getDecimalPlaces(boxA.value.replace(rgx,""));
			}
		}
		box.value = PWebUtil.formatNumber(boxval, unit, dec);
		box.style.border = bordercolor;
	}

}


/**
 * 
 */
PIndicatorToggle = function(legend, map, indLegend, options){
	this.legend = legend;
	this.map = map;
	this.indLegend = indLegend;
	this.instanceId = (options && options.instanceId != null)? options.instanceId : "";


	this.listeners = [];

	this.eventTypes = new Object();
	this.eventTypes.refresh = 'refresh';
	this.eventTypes.clear = 'clear';
	this.eventManager = new PEventManager();
}

PIndicatorToggle.YEAR = new Object();
PIndicatorToggle.YEAR.selectedYear = 1;
PIndicatorToggle.YEAR.availableYear = 2;
PIndicatorToggle.YEAR.mustSubscribe = 4;
PIndicatorToggle.YEAR.notAvailable = 8;
PIndicatorToggle.YEAR.projection = 16;

PIndicatorToggle.QUARTER = new Object();
PIndicatorToggle.QUARTER.selectedQuarter = 1;
PIndicatorToggle.QUARTER.availableQuarter = 2;

PIndicatorToggle.MONTH = new Object();
PIndicatorToggle.MONTH.selectedMonth = 1;
PIndicatorToggle.MONTH.availableMonth = 2;

PIndicatorToggle.INDICATOR = new Object();
PIndicatorToggle.INDICATOR.selectedIndicator = 1;

PIndicatorItemToggle = function(value, state, func, funcParams, title){
	this.value = value;
	this.state = state;
	this.func = func;
	this.funcParams = funcParams;
	this.title = title; /* optional */
}


PIndicatorToggle.prototype = {

	clear : function(){
		this.eventManager.triggerListeners(this.eventTypes.clear);
	},
	
	addListener : function(eventId, f, c) {
		this.eventManager.addListener(eventId, f, c);
	},
	
	refresh : function(){
		this.clear();
		
		var ind = this.legend.getIndicator();

		if( ind && !allowIndicator(ind) ) {

			this.indLegend.clear();
                        var alerter = new PAlerter();
                        var content = "You must be a subscriber to view this indicator.";
                        alerter.popup(content,null, null,"OK");

		} else if(ind) {
			var years = new Array();
			var quarters = new Array();
			var months = new Array();
			var indicators = new Array();

			// Sets the CURRENTYEAR variable to either 2009 or 2010 since claritas/nielsen data can now have either of those periods.
			setCurrentYear(ind);

			/** Create indicator year items **/
			// show 09 and 14 years
			if (ind.hasPeriod('2014') || ind.hasPeriod('2015')) {
			 	for (var i=2000; i<2007; i++)
					years.push( new PIndicatorItemToggle(i.toString(), this.getYearState(ind,i.toString()), this.selectYearFunction, {legend: this.legend, ind: ind, map: this.map, period: i.toString(), indLegend: this.indLegend } ));
			 	years.push( new PIndicatorItemToggle((CURRENTYEAR).toString(), this.getYearState(ind,(CURRENTYEAR).toString()) | PIndicatorToggle.YEAR.projection, this.selectYearFunction, {legend : this.legend, ind: ind, map: this.map, period: (CURRENTYEAR).toString(), indLegend: this.indLegend}) );
			 	years.push( new PIndicatorItemToggle((CURRENTYEAR+5).toString(), this.getYearState(ind,(CURRENTYEAR+5).toString()) | PIndicatorToggle.YEAR.projection, this.selectYearFunction, {legend : this.legend, ind: ind, map: this.map, period: (CURRENTYEAR+5).toString(), indLegend: this.indLegend}) );
			} else {
				// show 08 and 09 in legend
				for (var i=2000; i<2008; i++)
					years.push( new PIndicatorItemToggle(i.toString(), this.getYearState(ind,i.toString()), this.selectYearFunction, {legend: this.legend, ind: ind, map: this.map, period: i.toString(), indLegend: this.indLegend } ));

				years.push( new PIndicatorItemToggle('2008', this.getYearState(ind,"2008"), this.selectYearFunction, {legend: this.legend, ind: ind, map: this.map, period: "2008", indLegend: this.indLegend }) );

				if (ind.hasPeriod('2009') || ind.hasPeriod('2009q1') || ind.hasPeriod('2009-01') || ind.hasPeriod('2010') || ind.hasPeriod('2010q1') || ind.hasPeriod('2010-01') || ind.hasPeriod('2011') || ind.hasPeriod('2011-01') || ind.hasPeriod('2011q1') || ind.hasPeriod('2012')) {
					years.push( new PIndicatorItemToggle('2009', this.getYearState(ind,"2009"), this.selectYearFunction, {legend: this.legend, ind: ind, map: this.map, period: "2009", indLegend: this.indLegend }) );

					if (ind.hasPeriod('2010') || ind.hasPeriod('2010q1') || ind.hasPeriod('2010-01') || ind.hasPeriod('2011') || ind.hasPeriod('2011-01') || ind.hasPeriod('2011q1') || ind.hasPeriod('2012')) {
						years.push( new PIndicatorItemToggle('2010', this.getYearState(ind,"2010"), this.selectYearFunction, {legend: this.legend, ind: ind, map: this.map, period: "2010", indLegend: this.indLegend }) );
						if (ind.hasPeriod('2011') || ind.hasPeriod('2011-01') || ind.hasPeriod('2011q1'))
							years.push( new PIndicatorItemToggle('2011', this.getYearState(ind,"2011"), this.selectYearFunction, {legend: this.legend, ind: ind, map: this.map, period: "2011", indLegend: this.indLegend }) );
						if (ind.hasPeriod('2012'))
							years.push( new PIndicatorItemToggle('2012', this.getYearState(ind,"2012"), this.selectYearFunction, {legend: this.legend, ind: ind, map: this.map, period: "2012", indLegend: this.indLegend }) );
					}

					// assumes order of periods is most recent to older
					// check last period and if there's no 2000 period then remove 00 toggle
					var periods = ind.getPeriods();
					if (!periods[periods.length-1].match("2000"))
						years.shift();
				}
			}

			/** if indicator has quarters then create quarter items **/
			if (ind.getPeriod().match("q")) {

				// quarter buttons
				var q = ind.getPeriod().split("q");
				for (var i=1; i<5; i++) {
					var qLabel = "Q" + i;
					var period = q[0] + "q" + i;
					if (q[1] == i)
						quarters.push( new PIndicatorItemToggle(qLabel, PIndicatorToggle.QUARTER.selectedQuarter, null, null) );
					else if (ind.hasPeriod(period) && allowPeriod(ind,period))
						quarters.push( new PIndicatorItemToggle(qLabel, PIndicatorToggle.QUARTER.availableQuarter, this.selectQuarterFunction, {ind: ind, period: period, legend: this.legend, indLegend: this.indLegend, map: this.map}) );
					else
						quarters.push( new PIndicatorItemToggle(qLabel, 0, null, null) );
				}
			}
			else if (ind.getPeriod().match("-")) {
				var m = ind.getPeriod().split("-");
				var labels = ['J','F','M','A','M','J','J','A','S','O','N','D'];
				for (var i=1; i<13; i++) {
					var mLabel = labels[i-1];
					var z = "";
					if (i<10)
						z = "0";
					var period = m[0] + "-" + z + (i);
					if (m[1] == i)
						months.push( new PIndicatorItemToggle(mLabel, PIndicatorToggle.MONTH.selectedMonth, null, null) );
					else if (ind.hasPeriod(period) && allowPeriod(ind,period))
						months.push( new PIndicatorItemToggle(mLabel, PIndicatorToggle.MONTH.availableMonth, this.selectMonthFunction, {ind: ind, period: period, legend: this.legend, indLegend: this.indLegend, map: this.map}) );
					else
						months.push( new PIndicatorItemToggle(mLabel, 0, null, null) );
				}
			}

			// if there are other indicator types 
			if (this.indLegend.indicatorList) {

				this.indLegend.clearMeasurementLabels();
				// store all measurements
				for (var i=0; i<this.indLegend.indicatorList.length; i++) {
					var currentInd = this.indLegend.indicatorList[i];
					
					this.indLegend.storeMeasurementLabel(currentInd.measurement);
					
					var periods = currentInd.getPeriods();
					var indAllow = false;
					for (var j=0; j<periods.length; j++) {
						if (allowPeriod(currentInd, periods[j])) {
							indAllow = true;
							break;
						}
					}
		
					if (indAllow) {
						var value = this.indLegend.getMeasurementLabel(currentInd.measurement);
						var title = this.indLegend.getMeasurementLabel(currentInd.measurement, true);
						if (currentInd == ind)
							indicators.push( new PIndicatorItemToggle(value, PIndicatorToggle.INDICATOR.selectedIndicator, null, null, title) );
						else
							indicators.push( new PIndicatorItemToggle(value, 0, this.selectIndicatorFunction, {ind: currentInd, legend: this.legend, indLegend: this.indLegend}, title) );
					}
			
				}

			}

			this.eventManager.triggerListeners(this.eventTypes.refresh, years, quarters, indicators, months);
		}
	},
	
	getYearState : function(ind,period) {

		var state = PIndicatorToggle.YEAR.notAvailable; // default to not available
		// check year only (first 4 digits)
		if (ind.getPeriod().slice(0,4) == period)
			state = PIndicatorToggle.YEAR.selectedYear;
		else if (ind.hasYear(period) && allowPeriod(ind,period))
			state = PIndicatorToggle.YEAR.availableYear;
		else if (ind.hasYear(period) && ind.containsSource("Census and Nielsen"))
			state = PIndicatorToggle.YEAR.mustSubscribe;

		return state;
	},
	
	/** method called if year is selected, it is called within the context of the html element */
	selectYearFunction : function() {

		// has quarter - pick default
		if (!this.ind.hasPeriod(this.period)) {
			this.period = this.ind.getQuarter(this.period) || this.ind.getMonth(this.period);
			this.legend.unlockBoundaryType();
		}

		this.ind.setPeriod(this.period);
		global_period = this.period;

		/* kluge - should be hooked up to the event(specific to index page)  */
		if(this.map){
			jQuery('#maptitlebox').hide();
			jQuery('#moretitle').hide();
			document.getElementById("maptitle").innerHTML = createTitle(new PMapState(this.map.getCenter(),this.map.getZoom(),this.ind,null,null),true);
			showIndicatorDescriptionIfOn(this.ind);
			jQuery('#maptitlebox').fadeIn(2000);
		}
		closeCubeWindow();

		this.indLegend.refreshLegendThenCheckPlaceTypes();
		this.indLegend.indicatorChanged();

		if(PEnvironment.pageName == 'widget') {
			this.indLegend.refreshWidgetPopUpTable();
			refreshWidgetCharts();
		}
	},
	
	/** method called if quarter is selected, it is called within the context of the html element **/
	selectQuarterFunction : function() {

		this.ind.setPeriod(this.period);
		global_period = this.period;

		/* kluge - should be hooked up to the event(specific to index page)  */
		if(this.map){
			// refresh title
			jQuery('#maptitlebox').hide();
			jQuery('#moretitle').hide();
			document.getElementById("maptitle").innerHTML = createTitle(new PMapState(this.map.getCenter(),this.map.getZoom(),this.ind,null,null),true);
			showIndicatorDescriptionIfOn(this.ind);
			jQuery('#maptitlebox').fadeIn(2000);
		}
		closeCubeWindow();

		this.indLegend.refreshLegendThenCheckPlaceTypes();
		this.indLegend.indicatorChanged();

		if(PEnvironment.pageName == 'widget') {
			this.indLegend.refreshWidgetPopUpTable();
			refreshWidgetCharts();
		}
	},
	
	/** method called if month is selected, it is called within the context of the html element **/
	selectMonthFunction : function() {

		this.ind.setPeriod(this.period);
		global_period = this.period;

		/* kluge - should be hooked up to the event(specific to index page)  */
		if(this.map){
			// refresh title
			jQuery('#maptitlebox').hide();
			jQuery('#moretitle').hide();
			document.getElementById("maptitle").innerHTML = createTitle(new PMapState(this.map.getCenter(),this.map.getZoom(),this.ind,null,null),true);
			showIndicatorDescriptionIfOn(this.ind);
			jQuery('#maptitlebox').fadeIn(2000);
		}
		closeCubeWindow();

		this.indLegend.refreshLegendThenCheckPlaceTypes();
		this.indLegend.indicatorChanged();

		if(PEnvironment.pageName == 'widget') {
			this.indLegend.refreshWidgetPopUpTable();
			refreshWidgetCharts();
		}
	},
	
	/** method called if different indicator is selected ,it is called within the context of the html element **/
	selectIndicatorFunction : function() {
		this.indLegend.setIndicatorList([this.ind], true);
		
		/* kluge - should be hooked up to the event(specific to index page) */
		if( this.map ){
			// refresh title
			jQuery('#maptitlebox').hide();
			jQuery('#moretitle').hide();
			document.getElementById("maptitle").innerHTML = createTitle(new PMapState(this.map.getCenter(),this.map.getZoom(),this.ind,null,null),true);
			showIndicatorDescriptionIfOn(this.ind);
			jQuery('#maptitlebox').fadeIn(2000);
			jQuery('#maptitlbox').animate({ backgroundColor: "orange" }, 1000);
		}
		closeCubeWindow();

		if(this.map)
			this.map.setIndicator(this.ind);
		this.indLegend.refresh();
		this.indLegend.indicatorChanged();

		if(PEnvironment.pageName == 'widget') {
			this.indLegend.refreshWidgetPopUpTable();
		}
	}
}

PIndicatorShade = function(legend, options){
	this.legend = legend;
	this.instanceId = (options && options.instanceId != null)? options.instanceId : "";
	this.disableDefault = (options && options.disableDefault != null)? options.disableDefault : false;
	this.sessionId = this.instanceId + "btds";
	this.oldBoundaryTypeId = 0;
	this.boundaryId = 0; // current boundary_id
	this.userBoundaryId = 0; // boundary_id set by the user
	
	this.eventTypes = new Object();
	this.eventTypes.clear = "clear";
	this.eventTypes.refresh = "refresh";
	this.eventTypes.change = "change";
	this.eventManager = new PEventManager();
}

PIndicatorShadeInfo = function(ind) {
	this.indicator = ind;
	this.shadeString = null;
	this.shadeItems = null;
};

PIndicatorShadeItem = function(id,selected,value){
	this.id = id;
	this.selected = selected;
	this.value = value;
	this.defaultSelected = false;
}


PIndicatorShade.prototype = {

	clear : function(){
		session2.remove(this.sessionId);
		this.setOldBoundaryTypeId(0);
		this.boundaryId = 0;
		this.userBoundaryId = 0;
		this.eventManager.triggerListeners(this.eventTypes.clear);
	},
	
	addListener : function(eventId, f, c) {
		this.eventManager.addListener(eventId, f, c);
	},
	
	setOldBoundaryTypeId : function(id) { 
		this.oldBoundaryTypeId = id; 
	},
	
	getOldBoundaryTypeId : function() { 
		return this.oldBoundaryTypeId; 
	},
	/***
	 * Changes the currently selected shade
	 */
	changeShade : function(boundaryId, useLockOption) {
		if( boundaryId == 0 && (this.legend.boundaryTypeIsLocked(this.legend.getIndicator().id) || this.legend.isBoundaryTypeSetToLockGlobally()) ) {
			this.legend.unlockBoundaryType();

			// The lock option is used just for widgets.
			// It's set to true for when the shade by drop down is used because that's when it should lock if it's suppose to.
			// It's not set when changeShade is called by changing the periods or indicators and the locked boundray type isn't available.
			if (this.legend.isBoundaryTypeSetToLockGlobally() && useLockOption) {
				this.legend.unlockBoundaryTypeGlobally(boundaryId);
			}
			else {
				var btds = ( session2.get( this.sessionId ) && session2.get( this.sessionId ).constructor == Object ) ? session2.get( this.sessionId ) : {};
				btds[ this.legend.getIndicator().id ] = null;
				session2.put( this.sessionId, btds );
			}
			this.update(this.legend.getIndicator());
			this.setOldBoundaryTypeId(boundaryId);
		}else if( this.legend.isValidBoundaryType( boundaryId ) || PEnvironment.pageName == 'analytics' || boundaryId == 0 ) {
			this.legend.lockBoundaryType();
			this.legend.setBoundaryType( boundaryId );

			// The lock option is used just for widgets.
			// It's set to true for when the shade by drop down is used because that's when it should lock if it's suppose to.
			// It's not set when changeShade is called by changing the periods or indicators and the locked boundray type isn't available.
			if (this.legend.isBoundaryTypeSetToLockGlobally() && useLockOption) {
				this.legend.lockBoundaryTypeGlobally(boundaryId);
			}
			else {
				var btds = ( session2.get( this.sessionId ) && session2.get( this.sessionId ).constructor == Object ) ? session2.get( this.sessionId ) : {};
				btds[ this.legend.getIndicator().id ] = boundaryId;
				session2.put( this.sessionId, btds );
			}
			this.setOldBoundaryTypeId(boundaryId);
			this.boundary_id = boundaryId;
		}
		this.userBoundaryId = boundaryId;
		this.eventManager.triggerListeners(this.eventTypes.change);
		loadDelayCheck();
	},
	
	/***
	 * Changes list of shades
	 */
	update : function(ind){
		if(ind){
			if(this.disableDefault)
				this.legend.lockBoundaryType()

			var shadeInfo = new PIndicatorShadeInfo(ind);

			if( this.legend.isPrerenderedBoundary() ) {
				shadeInfo.shadeString = this.legend.getBoundaryType().getName();
			} else {
				shadeInfo.shadeItems = [];
				var mapBoundTypes = PEnvironment.pageName != 'analytics' ? this.legend.getBoundaryTypes() : PPlaceTypeConfig.containmentOrder.slice().reverse();
				var indBoundTypes = orderPlaceTypes(ind.getPlaceTypes()).reverse();
				var uniqueBounds = {};
				var listDefault = false;

				// This return is needed because MVA indicators sometimes return null for getBoundaryType()
				// Could be to do with the boundary_definition_id, MVA's are using 33 where other indicators use 53(Not sure why)
				if (!this.legend.getBoundaryType())
					return;

				// Setup default boundary.  On initial load: 1.Session 2.ZoomDefault or if analytics (censustract or smallest).
				var prefBoundaryId = this.legend.getBoundaryType().id;
				if(PEnvironment.pageName == 'analytics'){
					if(jQuery.inArray(PPlaceType.CENSUSTRACT, indBoundTypes)>=0)
						prefBoundaryId = PPlaceType.CENSUSTRACT.id;
					else if(indBoundTypes.length > 0)
						prefBoundaryId = indBoundTypes[0].id;
				}
				// Set prefered boundary id to session var if it exists.
				var sessionBoundaryId = null;
				var btds = ( session2.get( this.sessionId ) && session2.get( this.sessionId ).constructor == Object ) ? session2.get( this.sessionId ) : {};
				var btd = session2.get(this.instanceId + 'btd' );

				session2.remove(this.instanceId + 'btd');

				// for widgets we can lock a boundary type for all the indicators
				// so check if that's the case for the widget and then get the boundary type that was locked instead of using sessions to get the type for each indicator
				if (PEnvironment.pageName == 'widget' && this.legend.isBoundaryTypeSetToLockGlobally() && this.legend.isValidBoundaryType(this.legend.getGloballyLockedType())) {
					sessionBoundaryId = this.legend.getGloballyLockedType();
				} else if( (btd && this.legend.isValidBoundaryType( btd )) || (btd && PEnvironment.pageName == 'analytics')) {
					btds[ind.id] = btd;
					session2.put( this.sessionId, btds );
					sessionBoundaryId = btd;
				} else {
					sessionBoundaryId = btds[ind.id];
				}

				if(sessionBoundaryId && parseInt(sessionBoundaryId) > 0){
					prefBoundaryId = sessionBoundaryId;
					this.legend.lockBoundaryType();
					this.legend.setBoundaryType( prefBoundaryId );
				}

				// i think this first if statement is only needed for analytics page now that each indicator on map page can be locked separately
				if(this.userBoundaryId > 0 && PEnvironment.pageName == 'analytics')
					prefBoundaryId = this.userBoundaryId;
				else if(this.boundaryId > 0 && PEnvironment.pageName == 'analytics')
					prefBoundaryId = this.boundaryId;

				this.boundaryId = 0;
				for( var i = 0; i < mapBoundTypes.length; ++i ) {
					for( var j = 0; j < indBoundTypes.length; ++j ) {
						if( mapBoundTypes[i].id == indBoundTypes[j].id ) {
							if( uniqueBounds[mapBoundTypes[i].id] || (PEnvironment.pageName == 'analytics' && indBoundTypes[j].id == 15 && indBoundTypes.length > 1))
								continue;
							var typeName = indBoundTypes[j].getName();

							// Adjustment to the placetype label because some are too long
							if (PEnvironment.pageName == 'widget' && (indBoundTypes[j] == PPlaceType.SLD_UPPER || indBoundTypes[j] == PPlaceType.SLD_LOWER))
								typeName = typeName.replace("District", "Dist");

							var newItem = new PIndicatorShadeItem(indBoundTypes[j].id, false, typeName);
							uniqueBounds[mapBoundTypes[i].id] = true;
							if( prefBoundaryId == indBoundTypes[j].id && (this.legend.isValidBoundaryType(indBoundTypes[j]) || PEnvironment.pageName == 'analytics')) {
								newItem.selected = true;
								newItem.defaultSelected = true;

								// if in sesssion then display a default option
								// or if the boundary is a locked one then show the default option
								if (btds[ind.id] || (this.legend.isBoundaryTypeSetToLockGlobally() && this.legend.getGloballyLockedType()))
									listDefault = true;

								this.legend.setBoundaryType(indBoundTypes[j]);
								this.boundaryId = newItem.id;
							}
							shadeInfo.shadeItems.push(newItem); 
							break; 
						}
					}
				}

				if(listDefault && this.disableDefault != true){
						shadeInfo.shadeItems[shadeInfo.shadeItems.length] =  new PIndicatorShadeItem(0, false, "Default");
				}else if(this.boundary_id == 0){
					for(var i=0; i<shadeInfo.shadeItems.length && this.boundaryId == 0; i++){
						var id = shadeInfo.shadeItems[i].id; 
						if( id != PPlaceType.CBSA_07.id && id != PPlaceType.COUNTY_SUBDIVISION.id && id != PPlaceType.CITY.id && id != PPlaceType.MD.id){
							this.legend.setBoundaryType(shadeInfo.shadeItems[i].id);
							this.boundaryId = shadeInfo.shadeItems[i].id;
							shadeInfo.shadeItems[i].selected = true;
						}
					}
					if(this.boundaryId == 0 && shadeInfo.shadeItems.length >0) {
						this.legend.setBoundaryType(shadeInfo.shadeItems[0].id);
						this.boundaryId = shadeInfo.shadeItems[0].id;
						shadeInfo.shadeItems[0].selected = true;
					}
				}
			}
		}
		this.eventManager.triggerListeners(this.eventTypes.refresh, shadeInfo);
	}
}

PIndicatorValues = function(legend, options) {
	this.legend = legend;
	this.instanceId = (options && options.instanceId != null)? options.instanceId : "";
	this.sessionId = this.instanceId + "v";
	
	this.values = null;
	this.eventManager = new PEventManager();
	this.eventTypes = {change: 'change', load: 'load', enable: 'enable', disable: 'disable'};
	// should get values from session and set them.
}

PIndicatorValues.prototype = {
	
	clear : function(){
		this.values = null;
		session2.remove(this.sessionId);
		this.eventManager.triggerListeners(this.eventTypes.clear);
		// remove values from session
	},
	
	load : function() {
		var ind = this.legend.getIndicator();
		if(ind.breakid == P_BREAKTYPE_EXACT_VALUE_ID || ind.breakid == P_BREAKTYPE_EXACT_VALUE_CUSTOM_ID){

			this.enable();
			var incrementValue = PWebUtil.getBreakIncrement(this.legend.getBreaks());
			var breaks = this.legend.getFormattedBreaks(incrementValue);
			
			var valOptions = [];
			if(session2.get(this.sessionId))
				valOptions = evalJSON(session2.get(this.sessionId));
			
			this.values = [];
			for(var i=(ind.nodata?1:0),j=0;i<breaks.length;i++,j++)
				this.values.push([breaks[i], (valOptions.length>j)?valOptions[j]:1]);

			this.eventManager.triggerListeners(this.eventTypes.load, this.values);
		}else{
			this.disable();
		}
	},
	
	toggleValues : function(values){
		this.values = values;
		session2.put(this.sessionId, serializeJSON(this.getValueOptions()));
		this.eventManager.triggerListeners(this.eventTypes.change);
	},
	
	addListener : function(eventId, f, c) {
		this.eventManager.addListener(eventId, f, c);
	},
	
	enable : function(){ 
		this.eventManager.triggerListeners(this.eventTypes.enable);
	},
	
	disable : function(){
		this.eventManager.triggerListeners(this.eventTypes.disable);
	},
	
	getValues : function(){
		return this.values;
	},
	
	getValueOptions : function(){
		var valOptions;
		if(this.values){
			valOptions = [];
			for(var i=0;i<this.values.length;i++)
				valOptions.push(this.values[i][1]);
		}
		return valOptions;
	}
}

/***
 * Class: PIndicatorRange
 */
PIndicatorRange = function(legend, map, options){
	this.legend = legend;
	this.map = map;
	this.instanceId = (options && options.instanceId != null)? options.instanceId : "";
	this.sessionId = this.instanceId + "r";
	
	this.range = null;
	this.min = null;
	this.max = null;
	this.userUnit = null;
	this.userRange = null;
	
	this.eventManager = new PEventManager();
	this.eventTypes = {change: 'change', refresh: 'refresh', enable: 'enable', disable: 'disable'}

	if(session2.get(this.sessionId+"0") && session2.get(this.sessionId+"1")) {
		this.range = [parseFloat(session2.get(this.sessionId+"0")), parseFloat(session2.get(this.sessionId+"1"))];
		this.setUserRange(this.range);
	}
}

PIndicatorRange.prototype = {

	clear : function(){
		this.range = null;
		this.min = null;
		this.max = null;
		this.userRange = null;
		this.userUnit = null;
		session2.remove(this.sessionId+"0");
		session2.remove(this.sessionId+"1");
	},

	getRange : function(){
		return this.range;
	},
	
	getFormattedRange : function(){
		var unit = (this.legend.getIndicator())?this.legend.getIndicator().unit:null;
		return [PWebUtil.formatNumber(this.range[0], unit), PWebUtil.formatNumber(this.range[1], unit)];
	},

	getLimits : function(){
		return [this.min, this.max];
	},
	
	addListener : function(eventId, f, c) {
		this.eventManager.addListener(eventId, f, c);
	},

	setRange : function(range){
		this.storeRange(range);
		this.setUserRange(range);
		this.eventManager.triggerListeners(this.eventTypes.change, range);
		loadDelayCheck();
	},
	
	setUserRange : function(range){
		var indicator = this.legend.getIndicator();
		if(indicator)
			this.userUnit = indicator.unit;
		this.userRange = new Array();
		this.userRange[0] = (range[0] == this.min)? null : range[0];
		this.userRange[1] = (range[1] == this.max)? null : range[1];
	},
	
	refresh : function(){
		var breaks = this.legend.getBreaks().split(",");
		var indicator = this.legend.getIndicator();
		if(indicator.breakid != P_BREAKTYPE_EXACT_VALUE_ID && indicator.breakid != P_BREAKTYPE_EXACT_VALUE_CUSTOM_ID) {
			this.enable();
			if(indicator != null && breaks.length > 0 && this.legend.getBoundaryType()){
				var range = [];
				range[0] = parseFloat((breaks[0] == indicator.nodata)? breaks[1] : breaks[0])
				range[1] = parseFloat(breaks[breaks.length-1]);
				var tMin = this.min;
				var tMax = this.max;
				this.min = range[0];
				this.max = range[1];
				
				if(this.range != null || ((range[0] != tMin || range[1] != tMax) && (tMin != null && tMax != null))){
					// if the current range is of the same unit, and it is within the new boundaries, then use it 
					if(this.userRange && (this.userUnit == indicator.unit || this.unit == null ) && ((this.userRange[0] > range[0] && this.userRange[0] < range[1]) || (this.userRange[1] > range[0] && this.userRange[1] < range[1]))){
						var tmpRange = new Array();
						 tmpRange[0] = (this.userRange[0] != null && this.userRange[0] > range[0] && this.userRange[0] < range[1]) ? this.userRange[0] : range[0];
						 tmpRange[1] = (this.userRange[1] != null && this.userRange[1] > range[0] && this.userRange[1] < range[1]) ? this.userRange[1] : range[1];
						 this.storeRange(tmpRange);
					}else{
						this.storeRange(range);
					}
				}
				else
					this.storeRange([this.min,this.max])
				this.eventManager.triggerListeners(this.eventTypes.refresh, [this.min, this.max], this.range, indicator.unit);
			}else{
				this.eventManager.triggerListeners(this.eventTypes.refresh, [null, null], [null, null], null);
			}
		}else{
			this.disable();
		}
	},
	
	storeRange : function(range) {
		this.range = new Array(range[0], range[1]);
		if(this.min != null && this.max != null && ( range[0] != this.min || range[1] != this.max )){
			session2.put(this.sessionId+"0", this.range[0]);
			session2.put(this.sessionId+"1", this.range[1]);
		}
	},

	enable : function(){
		this.eventManager.triggerListeners(this.eventTypes.enable);
	},

	disable : function(){
		this.eventManager.triggerListeners(this.eventTypes.disable);
	}
}

/***
 * Class: PTRFIndicatorLegend
 */
PTRFIndicatorLegend = function(map, legend, options) {
	this.map = map;
	this.legend = legend;
	options = options || new Object();
	this.instanceId = options.instanceId || "";
	this.hasIndicator = false;
	// set the instanceId for the PLegend so it can be used in PLegends getBoundaryType
	// don't set it for when the boundary type is being locked across the board because we don't need to store each indicator and it's boundary type when that's the case
	if (this.legend.isBoundaryTypeSetToLockGlobally())
		this.legend.instanceId = "";
	else
		this.legend.instanceId = options.instanceId || "";

	// This is used for when identify parameters are in url	
	// It turns false after map is loaded and identify is added
	this.firstLoad = true;
	
	this.eventTypes = new Object();
	this.eventTypes.clear = 'clear';
	this.eventTypes.init = 'init';
	this.eventTypes.refresh = 'refresh';
	this.eventTypes.changed = 'changed';
	this.eventManager = new PEventManager();
	
	// keep track of measurement types to avoid duplicate labels
	this.measurements = [];
	
	if(options.enableToggle){
		this.indicatorToggle = new PIndicatorToggle(this.legend, this.map, this, {instanceId: this.instanceId});
		this.addListener('refresh', this.indicatorToggle.refresh, this.indicatorToggle);
		this.addListener('clear', this.indicatorToggle.clear, this.indicatorToggle);
	}
	if(options.enableShade){
		this.indicatorShade = new PIndicatorShade(this.legend, {instanceId: this.instanceId});
		this.addListener('refresh', this.indicatorShade.update, this.indicatorShade);
		this.addListener('clear', this.indicatorShade.clear, this.indicatorShade);
		this.indicatorShade.addListener('change', this.refresh, this);
	}
	if(options.enableRange){
		this.indicatorRange = new PIndicatorRange(this.legend, this.map, {instanceId: this.instanceId});
		this.indicatorRange.addListener('change', this.indicatorChanged, this);
		this.addListener('refresh', this.indicatorRange.refresh, this.indicatorRange);
		this.addListener('clear', this.indicatorRange.clear, this.indicatorRange);

		this.indicatorValues = new PIndicatorValues(this.legend, {instanceId: this.instanceId});
		this.indicatorValues.addListener('change', this.indicatorChanged, this);
		this.addListener('clear', this.indicatorValues.clear, this.indicatorValues);
		this.addListener('refresh', this.indicatorValues.load, this.indicatorValues);
	}
	if(options.enableBreaks){
		this.indicatorBreaks = new PIndicatorBreaks(this.legend, {instanceId: this.instanceId});
		this.addListener('changed', this.indicatorBreaks.refresh, this.indicatorBreaks);
		this.addListener('refresh', this.indicatorBreaks.refresh, this.indicatorBreaks);
		this.addListener('clear', this.indicatorBreaks.clear, this.indicatorBreaks);
	}
}

PTRFIndicatorLegend.prototype = {

	init : function(){
		this.eventManager.triggerListeners(this.eventTypes.init);
	},
		
	clear : function() {
		this.clearMeasurementLabels();
		this.indicatorList = null;
		this.hasIndicator = false;
		this.legend.removeIndicator();
		session2.remove(this.instanceId + 'period');
		this.eventManager.triggerListeners(this.eventTypes.clear);
	},

	clearIndicatorList : function() {
		this.indicatorList = null;
	},
	
	getIndicator : function(){
		return this.legend.getIndicator();
	},
	
	addListener : function(eventId, f, c) {
		this.eventManager.addListener(eventId, f, c);
	},
	
	refresh : function() {
		var ind = this.legend.getIndicator();
		if (ind) {
			session.periods = ind.getPeriod();
			session2.put(this.instanceId + 'period', ind.getPeriod());
			this.eventManager.triggerListeners(this.eventTypes.refresh, ind);
		}
	},
	
	getIndicatorToggle : function(){
		return this.indicatorToggle;
	},
	
	getIndicatorBreaks : function(){
		return this.indicatorBreaks;
	},
	
	getIndicatorShade : function(){
		return this.indicatorShade;
	},
	
	getIndicatorRange : function(){
		return this.indicatorRange;
	},
	
	getIndicatorValues : function(){
		return this.indicatorValues;
	},
	
	containsIndicator : function(){
		return this.hasIndicator;
	},
	
	setIndicatorListByIds : function(ids,selected,fromlist) {

		// copy in case keeping arguments ref is bad.
		this.indicatorIds = ids;

		this.hasIndicator = true;
		var idsCsv = ids.join(',');

		var sIdParam = "";
		// This is used for widgets where we pass the site_id so we can get the download permissions for the indicator from its taxonomy.
		// If it's not set then the backend will use PolicyMaps site_id.
		if(PEnvironment.pageName == 'widget' && this.map.sid)
			sIdParam = "&sid="+this.map.sid;

		PAsync.call(PEnvironment.indicatorUrl + '?v=1.2&id='+idsCsv+sIdParam, this, function (inds) {
			// check if coming from list of indicators (which means menu)
			if (fromlist) {
				var l = inds.length;
				var mt;
				for (var i=0; i<l; i++) {
					mt = inds[i].measurement;
					if (mt && (mt == "percent" || mt == "rate")) {
						selected = i;
						break;
					}
				}
			}
			this.setIndicatorList(inds,null,selected);
		});
	},
	
	setIndicatorList : function(inds,noupdate,selected) {
		this.hasIndicator = true;
		if (!noupdate)
			this.indicatorList = inds;
		if (!selected)
			selected = 0;
		var ind = inds[selected];

		session2.put(this.instanceId+"i", ind.id);
		var period = session2.get(this.instanceId + 'period');
		if (!period || !ind.hasPeriod(period))
			period = ind.getPeriod();
		if (period != null && ind.hasPeriod(period) && allowPeriod(ind,period) && allowIndicator(ind)) {
			var sPeriod = session2.get(this.instanceId + 'period');
			// kluge to default Claritas indicator to 2009 instead of 2014
			if ((!sPeriod || !ind.hasPeriod(sPeriod)) && ind.containsSource(/nielsen/i, true) && ind.hasPeriod(CURRENTYEAR) && allowPeriod(ind,CURRENTYEAR))
				ind.setPeriod(CURRENTYEAR);
			else
				ind.setPeriod(period);
		}
		else if (ind.containsSource(/nielsen/i, true)) {
			if (ind.hasPeriod(CURRENTYEAR) && allowPeriod(ind,CURRENTYEAR))
				ind.setPeriod(CURRENTYEAR);
			else {
				var periodFound = false;
				for (var i=CURRENTYEAR-1; i>=2000; i--) {
					if (ind.hasPeriod(i)) {
						ind.setPeriod(i);
						periodFound = true;
						break;
					}
				}

	        	        if( !periodFound && !isSubscriber() ) {
        	        	        var alerter = new PAlerter();
	                        	var content = "This data is available only to subscribers.";
		                        alerter.popup(content,null, null,"OK");
        		                map.removeIndicator();
                		        jQuery('#maptitle').empty().text(ind.getFullDisplayName()).fadeIn('slow');
					ind = null;
		                }
			}
		}
		else if (!allowIndicator(ind)) {
        	        var alerter = new PAlerter();
	                var content = "This data is available only to subscribers.";
		        alerter.popup(content,null, null,"OK");
        		map.removeIndicator();
                	jQuery('#maptitle').empty().text(ind.getFullDisplayName()).fadeIn('slow');
			ind = null;
		}
		if( ind != null ) {
			var urlParams = getUrlParams();
			ind.setCustomBreaksByJSON(session2.get(this.instanceId + 'breaks'));
			var self = this;
			if (urlParams['cb']) {
				PAsync2.call(PEnvironment.stringstoreUrl + '?id=' + urlParams['cb'], function(breaks) {
					// get saved custombreaks and apply to indicator
					var jsonbreaks = MochiKit.Base.evalJSON(breaks);
					ind.setCustomBreaksByJSON(jsonbreaks);
	
					// save back to session
					var breaksobj = ind.createCustomBreaksJSON();
					var obj = session2.get(self.instanceId + 'breaks');
					if (obj == null)
						obj = {};
					obj[ind.id] = breaksobj;
					session2.put(self.instanceId + 'breaks', obj);
					self.legend.setIndicator(ind);
					self.refresh();

					// triggers identify if in url and only when map is first loaded
					if (urlParams['iwx'] && urlParams['iwy'] && urlParams['iwtype'] == 'identify' && this.firstLoad)
						PMIdentificationModule.showInfoWindow(urlParams);

					loadDelayCheck();
				});
			} else {
				this.legend.setIndicator(ind);
				
				// If this is an exact breaks indicator that only contains a blank layer or only
				// contains a blank layer after an Insufficient Data layer, then this is an
				// indicator that needs to be zoomed to a specific place first. In that case,
				// don't refresh the legend; we don't know the correct number of breaks yet, and
				// it will be refreshed when we zoom to the indicator's location after this.
				var incrementValue = PWebUtil.getBreakIncrement(this.legend.getBreaks());
				var breaks = this.legend.getFormattedBreaks(incrementValue);
				if(!((ind.breakid == P_BREAKTYPE_EXACT_VALUE_ID || ind.breakid == P_BREAKTYPE_EXACT_VALUE_CUSTOM_ID) && (breaks.length < 3 && breaks[breaks.length - 1] == "")))
					this.refresh();
				
				loadDelayCheck();
			}

			// triggers identify if in url and no customer breaks and only when map is first loaded
			if (urlParams['iwx'] && urlParams['iwy'] && urlParams['iwtype'] == 'identify' && !urlParams['cb'] && this.firstLoad) {
				PMIdentificationModule.showInfoWindow(urlParams);
			}
			this.firstLoad = false;
		}
	},
	
	indicatorChanged : function(){
		this.eventManager.triggerListeners(this.eventTypes.changed, this.legend.getIndicator());
	},
	
	storeMeasurementLabel : function(m) {
		if (!this.measurements[m])
			this.measurements[m] = 0;
		this.measurements[m]++;
	},
	
	getMeasurementLabel : function(m, full) {
		var retVal = getMeasurementLabel(m, full);
	
		// check for duplicate measurement types
		if (this.measurements && this.measurements[m] && this.measurements[m] > 1) {
			retVal += " ";
			if (full)
				retVal += "(Type ";
			retVal += this.measurements[m];
			if (full)
				retVal += ")";
		}
	
		return retVal;
	},
	
	clearMeasurementLabels : function(){
		this.measurements = [];
	}, 
	
	getName : function() {
		var curLeg = this.legend;
		var curInd = curLeg.getIndicator();
		
		var name = "";
		if( curInd && curLeg.getBoundaryType() && curLeg.isValidBoundaryType(curLeg.getBoundaryType(), true) ){
			name = "p_" + curInd.periodids[curInd.curPerIndex] + ".id_" + curInd.id; 
			if(this.indicatorRange){
				var range = this.indicatorRange.getRange();
				var values = this.indicatorValues.getValues();
				if(range && range.length > 1 && range[0] != null && !isNaN(range[0]) && range[1] != null && !isNaN(range[1])){
					name += ".br_" + range[0] + ":" + range[1];
					name += ".bd_" + curLeg.getBoundaryDefinitionID(curLeg.getBoundaryType().id);
				}else if(values){
					name += ".br_";
					var nd = 0;
					for(var i=0;i<values.length;i++){
						if(values[i][1]==1){
							name += values[i][0] + ":";
							nd++;
						}
					}
					name = name.replace(/:$/, "");
					name += ".bd_" + curLeg.getBoundaryDefinitionID(curLeg.getBoundaryType().id) + ":nd_" + nd;
					if(nd==0)
						name = "";
				}else
					name = "";
			}
			
		}
		return name
	},

	changeColorRamp : function(name) {
		this.legend.setColorRamp(PColorRampOptions[name].ramp);
		session2.put('rmp',name);
		this.refresh();
	},
	/**
	*  Used in SelectYearFunction, selectQuarterFunction, and selectMonthFunction.
	*  Checks if the placetype from previous period stuck because different periods can have different placetypes.
	*  Check the boundaryid before the legend is refreshed compared to after to see if the legend found the old id for the indicator and period
	*  if it didn't then the new one will equal 0 and so pass that to changeShade which will update the legend/map and shadeby again.
	*  Might be best to find where this can fit in PIndicatorShade.update() but couldn't get that too work, would save having to call changeShade twice
	**/
	refreshLegendThenCheckPlaceTypes : function() {
		var oldid = this.indicatorShade.boundaryId;
		this.refresh();
		var newid = this.indicatorShade.boundaryId;
		if (oldid != newid)
			this.indicatorShade.changeShade(newid);
	},
	// refreshes widget rankings and text-only version table
	refreshWidgetPopUpTable : function() {
		if (map.widgetRankingsOn)
			refreshWidgetRankings();
		if (textOnlyIsOn) {
			refreshWidgetCube();
		}
	}
}

PLegendMerger = function(map){
	this.map = map;
	/* kluge -- the map indicator is setup similar.  if it is attached to the layer then it sends its info the server at render time.*/
	this.map.kamap.getCurrentMap().aLayers[0].legendMerger = this;
	this.indicatorLegends = new Array();
}

PLegendMerger.prototype = {

	addLegend : function(legend){
		this.indicatorLegends.push(legend);
		legend.addListener('changed', this.indicatorChanged, this);
},

	clearIndicator : function(index) {
		session2.remove("m"+index+"i");
		this.indicatorLegends[index].clear();
		this.indicatorChanged();
		// If the user is stepping through the Analytics wizard and removes an
		// indicator part-way through the process, we need to step back in the
		// wizard to the applicable step so they can re-add one.
		if(typeof wiz != 'undefined' && wiz != null) {
			if(wiz.step > 2 && wiz.step != 7 && this.getIndicatorCount() == 0) {
				wiz.hideAllArrows();
				wiz.hideAllSteps();
				wiz.step = 1;
				wiz.next();
			} else if(wiz.step > 3 && wiz.step != 7 && this.getIndicatorCount() < 2) {
				wiz.hideAllArrows();
				wiz.hideAllSteps();
				wiz.step = 3;
				wiz.next();
			}
		}
	},
	
	getIndicatorCount : function(){
		var count = 0;
		for(var i=0;i<this.indicatorLegends.length;i++)
			if(this.indicatorLegends[i].containsIndicator() == true)
				count++;
		return count;
	},
	
	addIndicator : function(indarr, selected, fromlist, prefLegend){
		var found = -1;
		if(this.getIndicatorCount() < this.indicatorLegends.length){
			if(prefLegend != null && this.indicatorLegends[prefLegend].containsIndicator() == false){
				this.indicatorLegends[prefLegend].setIndicatorListByIds(indarr, selected, fromlist);
				found = prefLegend;
			}else{
				// find empty indicatorLegend and set it up
				for(var i=0;i<this.indicatorLegends.length && found == -1;i++){
					if(this.indicatorLegends[i].containsIndicator() == false){
						this.indicatorLegends[i].setIndicatorListByIds(indarr, selected, fromlist);
						found = i;
					}
				} 
			}
		} else {
			var alerter = new PAlerter();
			var content = "You can only have a maximum of " + this.indicatorLegends.length + " indicators at once.  Please remove one if you wish to add another.";
			alerter.popup(content,null, null,"OK");
		}
		return found;
	},
	
	getLegend : function(index){
		if(index == null && this.indicatorLegends.length > 0)
			return this.indicatorLegends;
		else if(this.indicatorLegends.length == 0 || index >= this.indicatorLegends.length)
			return null;
		else
			return this.indicatorLegends[index];
	},
	
	getName : function(){
		var name = "";
		if(this.getIndicatorCount() > 0 ){
			var name = "mt(5D4770,BFBFBF";
			for(var i=0;i<this.indicatorLegends.length;i++){
				if(this.indicatorLegends[i].getIndicator()){
					var n = this.indicatorLegends[i].getName();
					if(n!=""){
						name += "," + n;
					}else{
						name = "";
						break;
					}
				}
			}
		}
		return name.length > 0 ? name + ")" : "";
	},
	
	indicatorChanged : function(ind){
		loadDelayCheck();
	}
}

