window.onload = function() {
	var xmlHttp;
	sahFeature.loadXML();
}

//replaces document.getElementById()
function $(el) {
	return document.getElementById(el);
}

function SahFeatureClass() {
	this.xmlDoc;
	this.xmlURL = "/files/newsroom/interactives/cdc/web-dataNew.xml"; // UPDATE RELATIVE URL
	this.natPage = "natPage";
	this.sbsPage = "sbsPage";
	this.currentPage = "p1";
	this.currentView = null;
	this.state1 = 1; // default to first state if not set
	this.state2 = null;
	this.state3 = null;
	this.isSafari = (navigator.userAgent.indexOf("Safari") != -1);
	this.notesObject = {};
	this.stateNameIDLookup = {"AL":"1","AK":"2","AZ":"3","AR":"4","CA":"5","CO":"6","CT":"7","DE":"8","DC":"9","FL":"10","GA":"11","HI":"12","ID":"13","IL":"14","IN":"15","IA":"16","KS":"17","KY":"18","LA":"19","ME":"20","MD":"21","MA":"22","MI":"23","MN":"24","MS":"25","MO":"26","MT":"27","NE":"28","NV":"29","NH":"30","NJ":"31","NM":"32","NY":"33","NC":"34","ND":"35","OH":"36","OK":"37","OR":"38","PA":"39","RI":"40","SC":"41","SD":"42","TN":"43","TX":"44","UT":"45","VT":"46","VA":"47","WA":"48","WV":"49","WI":"50","WY":"51"};
	this.sort = {};

}

// called once the xml document contents have been retrieved
SahFeatureClass.prototype.callback = function() {
	if (xmlHttp.readyState == 4) {
		if (xmlHttp.status == 200) {
			sahFeature.xmlDoc = xmlHttp.responseXML;
			sahFeature.init();
		}
	}
}

//access the xml via http so that we can traverse it using dom methods
SahFeatureClass.prototype.loadXML = function() {
	
	if (!this.isSafari) {
		sahFeature.setBackFunctionality();
	}

	if (window.XMLHttpRequest) { // Mozilla, Safari, ...
	    xmlHttp = new XMLHttpRequest();
	} else if (window.ActiveXObject) { // IE
	    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
	}
	xmlHttp.open("GET", this.xmlURL, true);
	xmlHttp.onreadystatechange = sahFeature.callback;
	xmlHttp.send(null);
}


// allow back button functionality without adding pages to history
SahFeatureClass.prototype.setBackFunctionality = function() {
	dhtmlHistory.initialize();
	dhtmlHistory.addListener(historyChange);
}

function historyChange(newLocation, historyData) {
	sahFeature.switchPage(sahFeature.natPage);
}

SahFeatureClass.prototype.goBack = function() {
	
	this.switchPage(this.natPage);
	
	/*if (sahFeature.isSafari) {
		this.switchPage(this.natPage);
	} else {
		history.go(-1);
	}*/

}

SahFeatureClass.prototype.formatValue = function(sVal, sFormatType) {
	
	if(!sFormatType) {return sVal;}
	
	if(!/percent|cost|price|value/i.test(sFormatType) || /[a-z]/gi.test(sVal)) {
		return sVal;
	}
	
	sVal = sVal + "";
	
	var x = sVal.split(".");
	var x1 = x[0];
	var x2 = (x.length > 1) ? "." + x[1] : "";
	var rgx = /(\d+)(\d{3})/;
	
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}

	sVal = (x1 + x2);
	
	return ((/percent/i.test(sFormatType)) ? sVal + "%" : (/cost|price/i.test(sFormatType)) ? "$" + sVal : sVal);
	
} 

//array sorting
SahFeatureClass.prototype.sortByField = function(arr, sSortCat, sortOrder) {
	
	function Sort(a, b) {
		
		if(sSortCat == "label")	 {
			if (a[sSortCat] < b[sSortCat]) return (sortOrder > 0) ? -1 : 1;
			if (a[sSortCat] > b[sSortCat]) return (sortOrder > 0) ? 1 : -1;
		} else {
			if (a.data[sSortCat].valueRaw == "N/A") {
				return 1;
			} else if (b.data[sSortCat].valueRaw == "N/A"){
				return -1;
			} else {
				if (a.data[sSortCat].valueRaw < b.data[sSortCat].valueRaw) return (sortOrder > 0) ? -1 : 1;
				if (a.data[sSortCat].valueRaw > b.data[sSortCat].valueRaw) return (sortOrder > 0) ? 1 : -1;
			}
		}

		return 0;

	}
	
	if (arguments.length < 2) return arr.sort();
	if (arguments.length < 3) sortOrder = 1;

	arr.sort(Sort);

	return arr;

}

SahFeatureClass.prototype.sortTable = function(el) {

	if(!el) {return;}
	
	var sSortField = el.getAttribute("sortfield");
	var sViewID = el.getAttribute("view");
	
	if(this.sort[sViewID].sortField == sSortField) {
		if (this.sort[sViewID].order == 1) {
			this.sort[sViewID].order = 0;
			this.sort[sViewID].sortClass = "sortDsc";
		} else {
			this.sort[sViewID].order = 1;
			this.sort[sViewID].sortClass = "sortAsc";
		}
	}
	
	this.sort[sViewID].sortField = sSortField;
	
	this.stateDataObject = this.sortByField(this.stateDataObject, this.sort[sViewID].sortField, this.sort[sViewID].order);
	
	this.drawNationalPage("p1",sViewID);

}


SahFeatureClass.prototype.buildHierObject = function() {
	
	var oHierObject = {
		pages:{}
	};
	
	var oDocEl = this.xmlDoc.getElementsByTagName("initiatives")[0];
	if (!oDocEl) { return; }
	var oHierNode = oDocEl.getElementsByTagName("hier")[0];
	var rHierMetricNodes = oHierNode.getElementsByTagName("hier-metric");
	
	var oItem, sPage, sView, sGroup, sCat;
	var sCurrentGroup = "";
	var nGroupIndex = 0;
	for(var i=0;i<rHierMetricNodes.length;i++) {
		oItem = rHierMetricNodes[i];
		sPage = oItem.getAttribute("ref.page");
		
		// if the page object does not exist, add it
		if(!oHierObject.pages[sPage]) {
			oHierObject.pages[sPage] = {};
		}

		sView = oItem.getAttribute("ref.view");
		if(!oHierObject.pages[sPage][sView]) {
			oHierObject.pages[sPage][sView] = {};
			nGroupIndex = 0;
			sCurrentGroup = "";
		}
		
		if(oItem.getAttribute("display")) {
			continue; //skip static views
		}

		sGroup = oItem.getAttribute("ref.group");
		if(!oHierObject.pages[sPage][sView].groups) {
			oHierObject.pages[sPage][sView].groups = [];
		}

		if(sCurrentGroup != sGroup) {
			oHierObject.pages[sPage][sView].groups.push({id:sGroup, cats:[]});
			sCurrentGroup = sGroup;
		};

		sCat = oItem.getAttribute("ref.cat");
		nGroupIndex = oHierObject.pages[sPage][sView].groups.length - 1;

		oHierObject.pages[sPage][sView].groups[nGroupIndex].cats.push(sCat);

	}

	return oHierObject;

}

SahFeatureClass.prototype.buildLookUpArray = function() {
	
	var lookups = {};
	var sID, sNoteID, rNotes;
	
	var oDocEl = this.xmlDoc.getElementsByTagName("initiatives")[0];
	var stateNodes = oDocEl.getElementsByTagName("states")[0].getElementsByTagName("state");
	var pageNodes = oDocEl.getElementsByTagName("pages")[0].getElementsByTagName("page");
	var viewNodes = oDocEl.getElementsByTagName("views")[0].getElementsByTagName("view");
	var groupNodes = oDocEl.getElementsByTagName("groups")[0].getElementsByTagName("group");
	var catNodes = oDocEl.getElementsByTagName("cats")[0].getElementsByTagName("cat");
	var noteNodes = oDocEl.getElementsByTagName("notes")[0].getElementsByTagName("note");

	lookups.states = {};
	lookups.pages = {};
	lookups.views = {};
	lookups.groups = {};
	lookups.cats = {};
	lookups.notes = {};

	for(var i=0;i<stateNodes.length;i++) {
		sID = stateNodes[i].getAttribute("state.id");
		lookups.states[sID] = {};
		lookups.states[sID].id = sID;
		lookups.states[sID].label = stateNodes[i].getAttribute("state.name");
		lookups.states[sID].description = stateNodes[i].getAttribute("state.description");
		lookups.states[sID].notes = [];
		sNoteID = stateNodes[i].getAttribute("ref.note");
		if(sNoteID) {
			sNoteID = sNoteID.replace(/^\s/,"");
			rNotes = sNoteID.split(" ");
			for(var n=0;n<rNotes.length;n++) {
				lookups.states[sID].notes.push(rNotes[n].replace(/\s/g,""));
			}
		}
	}

	for(var i=0;i<pageNodes.length;i++) {
		sID = pageNodes[i].getAttribute("page.id");
		lookups.pages[sID] = {};
		lookups.pages[sID].id = sID;
		lookups.pages[sID].label = pageNodes[i].getAttribute("page.label");
		lookups.pages[sID].description = pageNodes[i].getAttribute("page.description");
		lookups.pages[sID].template = pageNodes[i].getAttribute("page.template");
		lookups.pages[sID].notes = [];
		sNoteID = pageNodes[i].getAttribute("ref.note");
		if(sNoteID) {
			sNoteID = sNoteID.replace(/^\s/,"");
			rNotes = sNoteID.split(" ");
			for(var n=0;n<rNotes.length;n++) {
				lookups.pages[sID].notes.push(rNotes[n].replace(/\s/g,""));
			}
		}
	}

	for(var i=0;i<viewNodes.length;i++) {
		sID = viewNodes[i].getAttribute("view.id");
		lookups.views[sID] = {};
		lookups.views[sID].id = sID;
		lookups.views[sID].label = viewNodes[i].getAttribute("view.label");
		lookups.views[sID].description = viewNodes[i].getAttribute("view.description");
		lookups.views[sID].display = viewNodes[i].getAttribute("display");
		lookups.views[sID].notes = [];
		sNoteID = viewNodes[i].getAttribute("ref.note");
		if(sNoteID) {
			sNoteID = sNoteID.replace(/^\s/,"");
			rNotes = sNoteID.split(" ");
			for(var n=0;n<rNotes.length;n++) {
				lookups.views[sID].notes.push(rNotes[n].replace(/\s/g,""));
			}
		}
	}

	for(var i=0;i<groupNodes.length;i++) {
		sID = groupNodes[i].getAttribute("group.id");
		lookups.groups[sID] = {};
		lookups.groups[sID].id = sID;
		lookups.groups[sID].label = groupNodes[i].getAttribute("group.label");
		lookups.groups[sID].notes = [];
		sNoteID = groupNodes[i].getAttribute("ref.note");
		if(sNoteID) {
			sNoteID = sNoteID.replace(/^\s/,"");
			rNotes = sNoteID.split(" ");
			for(var n=0;n<rNotes.length;n++) {
				lookups.groups[sID].notes.push(rNotes[n].replace(/\s/g,""));
			}
		}
	}

	for(var i=0;i<catNodes.length;i++) {
		sID = catNodes[i].getAttribute("cat.id");
		lookups.cats[sID] = {};
		lookups.cats[sID].id = sID;
		lookups.cats[sID].label = catNodes[i].getAttribute("cat.label");
		lookups.cats[sID].notes = [];
		sNoteID = catNodes[i].getAttribute("ref.note");
		if(sNoteID) {
			sNoteID = sNoteID.replace(/^\s/,"");
			rNotes = sNoteID.split(" ");
			for(var n=0;n<rNotes.length;n++) {
				lookups.cats[sID].notes.push(rNotes[n].replace(/\s/g,""));
			}
		}
	}

	for(var i=0;i<noteNodes.length;i++) {
		sID = noteNodes[i].getAttribute("note.id");
		lookups.notes[sID] = {};
		lookups.notes[sID].id = sID;
		lookups.notes[sID].label = noteNodes[i].getAttribute("note.label");
		lookups.notes[sID].sign = noteNodes[i].getAttribute("note.sign");
	}

	return lookups;

}

SahFeatureClass.prototype.buildStateDataArray = function() {
	
	var rStateData = [];
	var oDocEl = this.xmlDoc.getElementsByTagName("initiatives")[0];
	var stateNodes = oDocEl.getElementsByTagName("state");
	
	var metricNodes, sCatID, sNoteID, rNotes, rChildNodes, oChildNode, nodeType, nodeValue, nodeName;
	
	for(var i=0;i<stateNodes.length;i++) {

		rStateData[i] = {};
		rStateData[i].id = stateNodes[i].getAttribute("state.id");
		rStateData[i].label = stateNodes[i].getAttribute("state.name");
		rStateData[i].data = {};
		
		metricNodes = stateNodes[i].getElementsByTagName("metric");

		for (var j=0;j<metricNodes.length;j++) {

			sCatID = metricNodes[j].getAttribute("ref.cat");

			// get value and type
			rChildNodes = metricNodes[j].childNodes;
			for(var c=0;c<rChildNodes.length;c++) {
				var oChildNode = rChildNodes[c];
				if (oChildNode.nodeType == 1) {
					nodeValue = oChildNode.firstChild.nodeValue;
					nodeName = oChildNode.nodeName;
					break;
				}
			}
			
			rStateData[i].data[sCatID] = {
				id:sCatID
				,type:nodeName
				,value:this.formatValue(nodeValue, nodeName)
				,valueRaw:nodeValue
			};
			
			sNoteID = metricNodes[j].getAttribute("ref.note");
			rStateData[i].data[sCatID].notes = [];
			
			if(sNoteID) {
				rNotes = sNoteID.split(" ");
				for(var n=0;n<rNotes.length;n++) {
					rStateData[i].data[sCatID].notes.push(rNotes[n].replace(/\s/g,""));
				}
			}
					
		}
		
	}

	return rStateData;	
	
}

SahFeatureClass.prototype.setStructure = function() {
	
	var oContainer = $("content");
	
	var sTemplate, oViewsContainer, oViewNoteContainer, oView, oTabContainer, oTabs, nCounter, oNoteContainer;
	
	var rPageNotes, oP;
	
	for (var sPageID in this.hierObject.pages) {

		sTemplate = this.lookupObject.pages[sPageID].template;
		oViewsContainer = $(sTemplate+"ViewContainer");

		if(!oViewsContainer) {
			alert("div#"+sTemplate+"ViewContainer element not found");
			return;
		}
		
		//get page tab container
		oTabContainer = $(sTemplate + "TabRow");
		oTabs = new Tabs(oTabContainer);
		
		//add page notes
		oNoteContainer = $(sTemplate + "NoteContainer");
		rPageNotes = this.lookupObject.pages[sPageID].notes;
		
		if (rPageNotes.length) {
			for(var i=0;i<rPageNotes.length;i++) {
				oP = document.createElement("p");
				oP.innerHTML = this.lookupObject.notes[rPageNotes[i]].label;
			}
			oNoteContainer.appendChild(oP);
		}

		//attach individual views
		nCounter = 0;
		for(var sViewID in this.hierObject.pages[sPageID]) {
			//add tab
			oTabs.add(this.lookupObject.views[sViewID].label, sTemplate, sViewID, ((nCounter == 0)?true:false), function() { sahFeature.switchViews(this);});
			
			oView = $(sTemplate + "View_" + sViewID);
			//create new view container if it doesn't already exist
			if(!oView) {
				oView = document.createElement("div");
				oView.setAttribute("id", sTemplate + "View_" + sViewID);
				oViewsContainer.appendChild(oView);
			}
			oView.className = (nCounter == 0) ? "" : "displayNone";

			this.drawViewDescriptions(sTemplate, sViewID);
			
			//add individual view notes containers to main note container;
				oViewNoteContainer = $(sViewID + "Notes");
				if(!oViewNoteContainer) {
					oViewNoteContainer = document.createElement("div");
					oViewNoteContainer.setAttribute("id", sViewID + "Notes");
					oViewNoteContainer.className = ((nCounter == 0) ? "" : "displayNone");
					oNoteContainer.appendChild(oViewNoteContainer);
				}
			
			//setup note storage
			this.notesObject[sViewID] = {};
			
			//add view notes
			if(this.lookupObject.views[sViewID].notes.length) {
				
				var rNotes = this.lookupObject.views[sViewID].notes;
				for(var i=0;i<rNotes.length;i++) {
					if(!this.notesObject[sViewID][rNotes[i]]) {
						this.notesObject[sViewID][rNotes[i]] = true;
					}
				}

			}

			//add group notes
			var rGroups = this.hierObject.pages[sPageID][sViewID].groups;
			
			 //static views don't have groups
			if(!rGroups) {
				nCounter++;
				continue;
			}

			for(var i=0;i<rGroups.length;i++) {

				var rNotes = this.lookupObject.groups[rGroups[i].id].notes;
				for(var n=0;n<rNotes.length;n++) {
					if(!this.notesObject[sViewID][rNotes[n]]) {
						this.notesObject[sViewID][rNotes[n]] = true;
					}
				}

				//add cat notes
				var rCats = rGroups[i].cats;
				for(var c=0;c<rCats.length;c++) {
					var rNotes = this.lookupObject.cats[rCats[c]].notes;
					for(var n=0;n<rNotes.length;n++) {
						if(!this.notesObject[sViewID][rNotes[n]]) {
							this.notesObject[sViewID][rNotes[n]] = true;
						}
					}
				}

			}

			nCounter++;
			
		}
		
		oTabs.render();
	}

	//draw national page data
	var sPageID = "";
	for (var sArg in this.hierObject.pages) {
		if (this.lookupObject.pages[sArg].template == this.natPage) {
			sPageID = sArg;
			break;
		}
	}
	
	//hide loading movie
	$("featureLoader").style.display = "none";
	
	
	for(var sViewID in this.hierObject.pages[sPageID]) {
		if(this.lookupObject.views[sViewID].display == "static") { continue;} //skip static views
		this.drawNationalPage(sPageID, sViewID);
	}
	
	this.drawNotes();

}

SahFeatureClass.prototype.switchPage = function(sPageTemplateID) {
	
	for(var sPageID in this.lookupObject.pages) {
		$(this.lookupObject.pages[sPageID].template).className = "displayNone";
	}
	$(sPageTemplateID).className = "";
	
	if(sPageTemplateID == this.sbsPage) {
		dhtmlHistory.add('1','');
		this.drawSbsPage();
	}

}

SahFeatureClass.prototype.switchViews = function(el) {
	
	var sViewContainerName = el.getAttribute("viewcontainer");
	var sViewID = el.getAttribute("view");

	var oUl = el;
	while(oUl.tagName.toLowerCase() != "ul") {
		oUl = oUl.parentNode;	
	}
	
	var rListItems = oUl.getElementsByTagName("li");

	for(var i=0;i<rListItems.length;i++) {
		rListItems[i].className = "";
	}
	
	var oClickedTab = $(el.parentNode.id);
	if(oClickedTab) {
		oClickedTab.className = "active";
	}
	
	var oMasterViewContainer = $(sViewContainerName).parentNode;
	var rViews = oMasterViewContainer.childNodes;

	for(var i=0;i<rViews.length;i++) {
		if(rViews[i].nodeType != 1) { continue; }
		rViews[i].className = "displayNone";
	}
	$(sViewContainerName).className = "";
	
	//swap active note container
	var oNoteContainer = $(sViewID + "Notes");
	
	if(oNoteContainer) {
		var oNoteContainerParent = oNoteContainer.parentNode;
		var rViewNoteContainers = oNoteContainerParent.getElementsByTagName("div");
		
		for(var i=0;i<rViewNoteContainers.length;i++) {
			rViewNoteContainers[i].className = "displayNone";
		}

		oNoteContainer.className = "";

	}
	
}

SahFeatureClass.prototype.drawViewDescriptions = function(sTemplate, sViewID) {
	
	if(this.lookupObject.views[sViewID].display == "static") { return; }
	
	var oViewDesc, sViewLabel, sViewDescription, oViewLabel, oViewDescription, sNoteSign;
	
	var oViewContainer = $(sTemplate + "View_" + sViewID);
	if(!oViewContainer) {alert("no view container found");return;}
	
	//view description
	oViewDesc = document.createElement("div");
	oViewDesc.className = "viewDesc";
	
	sNoteSign = this.appendNoteSigns(this.lookupObject.views[sViewID].notes);
	sViewLabel = this.lookupObject.views[sViewID].label + sNoteSign;
	sViewDescription = this.lookupObject.views[sViewID].description;
	
	if(sViewLabel && sViewLabel != "") {
		oViewLabel = document.createElement("h3");
		oViewLabel.innerHTML = sViewLabel;
		oViewDesc.appendChild(oViewLabel);
	}

	if(sViewDescription && sViewDescription != "") {
		oViewDescription = document.createElement("p");
		oViewDescription.innerHTML = sViewDescription;
		oViewDesc.appendChild(oViewDescription);
	}

	oViewContainer.appendChild(oViewDesc);
	
}

SahFeatureClass.prototype.appendNoteSigns = function(rNotes) {
	
	if(!rNotes || rNotes.constructor != Array) { return ""; }
	
	var rSigns = [];
	if (rNotes.length) {
		for(var i=0;i<rNotes.length;i++) {
			rSigns.push(this.lookupObject.notes[rNotes[i]].sign);
		}
	}

	return (rSigns.length) ? " [" + rSigns.join(",") + "]" : "";

}

SahFeatureClass.prototype.drawNationalPage = function(sPageID, sViewID) {

	var oPageData = this.hierObject.pages[sPageID];
	
	var oViewContainer = $(this.natPage + "View_" + sViewID);
	if(!oViewContainer) {alert("no view container found");return;}
	
	// if the table exists, first remove it
	var oDataContainer = $(this.natPage + "View_" + sViewID + "DataContainer");
	if(oDataContainer) {
		while (oDataContainer.childNodes.length) {
			oDataContainer.removeChild(oDataContainer.childNodes[0]);
		}
	} else {
		oDataContainer = document.createElement("div");
		oDataContainer.setAttribute("id", this.natPage + "View_" + sViewID + "DataContainer");
		oViewContainer.appendChild(oDataContainer);
	}
	
	//sorting parameters
	if(!this.sort.hasOwnProperty(sViewID)) {
		this.sort[sViewID] = {
			order:1
			,sortClass:"sortAsc"
			,sortField:"label"
		}
	}

	var oTable, oThead, oTbody, oTfoot, oTr, oTh, oTd, oA, sNoteSign,sCatID;
	
	oTable = document.createElement("table");
	oTable.className = "sahData";
	oTable.setAttribute("cellpadding",5);
	oTable.setAttribute("cellspacing",0);
	oTable.setAttribute("border",0);
	
	oThead = document.createElement("thead");
	oTbody = document.createElement("tbody");
	//oTfoot = document.createElement("tfoot");
	
	var rCats = [];
	
	for(var i=0;i<oPageData[sViewID].groups[0].cats.length;i++) {
		rCats.push(oPageData[sViewID].groups[0].cats[i]);
	}
	
	//draw thead
	oTr = document.createElement("tr");
	oTh = document.createElement("th");
	oTh.className = "col1A";
	oA = document.createElement("a");
	oA.setAttribute("id","label");
	oA.setAttribute("sortfield","label")
	oA.setAttribute("view",sViewID);
	oA.setAttribute("href","javascript:void(0)");
	oA.onclick = function() {sahFeature.sortTable(this);}
	oA.onfocus = function() {this.blur();}
	oA.className = (this.sort[sViewID].sortField == "label") ? this.sort[sViewID].sortClass : "blank";
	oA.innerHTML = "State";
	oTh.appendChild(oA);
	oTr.appendChild(oTh);

	for(var i=0;i<rCats.length;i++) {
		sCatID = rCats[i];
		oTh = document.createElement("th");
		oTh.className = "col" + (i+2) + "A";
		oA = document.createElement("a");
		oA.setAttribute("id",sCatID);
		oA.setAttribute("sortfield",sCatID);
		oA.setAttribute("href","javascript:void(0)");
		oA.onclick = function() {sahFeature.sortTable(this)}
		oA.setAttribute("view",sViewID);
		oA.onfocus = function() {this.blur()}
		oA.className = (this.sort[sViewID].sortField == sCatID) ? this.sort[sViewID].sortClass : "blank";
		//var cNum = parseInt(sCatID.substring(1))-1;
		sNoteSign = this.appendNoteSigns(this.lookupObject.cats[sCatID].notes);
		oA.innerHTML = this.lookupObject.cats[sCatID].label + sNoteSign;
		oTh.appendChild(oA);
		oTr.appendChild(oTh);
	}
	
	oThead.appendChild(oTr);	

	//draw tbody
	var sStateID, oNoteSignNode, sFormatType, sValueFormatted;
	for (var i=0;i<this.stateDataObject.length;i++) {
		sStateID = this.stateDataObject[i].id;
		sNoteSign = "";
		oNoteSignNode = [];
	
		oTr = document.createElement("tr");
		oTd = document.createElement("td");
        
	    if (i%2 == 0){
		    oTr.className = "oddRow";
	    }
	    
		oTd.className = "firstCol";
		sNoteSign = this.appendNoteSigns(this.lookupObject.states[sStateID].notes);
		oTd.innerHTML = '<b><a href="#" onclick="sahFeature.selectState(\'' + sStateID + '\'); return false">' + this.stateDataObject[i].label + '</a></b>' + sNoteSign;
		//oTd.innerHTML = '<b>' + this.stateDataObject[i].label + '</b>' + sNoteSign;
		oTr.appendChild(oTd);
		
		for(var j=0;j < rCats.length;j++) {
			oTd = document.createElement("td");
			sNoteSign = this.appendNoteSigns(this.stateDataObject[i].data[rCats[j]].notes);
			oTd.innerHTML = this.stateDataObject[i].data[rCats[j]].value + sNoteSign;
			oTr.appendChild(oTd);
		}
		
		oTbody.appendChild(oTr);
		
	}
	
	oTable.appendChild(oThead);
	oTable.appendChild(oTbody);
	//oTable.appendChild(oTfoot);
	
	oDataContainer.appendChild(oTable);
}

SahFeatureClass.prototype.drawSbsPage = function() {

	//draw sbs page data
	var sPageID = "";
	for (var sArg in this.hierObject.pages) {
		if (this.lookupObject.pages[sArg].template == this.sbsPage) {
			sPageID = sArg;
			break;
		}
	}
	
	this.populateStateRightCol();
	this.populateStateInfo();
	
	for(var sViewID in this.hierObject.pages[sPageID]) {
		if(this.lookupObject.views[sViewID].display == "static") { continue; }//skip static views
		this.drawSbsTable(sPageID, sViewID);
	}

}

SahFeatureClass.prototype.drawSbsTable = function(sPageID, sViewID) {

	var oPageData = this.hierObject.pages[sPageID];

	var oViewContainer = $(this.sbsPage + "View_" + sViewID);
	if(!oViewContainer) {alert("no view container found");return;}
	
	// if the table exists, first remove it
	var oDataContainer = $(this.sbsPage + "View_" + sViewID + "DataContainer");
	if(oDataContainer) {
		while (oDataContainer.childNodes.length) {
			oDataContainer.removeChild(oDataContainer.childNodes[0]);
		}
	} else {
		oDataContainer = document.createElement("div");
		oDataContainer.setAttribute("id", this.sbsPage + "View_" + sViewID + "DataContainer");
		oViewContainer.appendChild(oDataContainer);
	}
	
	var oTable, oThead, oTbody, oTfoot, oTr, oTh, oTd, oSelect, oOption, rCats, sNoteSign;

	oTable = document.createElement("table");
	oTable.className = "sahData";
	oTable.setAttribute("cellpadding",5);
	oTable.setAttribute("cellspacing",0);
	oTable.setAttribute("border",0);
	
	oThead = document.createElement("thead");
	oTbody = document.createElement("tbody");
	
	oTr = document.createElement("tr")
	oTh = document.createElement("th");
	oTh.className = "col1B";
	oTh.innerHTML = "&nbsp;";
	oTr.appendChild(oTh);
	
	oTh = document.createElement("th");
	oTh.className = "col2B";
	oTh.innerHTML = this.lookupObject.states[this.state1].label;
	oTr.appendChild(oTh);
	
	var ddElArr = [];
	for(var i=2;i<4;i++) {
		var tmpState = "state" + i;
		oTh = document.createElement("th");
		oTh.className = "col" + (i+1) + "B";
		oSelect = document.createElement("select");
		oSelect.setAttribute("id","ddState"+i+"_"+sViewID);
		oSelect.setAttribute("name","state"+i);
		oSelect.onchange = function() {sahFeature.updateSbsTable(this)};
		oOption = document.createElement("option");
		oOption.setAttribute("value","");
		oOption.innerHTML = "Compare to...";
		oSelect.appendChild(oOption);
		oTh.appendChild(oSelect);
		ddElArr.push(i);
		oTr.appendChild(oTh);
	}
	
	oThead.appendChild(oTr);
	
	for(var i=0;i<oPageData[sViewID].groups.length;i++) {
		oTr = document.createElement("tr");
		oTh = document.createElement("th");
		sNoteSign = this.appendNoteSigns(this.lookupObject.groups[oPageData[sViewID].groups[i].id].notes);
		oTh.innerHTML = "<br />" + this.lookupObject.groups[oPageData[sViewID].groups[i].id].label + sNoteSign;
		oTh.colSpan = 4;
		oTr.appendChild(oTh);
			/*for(var a=0;a<3;a++) {
				oTd = document.createElement("td");
				oTd.innerHTML = "--";
				oTr.appendChild(oTd);
			}*/
		oTbody.appendChild(oTr);

		rCats = oPageData[sViewID].groups[i].cats;
		for(var j=0;j<rCats.length;j++) {
			var sCatID = rCats[j];
			oTr2 = document.createElement("tr");
			oTd2 = document.createElement("td");
			oTd2.className = "firstCol2";
			sNoteSign = this.appendNoteSigns(this.lookupObject.cats[sCatID].notes);
			oTd2.innerHTML = this.getCatLabel(sCatID) + sNoteSign;
			oTr2.appendChild(oTd2);

			oTd2 = document.createElement("td");
			oTd2.innerHTML = this.stateDataObject[this.state1].data[rCats[j]].value + this.appendNoteSigns(this.stateDataObject[this.state1].data[rCats[j]].notes);
			oTr2.appendChild(oTd2);

			oTd2 = document.createElement("td");
			oTd2.innerHTML = (this.state2 && typeof(this.state2) != undefined) ? this.stateDataObject[this.state2].data[rCats[j]].value + this.appendNoteSigns(this.stateDataObject[this.state2].data[rCats[j]].notes) : "&nbsp;";
			oTr2.appendChild(oTd2);

			oTd2 = document.createElement("td");
			oTd2.innerHTML = (this.state3 && typeof(this.state3) != undefined) ? this.stateDataObject[this.state3].data[rCats[j]].value + this.appendNoteSigns(this.stateDataObject[this.state3].data[rCats[j]].notes) : "&nbsp;";
			oTr2.appendChild(oTd2);
			oTbody.appendChild(oTr2);
		}
	}

	oTable.appendChild(oThead);
	oTable.appendChild(oTbody);
	oDataContainer.appendChild(oTable);
	
	for(var i=0;i<ddElArr.length;i++) {
		this.buildStateDropDown("ddState"+ddElArr[i]+"_"+sViewID, this["state"+ddElArr[i]]);
	}
	
	//this.drawNotes("notes2");
	
}

SahFeatureClass.prototype.selectState = function(el) {
	inputType = typeof(el);
	if(inputType == "object") {
		if(el.selectedIndex == 0) {
			return false;
		}
		this.state1 = el.value || "AL";
	} else {
		this.state1 = el;
	}
	this.switchPage(this.sbsPage);	
	
}


//dynamically populate state select field
SahFeatureClass.prototype.buildStateDropDown = function(ddElement, selIndex) {

	var selIndex = selIndex || "";
	var oSelect = $(ddElement);

	var oOption;
	for(var i=0;i<this.stateDataObject.length;i++) {
		
		oOption = document.createElement("option");
		oOption.setAttribute("value", this.stateDataObject[i].id);
		if (this.stateDataObject[i].id == selIndex) {
			oOption.setAttribute("selected", "selected");
		}
		oOption.innerHTML = this.stateDataObject[i].label;
		oSelect.appendChild(oOption);

	}

}

SahFeatureClass.prototype.resetDropDown = function(ddElement) {
	$(ddElement).selectedIndex = 0;
}

//associate properties with array indexes for efficient lookups
SahFeatureClass.prototype.buildStateDataHashTable = function() {

	//stateData
	for(var i=0;i<this.stateDataObject.length;i++) {
		this.stateDataObject[this.stateDataObject[i].id] = this.stateDataObject[i];	
	}
}

SahFeatureClass.prototype.getCatLabel = function(nCatID) {
	
	return this.lookupObject.cats[nCatID].label;
	
	//TODO this function needs to be revisited
	/*var catNotes = [];
	var catNotesVal = "";
	var thisCat = this.lookupObject.cats[nCatID];
	if(thisCat.notes != null) {
		for(var i=0;i<thisCat.notes.length;i++) {
			catNotes.push(this.lookupObject.notes[thisCat.notes[i]].sign);
			this.notesObj[thisCat.notes[i]] = true;
		}
		catNotesVal = " <sup>[" + catNotes.join(',') + "]</sup>";
	}
	return thisCat.label + catNotesVal;*/

}

SahFeatureClass.prototype.getViewNotes = function(sViewID) {
	var tabNotes = [];
	if(this.lookupObject.views[sViewID].notes != null) {
		for(var i=0;i<this.lookupObject.views[sViewID].notes.length;i++) {
			tabNotes.push(this.lookupObject.notes[this.lookupObject.views[sViewID].notes[i]].sign);
			this.notesObj[this.lookupObject.views[sViewID].notes[i]] = true;
		}
		return " <span class='tabNote'>[" + tabNotes.join(',') + "]</span>";
	} else {
		return "";
	}
}

SahFeatureClass.prototype.getTabLabel = function(sViewID) {
	var sTabLabel = this.lookupObject.views[sViewID].label;
	var sTabNotesVal = this.getViewNotes(sViewID);
	sTabLabel += sTabNotesVal;
	return sTabLabel;
}

SahFeatureClass.prototype.drawNotes = function(noteDiv) {
	
	var rNotes, oDl, oDt, oDd;
	
	// draw notes for each view
	for (var sViewID in this.notesObject) {
		rNotes = [];
		oViewNoteContainer = $(sViewID + "Notes");
		
		oDl = document.createElement("dl");
		oDl.className = "hasLayout";
		
		//add note id's to an array so they can be ordered
		for(var sNoteID in this.notesObject[sViewID]) {
			rNotes.push(sNoteID);
		}
		rNotes.sort();

		for(var i=0;i<rNotes.length;i++) {
			oDt = document.createElement("dt");
			oDt.innerHTML = "[" + this.lookupObject.notes[rNotes[i]].sign + "]";
			oDd = document.createElement("dd");
			oDd.innerHTML = this.lookupObject.notes[rNotes[i]].label;
			
			oDl.appendChild(oDt);
			oDl.appendChild(oDd);
		}

		oViewNoteContainer.appendChild(oDl);

	}

}

SahFeatureClass.prototype.updateSbsTable = function(oSelectEl) {

	if(!oSelectEl || oSelectEl.value == "") {return;}
	
//TODO make sPageID dynamic
	var sPageID = "p2";
	var sSelectedValue = oSelectEl.value;
	this[oSelectEl.name] = sSelectedValue;
	
	//if this is the main select element, reset the selected index to 0 after each selection
	if (oSelectEl.name == "state1") {
		oSelectEl.selectedIndex = 0;
	}
	
	this.populateStateRightCol();
	this.populateStateInfo();
	
	for(var sViewID in this.hierObject.pages[sPageID]) {
		if(this.lookupObject.views[sViewID].display == "static") {continue;}
		this.drawSbsTable(sPageID, sViewID);
	}

}

SahFeatureClass.prototype.populateStateInfo = function() {

	//var rDatapoints = ["c1","c2","c3","c4"];

	var oContainer = $("stateInfo");
	while (oContainer.childNodes.length) {
		oContainer.removeChild(oContainer.childNodes[0]);
	}

	var oH3 = document.createElement("h3");
	oH3.className = "stateInfoStateName";
	var sNoteSign = this.appendNoteSigns(this.lookupObject.states[this.state1].notes);
	oH3.innerHTML = this.lookupObject.states[this.state1].label + sNoteSign;
	oContainer.appendChild(oH3);

/*	var oHeading = document.createElement("h4");
	oHeading.innerHTML = "Data Highlights:";
	oContainer.appendChild(oHeading);
	
	var oDt, oDd, sCatID;
	var oTable, oTbody, oTr, oTh, oTd;
	var oDl = document.createElement("dl");
	oTable = document.createElement("table");
	oTbody = document.createElement("tbody");
	
	for(var i=0;i<rDatapoints.length;i++) {
		
		sCatID = rDatapoints[i];
		
		oTr = document.createElement("tr");
		oTh = document.createElement("th");
		oTd = document.createElement("td");
		
		oTh.innerHTML = this.lookupObject.cats[sCatID].label;
		oTd.innerHTML = this.stateDataObject[this.state1].data[sCatID].value;
		
		oTr.appendChild(oTh);
		oTr.appendChild(oTd);
		oTbody.appendChild(oTr);
	}

	oTable.appendChild(oTbody);
	oContainer.appendChild(oTable);*/

}

SahFeatureClass.prototype.populateStateRightCol = function(stateId) {
	
}

SahFeatureClass.prototype.init = function() {
	
	this.hierObject = this.buildHierObject();
	this.lookupObject = this.buildLookUpArray();
	this.stateDataObject = this.buildStateDataArray();
	this.buildStateDataHashTable();
	
	//console.dir(this.hierObject);
	//console.dir(this.lookupObject);
	//console.dir(this.stateDataObject);
	
	this.setStructure();
	
	this.buildStateDropDown("ddStatesNat");
	this.buildStateDropDown("ddStatesSbs");

}

//instantiate sahFeatureClass
var sahFeature = new SahFeatureClass();

function Tabs(oTabContainer) {

	this.rTabs = [];
	this.oTabContainer = oTabContainer;

}

Tabs.prototype.add = function(label, pageName, view, active, click) {
	
	var oTab = {
		label:label
		,pageName:pageName
		,view:view
		,active:active
		,click:click
	}
	
	this.rTabs.push(oTab);

}

Tabs.prototype.render = function() {

	var oTab, oLi, oAnchor;
	var oUl = document.createElement("ul");
	
	for(var i=0;i<this.rTabs.length;i++) {
		
		oTab = this.rTabs[i];
		
		oLi = document.createElement("li");
		oLi.setAttribute("id", oTab.pageName + "Tab_" + oTab.view);
		
		if(oTab.active) {
			oLi.className = "active";
		}
		
		oAnchor = document.createElement("a");
		oAnchor.innerHTML = oTab.label;
		oAnchor.href = "javascript: void(0)";
		oAnchor.setAttribute("view",oTab.view);
		oAnchor.setAttribute("viewcontainer", oTab.pageName + "View_" + oTab.view);
		oAnchor.onclick = oTab.click;
		oAnchor.onmouseover = function() {
			window.status = "";
			return true;
		}
		oAnchor.onfocus = function() {
			this.blur();
		}
		
		oLi.appendChild(oAnchor);
		oUl.appendChild(oLi);
		this.oTabContainer.appendChild(oUl);

	}
	
}
