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() ) { 
		subscribeAlert(	function(){
			widget.getIndicatorBreaks().setEditMode(false);
		});
	} 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 {
			// restoreBreaks as it previously existed. Used for all but exact 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() {
		var numBreaks = this.legend.getNumberOfBreaks();
		if(editState & PIndicatorBreaks.EDITSTATE.exactBreaks) {
			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 {
			// Non-MVA dataset. This is applyCustomBreaks as it previously existed before adding the
			// ability to add/remove exact breaks.
			var breaks = "";
			for (var i=0; i<numBreaks; i++) {
				var index;
				if (this.legend.getIndicator().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,"");
			}
			this.legend.getIndicator().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 pos = getAlertPosition(parseInt(alerter.box.style.width));
                        var content = "You must be a subscriber to view this indicator.";
                        alerter.popup(content,pos[0],pos[1],"OK");

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

			/** Create indicator year items **/
			// show 09 and 14 years
			if (ind.hasPeriod('2014')) {
			 	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')) {
					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'))
						years.push( new PIndicatorItemToggle('2010', this.getYearState(ind,"2010"), this.selectYearFunction, {legend: this.legend, ind: ind, map: this.map, period: "2010", 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.getSource() == "Census and Claritas")
			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);
			checkMore();
			jQuery('#maptitlebox').fadeIn(2000);
		}
		closeCubeWindow();

		this.indLegend.refreshLegendThenCheckPlaceTypes();
		this.indLegend.indicatorChanged();
	},
	
	/** 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);
			checkMore();
			jQuery('#maptitlebox').fadeIn(2000);
		}
		closeCubeWindow();

		this.indLegend.refreshLegendThenCheckPlaceTypes();
		this.indLegend.indicatorChanged();
	},
	
	/** 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);
			checkMore();
			jQuery('#maptitlebox').fadeIn(2000);
		}
		closeCubeWindow();

		this.indLegend.refreshLegendThenCheckPlaceTypes();
		this.indLegend.indicatorChanged();
	},
	
	/** 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);
			checkMore();
			jQuery('#maptitlebox').fadeIn(2000);
			jQuery('#maptitlbox').animate({ backgroundColor: "orange" }, 1000);
		}
		closeCubeWindow();

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

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(source, datadir){
	this.source = source;
	this.shadeString = null;
	this.shadeItems = null;
	this.dataDirectory = datadir;
	this.windowShadeString = 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) {
		if( boundaryId == 0 && this.legend.boundaryTypeIsLocked(this.legend.getIndicator().id) ) {
			this.legend.unlockBoundaryType();
			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 ) || PAGE_ID=="a_" || boundaryId == 0 ) {
			this.legend.lockBoundaryType();
			this.legend.setBoundaryType( boundaryId );
			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.source, ind.getDataDirectory());

			if( this.legend.isPrerenderedBoundary() ) {
				shadeInfo.shadeString = this.legend.getBoundaryType().getName();
			} else {
				shadeInfo.shadeItems = [];
				var mapBoundTypes = PAGE_ID!="a_" ? 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(PAGE_ID=="a_"){
					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');

				if( (btd && this.legend.isValidBoundaryType( btd )) || (btd && PAGE_ID=="a_")) {
					btds[ind.id] = btd;
					session2.put( this.sessionId, btds );
					sessionBoundaryId = btd;
				} else {
					sessionBoundaryId = btds[ind.id];
				}

				// For window widget the sessionBoundaryId should be what's set in the url and only for the indicator in the url
				// winwidgetbtds array is set in the setIndicatorListByIds function
				if (PAGE_ID == "w_" && this.winwidgetbtds) {
					sessionBoundaryId = this.winwidgetbtds[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 && PAGE_ID=="a_")
					prefBoundaryId = this.userBoundaryId;
				else if(this.boundaryId > 0 && PAGE_ID=="a_")
					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] || (PAGE_ID == "a_" && indBoundTypes[j].id == 15 && indBoundTypes.length > 1))
								continue;
							
							var newItem = new PIndicatorShadeItem(indBoundTypes[j].id, false, indBoundTypes[j].getName());
							uniqueBounds[mapBoundTypes[i].id] = true;
							if( prefBoundaryId == indBoundTypes[j].id && (this.legend.isValidBoundaryType(indBoundTypes[j]) || PAGE_ID=="a_")) {
								newItem.selected = true;
								newItem.defaultSelected = true;

								// if in sesssion then display a default option
								if (btds[ind.id])
									listDefault = true;

								this.legend.setBoundaryType(indBoundTypes[j]);
								this.boundaryId = newItem.id;

								// this will make the window widget show just the string of the placetype in the legend and not the dropdown
								if (PAGE_ID == "w_")
									shadeInfo.windowShadeString = indBoundTypes[j].getName();
							}
							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
	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;

		// For the window widget when 'btd' is in the url we need to store the ids and the btd
		// This is only for when the window widget is first loaded since we only want the indicator from the url and it's associated ids
		// These ids are looked for in the update function for PIndicatorShade where it freezes the boundary for all the ids
		if (PAGE_ID == "w_" && !this.indicatorShade.winwidgetbtds && session2.get('btd') && this.indicatorShade) {
			this.indicatorShade.winwidgetbtds = [];
			var btd = session2.get('btd');
			// Set winwidgetbtds so it can always be referred to when these ids are selected from the menu again
			for (var i=0; i<ids.length; i++)
				this.indicatorShade.winwidgetbtds[ids[i]] = btd;
		}

		this.hasIndicator = true;
		var idsCsv = ids.join(',');
	
		PAsync.call(PEnvironment.indicatorUrl + '/ind?v=1.2&id='+idsCsv, 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.source.match("Claritas") && ind.hasPeriod(CURRENTYEAR) && allowPeriod(ind,CURRENTYEAR))
				ind.setPeriod(CURRENTYEAR);
			else
				ind.setPeriod(period);
		}
		else if (ind.source.match("Claritas")) {
			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 pos = getAlertPosition(parseInt(alerter.box.style.width));
	                        	var content = "This data is available only to subscribers.";
		                        alerter.popup(content,pos[0],pos[1],"OK");
        		                map.removeIndicator();
                		        jQuery('#maptitle').empty().text(ind.getFullDisplayName()).fadeIn('slow');
					ind = null;
		                }
			}
		}
		else if (!allowIndicator(ind)) {
        	        var alerter = new PAlerter();
               	        var pos = getAlertPosition(parseInt(alerter.box.style.width));
	                var content = "This data is available only to subscribers.";
		        alerter.popup(content,pos[0],pos[1],"OK");
        		map.removeIndicator();
                	jQuery('#maptitle').empty().text(ind.getFullDisplayName()).fadeIn('slow');
			ind = null;
		}
		if( ind != null ) {
			var urlParams = PWebUtil.parseQuery(window.location.search);
			ind.setCustomBreaksByJSON(session2.get(this.instanceId + 'breaks'));
			var self = this;
			if (urlParams['cb']) {
				PAsync2.call(PEnvironment.pinUrl + '/servlet/stringstore?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]);
		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);
	}
}

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();
	},
	
	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 pos = getAlertPosition(parseInt(alerter.box.style.width));
			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,pos[0],pos[1],"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();
	}
}
