////////////////////////////////////////////////////////////////////////////////
// ScrollingPanelManager
////////////////////////////////////////////////////////////////////////////////

function ScrollingPanelManager() {
	this.resultsScroller = $("resultsScroller");
	this.adminFrame      = $("queryFetcher");
	window.addOnresize("if (scrollingPanelManager){scrollingPanelManager.divAndIframeResize();}");

	/*
	pretty sure this doesn't do anything now... was needed for ff 1.5...
	if (!document.all && this.resultsScroller) {
		//TODO - firefox 2.0 we dont need this anymore, but since it calls preventDefault, it might not cost us anything to just leave it in. 
		//document.body.addEventListener("DOMMouseScroll", mouseWheelScroller, true);
	}
	*/
}
ScrollingPanelManager.prototype.divAndIframeResize = function() {
	var objectToResize;
	var heightAvailable = util.getWindowHeight();

	if (window.stateManager && window.stateManager.isState("adminState")) {
		objectToResize = this.adminFrame;
	}
	else {
		objectToResize = this.resultsScroller;
		heightAvailable -= util.getTop (objectToResize);
	}
	
	objectToResize.style.height = heightAvailable + "px";
}


////////////////////////////////////////////////////////////////////////////////
// SkinManager
////////////////////////////////////////////////////////////////////////////////

function SkinManager() {
	this.activeSkinStyleSheetIndex   = -1;
	this.mouseOverHighlightColor     = false;
	this.mouseOverHighlightTextColor = false;
	this.searchTermHighlightColor    = false;
	this.buildCrossBrowserSkinList();
	this.pullHighlightColors();	
	this.explicitHighlight = false;
	
	this._resultStateControlMap = {};
	this.homePagePanels = new Hash();
	
}
SkinManager.prototype.attach = function() {
	
	// Report view state controls
	addEvent($("resultsViewControls"), 'click', this.handleResultsViewClick.bind(this));
	
	// If mouseover and mouseout events fall all the way down to document, they get caught here 
	addEvent(document, 'mouseover', this.handleMouseOver.bind(this));
	addEvent(document, 'mouseout', this.handleMouseOut.bind(this));	

	window.splunkEvents["preferencesLoaded"].subscribe(this.handleLoadPrefs.bind(this));
}

SkinManager.prototype.handleLoadPrefs = function() {
	skin = stateManager.getProp("skin");
	this.setSkin(skin);
}

SkinManager.prototype.buildCrossBrowserSkinList = function() {
	var linkTags = document.getElementsByTagName("LINK");
	this.skinList = []
	for (var i=0;i<linkTags.length; i++ ) {
		var ss = linkTags[i];
		if (ss.getAttribute("href").indexOf("skins")!=-1) {
			// skinList has the cross browser references returned by getCSSDomReference. 
			// which may be a link tag, or maybe a reference into document.styleSheets 
			this.skinList[this.skinList.length] = this.getCSSDomReference(ss);
		}	
	}
}
SkinManager.prototype.getActiveSkin = function() {
	if (this.activeSkinStyleSheetIndex > -1) {
		return this.skinList[this.activeSkinStyleSheetIndex];
	}
	// this will only run once when the system loads.  its a bit pedantic because we could just default activeSkinStyleSheetIndex to 0, as the first skin in the list is always the selected one
	for (var i=0; i < this.skinList.length ; i++) {
		var skin = this.skinList[i];
		if (this._checkIfActive(skin)) {
			this.activeSkinStyleSheetIndex = i;
			return skin;
		}
	}
	if (this.skinList && this.skinList[0]) return this.skinList[0];
	alert("no skins found");
	return false;
}
SkinManager.prototype.getActiveSkinTitle = function() {
	if (is.opera) return "not implemented";
	else if (this.activeSkinTitle) return this.activeSkinTitle;
	else return this.activeSkinTitle = this.getActiveSkin().title;
}
SkinManager.prototype._checkIfActive = function(skin) {
	if (skin.getAttribute && (skin.getAttribute("disabled") != "false"))  return false;
	else if ((skin.disabled==true)) return false;
	else return true;
}
SkinManager.prototype._hasTitle = function(skin, title) {
	if (this._getTitle(skin) == title) return true;
	else return false
}
SkinManager.prototype._getTitle = function(skin) {
	if (skin.title) return skin.title;
	else if (skin.getAttribute && (skin.getAttribute("title"))) return skin.getAttribute("title");
	else return false
}

// code to change the active stylesheet
SkinManager.prototype.setSkin = function(title) {
	try {
		title = title.toLowerCase();
	}
	catch(e) {
		D.error("SkinManager.setSkin - undefined skin (" + skin + "). Exiting.")
		return false;
	}

	this.activeSkinTitle = false
	for (var i=0; i<this.skinList.length; i++) {
		var skin = this.skinList[i];
		if (this._hasTitle(skin,title)) {
			this.activeSkinStyleSheetIndex = i;
			skin.disabled = false;
			this.activeSkinTitle = title;
		}
		else skin.disabled = true;
	}
	// if none of them matched we will have turned them all off. If that happens, turn on the first one.
	if (!this.activeSkinTitle) {
		this.activeSkinStyleSheetIndex = 0;
		this.skinList[0].disabled = false;
		this.activeSkinTitle = this._getTitle(this.getActiveSkin());
	}
	
	this.pullHighlightColors();	
	return true;
}
SkinManager.prototype._setCssRule = function (newSelector, newRule, index) {
	// be aware of browser crashes
	if (is.opera) return false;

	var styleSheet = this.getActiveSkin();
	var rules = (document.all) ? styleSheet.rules : styleSheet.cssRules;

	if (styleSheet.deleteRule) styleSheet.deleteRule(index);
	else if (styleSheet.removeRule) styleSheet.removeRule(index);
	try {
		if (styleSheet.insertRule) styleSheet.insertRule(newSelector +"{"+newRule+"}",  index);
		else if (styleSheet.addRule) styleSheet.addRule(newSelector, newRule, index);	
	}
	catch (e){
		D.error('Please send this error to one of the splunk ui developers. SkinManager tried to push this CSS selector into the CSSDOM:: ' + newSelector +"\n.");
		D.error('Again, this error was caused by "' + newSelector + '"');
		return false;
	}
	return true;
}


// dhtml frameworks typically use either LINK elements in a list, or the document.stylesheets collection. 
// we need to use the former to get wider browser support, and the stylesheet switching is easier
// but we need the fancier dom methods to be able to call insertRule/addRule for the dynamic highlighting. 
// this function provides a one way conversion, from linkElements in the DOM, returning the right CSSDom object. 
SkinManager.prototype.getCSSDomReference = function(linkElement) {
	if (!document.styleSheets) return linkElement
	for (var i=0; i<document.styleSheets.length; i++) {
		
		// TODO: this is a semi-hack, done to circumvent the safari bug
		// that doesn't recognize the .title property
		if (document.styleSheets[i].href && (document.styleSheets[i].href.replace(/https?...[^\/]+/, '') == linkElement.getAttribute("href"))) 
			return document.styleSheets[i];
	}
	//alert("Can't get a cross-browser reference to a CSSDom object.")
	return false;
}
SkinManager.prototype.reconcileSkin = function(someDocument) {
	var newTitle = this.getActiveSkinTitle();
	var styleElem = someDocument.createElement("link");
	styleElem.setAttribute("type", "text/css");
	styleElem.setAttribute("rel", "stylesheet");
	styleElem.setAttribute("href", util.getStaticPath() + "/css/skins/" + newTitle + ".css");
	someDocument.getElementsByTagName("head")[0].appendChild(styleElem);
}
SkinManager.prototype.handleMouseOut = function(mozEvent) {
	if (this.explicitHighlight) {
		var originator = util.getOrigin(mozEvent);
		this.removeHighlight(mozEvent);
		if (!originator.getAttribute("title")) util.cancelEventBubbling(mozEvent);
	}
	return true;
}
// This is necessary so that the skin CSS is indeed a comprehensive skin. Before this, the highlight color had to be hardcoded somewhere in the js.
SkinManager.prototype.pullHighlightColors = function() {
	if (is.opera) return false;
	var skinStyleSheet = this.getActiveSkin();

	if (skinStyleSheet) {
		var rules = (document.all) ? skinStyleSheet.rules : skinStyleSheet.cssRules;
		this.mouseOverHighlightColor = rules[0].style.backgroundColor;
		if (rules[0].style.color) {
			this.mouseOverHighlightTextColor = rules[0].style.color;
		}
		this.searchTermHighlightColor = rules[1].style.backgroundColor;
	}
	else {
		this.mouseOverHighlightColor = "#ffed99";
		//this.mouseOverHighlightTextColor = "#ffed99";
		this.searchTermHighlightColor = "#ffed99";
	}
	return true;
}

SkinManager.prototype.handleMouseOver = function(mozEvent) {
	var originator = util.getOrigin(mozEvent);
	//D.debug("handleMouseOver for " + util.getTagName(originator) );
	if (((util.getTagName(originator)=="LABEL") || util.getTagName(originator)=="SVG:PATH") && !util.isOfClass(originator,"label")) {
		var parent = originator.parentNode
		// Simplest. Always the only one if format is all (hence no nested segments ever).  
		// and even in format::all, cascading menu highlights and outermost label highlighting always fall in here.
		if ((searchController.getFormat() != 'all') || util.getTagName(parent) != "LABEL") {
			this.highlightLabel(originator);
		}
		// this one is relevant if format::all is used on queries.   You wont understand it unless you change format to format::all in QueryResults and look at the "pyramids view" by putting an extra classname "exploded" into <div id="outerWrapper"> in index.html
		else if (parent.childNodes[parent.childNodes.length-1] == originator) { 
			this.highlightLabel(parent);
			//debugMsg("higlighting parent label " + util.getTextContent(parent));
		}
		else {
			this.highlightLabel(originator);
			//debugMsg("higlighting label " + util.getTextContent(originator));
		}
	}
	
}


SkinManager.prototype.highlightLabel = function(labelReference) {
	// Always clear any timeout if highlightLabel gets called again.
	if (this.highlightAttacher) {
		window.clearTimeout(this.highlightAttacher);
	}
	// cancel the expensive remove, cause the style will soon enough be overwritten by the new highlight rule.
	if (this.highlightRemover) {
		window.clearTimeout(this.highlightRemover);
		this.highlightRemover = null;
	}
	// usually false, cause previous onmouseout will have taken care of it.
	if (this.explicitHighlight) {util.removeClass(this.explicitHighlight, "explicitMouseOver");}

	if (this.explicitOpen) {
		// despite identical markup, mozilla sometimes forces a close on a label tag if it contains a ul element.
		if ((labelReference.parentNode.parentNode.parentNode != this.explicitOpen) && (labelReference.parentNode.parentNode.parentNode.parentNode != this.explicitOpen)) {
			util.removeClass(this.explicitOpen, "open");
			this.explicitOpen = false;
		}
	}
	// set it to the new one.
	this.explicitHighlight = labelReference;
	//var className = this.explicitHighlight.getAttribute('class');
	var className = labelReference.className;

	className = className.split(" ").shift();
	
	if (util.getTagName(labelReference)=="SVG:PATH") {
		className = labelReference.getAttribute("class");
	}
	
	if (util.isOfClass(this.explicitHighlight.parentNode,"secondary")) {
		this.explicitOpen = this.explicitHighlight.parentNode;
		util.addClass(this.explicitOpen, "open");
	}
	else if ((util.getTagName(this.explicitHighlight.parentNode)!="LI") && (this.explicitHighlight.parentNode.id!="typeAhead") && util.getTagName(this.explicitHighlight.parentNode) !="LI"){
		if ((className != "") && (className != "explicitMouseOver") && (className != "clickableTime")) {
			//D.debug("highlightLabel pushing highlight change for classname + '" + className + "'");
			this.highlightAttacher = window.setTimeout('skinManager.highlightAllLabels("'+className+'");',100);
		}
	}
	util.addClass(this.explicitHighlight, "explicitMouseOver");
	
	// handle the kv extraction
	//if(labelReference.hasAttribute('k')) {
	//	util.addClass(labelReference, 'kvOn');
	//	util.removeClass(labelReference, 'kv');
	//}
}

// returns false and does nothing in rare cases where the className in question isnt supposed to get highlighted.
SkinManager.prototype.highlightAllLabels = function(className) {
		
	//timingManager.debugSetStart("highlighting a label")
	var selector = "label." + className;
	var rule = ""
	if (this.mouseOverHighlightColor) {
		rule += "background-color:" + this.mouseOverHighlightColor  + " !important;";
	}
	if (this.mouseOverHighlightTextColor) {
		rule += "color:"  + this.mouseOverHighlightTextColor + ";"
	}
	// only for the subhistograms
	if ((className.indexOf("sg")!=0))
		rule += "display:block !important;";
	
	//this is where most of the expense is.  forces the page to re-render.
	this._setCssRule(selector, rule, 0);
	D.debug("SkinManager._setCssRule " + selector + ", " + rule);
	//timingManager.debugSetEnd("highlighting a label")
	return true;
}
//TODO Optimize the following case.   Mouseovers in format::all,  from say the "2" in an ip address,  to the "." immediately before it,  do a full onmouseout remove from CSSDom, then onmouseover add the same damn label's class back to the CSS Dom.  Mouseover on the highlight could in theory cancel the remove timeout, if it knew that the pending remove was identical to the pending add... -n
SkinManager.prototype.removeHighlight = function(mozEvent) {
	
	if (this.explicitHighlight && !util.isOfClass(this.explicitHighlight, "secondary")) {
		util.removeClass(this.explicitHighlight, "explicitMouseOver");
		this.explicitHighlight = null;
	}
	if (this.highlightRemover) {
		window.clearTimeout(this.highlightRemover);
		this.highlightRemover = null;
	}
	if (this.highlightAttacher) {
		window.clearTimeout(this.highlightAttacher);
		this.highlightAttacher = null
	}
	
	// handle the kv extraction
	//var target = util.getOrigin(mozEvent);
	//if(target.hasAttribute('k')) {
	//	util.addClass(target, 'kv');
	//	util.removeClass(target, 'kvOn');
	//}
	
	this.highlightRemover = window.setTimeout('skinManager._setCssRule(".stubClassName", "background-color:'    + this.mouseOverHighlightColor +'", 0);',50);
}
SkinManager.prototype.highlightContextMenu = function(rowElement) {
	this.resultRowHighlight = rowElement;
	util.addClass(this.resultRowHighlight, "rowHighlight");
}
SkinManager.prototype.unHighlightContextMenu = function() {
	util.removeClass(this.resultRowHighlight, "rowHighlight");
}




/**
 * Generates a new deep copy of the generic search result panel node, used to
 * hold new results coming back from the server
 *
 * @param parentDestinationNode DOMElement The parent node on which to append 
 * the newly created node.
 * 
 * @param panelName string The name of the panel to use.  The DOM element IDs
 * will be appended with this string.
 *
 */
SkinManager.prototype.generatePanelCloneTarget = function(parentDestinationNode, panelName) {

	D.debug("generatePanelCloneTarget - creating node: " + panelName);
	
	// if panel exists, destroy and rebuild
	var panel = $('panelBlock' + panelName);

	if(!panel) {
		// construct new DOM node from template and append to the parent
		panel = $('panelBlock').cloneNode(true);
		panel.setAttribute("panelId", panelName);
		util.renameNodeIds(panel, panelName);
		parentDestinationNode.appendChild(panel);
	}
	
	// return a reference to the new node
	return panel;
}



//
// Custom Event handlers
//


/**
 * Fires custom event when user clicks on result view
 *
 */
SkinManager.prototype.handleResultsViewClick = function(mozEvent) {
	
	var originator = util.getOrigin(mozEvent);
	var newState = originator.getAttribute("state");
	
	D.debugj("SkinManager.handleResultsViewClick - START got click event: state=" + newState);

	// check current state; switch context if necessary
	if(newState == stateManager.getActiveTransientState('resultViewState')) return true;
	stateManager.stateChange(newState, true);

	// don't sticky the report view
	if(newState != 'reportView')
		stateManager.setProp("resultsViewState", newState);
	
	window.splunkEvents["resultsViewChange"].fire({state: newState});

	D.debugj("SkinManager.handleResultsViewClick - END got click event: state=" + newState);
}



/**
 * Handles state changes from populating a home page panel
 * The readyState values are copied from xmlhttp; we only use states 1,3,4
 *
 */
SkinManager.prototype.handlePanelQueryChange = function(type, args) {
	
	var query = args[0].queryObject;
	var searchString = query.searchName;
	
	switch(args[0].readyState) {
		
		// called from panelQuery.query()
		// init the destination container, and set panel state to 'working'
		case 1:
			// determine where in the UI the results are to be placed
			// this.destination is usually set when a query result is destined
			// to be placed as a home page panel;
			query.destinationPanel = this.generatePanelCloneTarget(query.panelContainer, query.destination);
			util.removeClass(query.destinationPanel, "cloneable");

			// set messaging
			messageController.setStatus('Loading panel: ' + searchString + '...');
			
			// fill in the query summary as an attribute, and then into user
			// space
			query.destinationPanel.setAttribute("searchString", searchString);
			if (query.className=="PanelQuery") {
				var anchor = document.createElement("A");
				anchor.appendChild(document.createTextNode(searchString));
				// get the actual saved search string
				var savedSearches = stateManager.getSavedSearches();
				anchor.setAttribute("title", savedSearches.get(searchString));			

				$('panelSummarySearch' + query.destination).appendChild(anchor)
				//$('panelSummarySearch' + query.destination).innerHTML = searchString;
			}
			else {
				// quick and dirty - with static content the last refreshed is kind of nonsense, so we suppress it here. 
				// TODO - dashboard panels are now heterogenous enough where the whole cloneable elements thing 
				// should probably be reexamined a bit. 
				if (query.className == "StaticContentPanelQuery") {
					$('panelControls' + query.destination).style.display = "none";
				}
				var header = document.createElement("H3");
				header.appendChild(document.createTextNode(searchString));
				$('panelSummarySearch' + query.destination).appendChild(header);
			}
			$('panelinnerHistogramCloneTarget' + query.destination).setAttribute('searchString', searchString);

			
			util.addClass(query.destinationPanel, 'panelWorking');
			
			// attach the drag handler
			this.homePagePanels.set(query.destination, new PanelDragHandler(query.destinationPanel));
			
			break;
			
			
		// called from start of panelQuery.copyResponse
		// set saved prefs
		// remove panel state 'working'
		case 3:
			// retrieve saved view state
			var panelIsOpen = stateManager.getProp('saved_' + searchString + '_panelIsOpen');
			//D.debugj("CHECKING PANEL: " + query.destinationPanel.id + '=' + panelIsOpen);
			if(panelIsOpen === null) panelIsOpen = true;
			
			// minimize panel if user had closed it last
			if(!panelIsOpen) {
				util.removeClass(query.destinationPanel, 'panelBlockMaximized');
			}

			util.removeClass(query.destinationPanel, 'panelWorking');
			query.destinationPanel.style.height = 'auto';

			break;
		
		
		// called from end of panelQuery.copyResponse
		// generate the panel selection dropdown, and activate the UI widgets
		case 4:
		
			// retrieve saved view state; if not set, use default
			
			var panelToShow = stateManager.getProp('saved_' + searchString + '_panelMode');
			if (query.className != "PanelQuery") {
				panelToShow = "List";
			}

			if (!panelToShow) panelToShow = args[0].defaultPanelMode;
			
			// clear the drop down, and then populate the drop down with panels
			var panels = query.destinationPanel.getElementsByTagName('div');
			$('panelControlsMode' + query.destination).options.length = 0;
			if (panelToShow !="Chart" && panelToShow != "Table") {
				$("panelDisplaySelect" + query.destination).style.display = "none";
			}
			for (var i=0,l=panels.length; i<l; i++) {
				if (panels[i].hasAttribute('label')) {
					
					if (panels[i].getAttribute('label') == panelToShow) {
						panels[i].className = 'panelDetailOn';
					}
					// The only types of dashboards currently where the pulldown works at all,  are 'chart', and 'table'.
					var label = panels[i].getAttribute('label');
					if ((panelToShow =="Chart" || panelToShow == "Table") && (label=="Chart" || label=="Table")) {
						var option = document.createElement('option');
						option.text = label;
						option.setAttribute('linkPanel', panels[i].id);
						if (panels[i].getAttribute('label') == panelToShow) {
							option.selected = true;
						}
						$('panelControlsMode' + query.destination).appendChild(option);
					}					
				}
			}

			//------------------------------------------------------------------
			// attach event handlers to all UI widgets
			//------------------------------------------------------------------

			// skip attaching handlers if already there (as a result doing a 'refresh')
			if(query.destinationPanel.hasAttribute("hasHandlers")) break;
			
			// attach the event handlers to the new drop down
			addEvent($('panelControlsMode' + query.destination), 'change', function() {
				for(var i=0,l=this.options.length; i<l; i++) {
					var o = this.options[i];
					var p = $(o.getAttribute('linkPanel'));
					//D.debugj("SkinManager.handlePanelQueryChange - panel=" + o.text + " DOM=" + p.id);
					if(o.selected) {
						p.className = 'panelDetailOn';
						stateManager.setProp('saved_' + searchString + '_panelMode', o.text);
					} else {
						p.className = 'panelDetail';
					}
				}
			});
			if (query.className == "PanelQuery") {
				// attach event handler to refresh link
				addEvent($('panelSummarySearch' + query.destination), 'click', function() {
					var block = this.parentNode.parentNode;
					var savedSearches = stateManager.getSavedSearches();
					var viewState = viewStateManager.get(searchString);
					
					// switch the view state
					stateManager.stateChange(viewState['resultView'], true);
					
					// set the default plot mode
					D.debugj("Panel click - setting chartLastPlotMode=" +  viewState['chart']['plotMode']);
					stateManager.setProp('chartLastPlotMode', viewState['chart']['plotMode']);
					
					// run search
					queryFactory.runFreshQuery(savedSearches.get(searchString));
					return false;
				});
			}
			// attach event handler to toggle switch
			addEvent($('panelToggle' + query.destination), 'click', function() {
				var block = this.parentNode.parentNode;
				var panelIsOpen = util.toggleClass(block, 'panelBlockMaximized');
				stateManager.setProp('saved_' + searchString + '_panelIsOpen', panelIsOpen);
			});

			// attach event handler to close button
			addEvent($('panelClose' + query.destination), 'click', function() {
				var block = this.parentNode.parentNode.parentNode;
				
				// unregister this panel from drag-drop manager
				// each drag handler is stored in skinManager
				var handler = skinManager.homePagePanels.get(query.destination);
				handler.unreg();
				skinManager.homePagePanels.remove(query.destination);
				block.parentNode.removeChild(block);
			});
			

			// resurrect the saved timerange	
			addEvent($("panelinnerHistogramCloneTarget" + query.destination), "click", function(evt) {
				var savedSearches = stateManager.getSavedSearches();
					var searchTermStr  = savedSearches.get(searchString);
					if (searchTermStr) {

					/* TODO - this needs to be improved.   Need to leverage query-parsing logic in side Command. 
					 * such that the absorbTimeTerms functionality only absorbs them from the search clause
					 * THERE ARE MANY SUCH PLACES WHERE THIS SHOULD BE DONE. 
					 * Until then, the TODO specific to this code here, is that dashboard modules with subsearches, that have different timeranges will behave badly in the UI.
					 */
						var searchTermList = searchTermStr.split(" ");
						var range = new TimeRange();
						if (range.absorbTimeTerms(searchTermList)) {
							searchTermStr = searchTermList.join(" ");
							timelineManager.setTimelineRange(range.copy()); 		
						}
						searchController.setPendingSearch(searchTermStr);
					} else D.error("could not locate saved search matching this dashboard module");
				
				timelineManager.handleHistogramClick(evt);
			});

			addEvent($("panelinnerHistogramCloneTarget" + query.destination), "mouseout", timelineManager.handleHistogramMouseout.bind(timelineManager));
			
			
			// attach default mouse events
			addEvent($("panelinnerHistogramCloneTarget" + query.destination), "mouseover", timelineManager.handleHistogramMouseover.bind(timelineManager));
			// mark the panel as having all its handlers attached
			query.destinationPanel.setAttribute("hasHandlers", true);
			
			// clear messaging
			messageController.clearStatus();
			
			break;
			
	}
	
}


/**
 * Handles event when dashboard panels are re-ordered. Persists the new ordering.
 *
 */
SkinManager.prototype.handlePanelReorder = function() {
	
	// determine the current dashboard set
	var currentSetName = stateManager.getProp('dashboard_activeset');
	if(!currentSetName) currentSetName = 'default';
	
	// loop over all existing panels, and read in new order
	var container = $('landingPageContainer');
	var panels = [];
	for(var i=0; i<container.childNodes.length; i++) {
		var panel = container.childNodes[i];
		if(util.isOfClass(panel, 'panel') && panel.hasAttribute('searchstring')) {
			panels.push(panel.getAttribute('searchstring'));
		}
	}
	// add on the marker that this property should automatically inherit values from default and from other bundles. 
	//panels.push("$+");
	// since we're just reordering not removing, we dont muck with the dashboardsetmask_ property
	stateManager.setProp('dashboardset_' + currentSetName,  panels.join(","));
}


/**
 * Handles click actions on 'report summary' pages.  Deals with toggle panels.
 *
 */
SkinManager.prototype.handleSummaryPanelClick = function(sourceObject, className, isActive) {
	var root = sourceObject.parentNode.parentNode;
	if(isActive) {
		util.addClass(root, className);
	} else {
		util.removeClass(root, className);
	}
	return false;
}


/**
 * Handles the index dropdown menu
 *
 */
SkinManager.prototype.handleIndexMenuChange = function(targetObject) {
	searchController.setPulldownIndexName(util.getSelectedValue(targetObject), true);
	queryFactory.runIndexedMetaQuery()
}


/**
 * Handles clicks to 'add content' to current dashboard
 *
 */
SkinManager.prototype.handleDashboardEditClick = function(mozEvent) {

	splunkWebAdapter.execute("adminPopup","/v2/prefs/getDashboardMask?xsl=preferences.xsl", this.handleDashboardEditCallback.bind(this), true);
	if (stateManager) stateManager.stateChange("adminPopupLayerOpen", true);
	util.cancelEventBubbling(mozEvent);

}

SkinManager.prototype.handleDashboardEditCallback = function(responseXML) {
	var targetDiv = $("adminPopupLayer");
	var fragment = searchController.transformDocument('preferences', responseXML);

	// perform the copy action
	if (targetDiv) util.copyIntoDocument(targetDiv,fragment);
}

SkinManager.prototype.handleDashboardEditSubmit = function(formObject) {
	
	// get the existing list order
	var dashboardSet = stateManager.getProp('dashboard_activeset');
	var dashboardList = stateManager.getProp('dashboardset_' + dashboardSet).split(",");

	var newSearchList = dashboardList;
	// We have to store both the positive list and the exclusion list. Note the "$+" appended to the positive list. 
	// this means that new bundles will dump values in here, and thus they'll be checked by default on the user's dashboard.
	// but if the user later unchecks it, we'd remove it from thelist, it'd get reinherited, reappear checked, User would fly into rage. 
	// Thus we keep the negative list explicitly and mask out those values from the positive list, even though it's almost always redundant. 
	var newSearchListMask = [];

	// get the user input list
	// we want to maintain the original order, so:
	// -- if search is unchecked, remove it
	// -- else if checked and is new, then add to bottom
	var els = formObject.elements;
	for (var i=0,l=els.length; i<l; i++) {
		if (els[i].hasAttribute('searchName')) {
			var name = els[i].getAttribute('searchName');
			if (!els[i].checked) {
				newSearchList.remove(name);
				newSearchListMask.push(name);
			} else if (els[i].checked && dashboardList.indexOf(name) == -1) {
				newSearchList.push(name);
			}
		}
	}
	// add on the marker that this property should automatically inherit values from default and from other bundles. 
	//newSearchList.push("$+");
	// write list out
	stateManager.setProp('dashboardset_' + dashboardSet, newSearchList.join(","));
	stateManager.setProp('dashboardsetmask_' + dashboardSet, newSearchListMask.join(","));



	// hide the form
	stateManager.stateChange("adminPopupLayerOpen", false);

	// refresh the panels
	searchController.handleInitHomePageCallback();
	
}




////////////////////////////////////////////////////////////////////////////////
// PopupLayerManager
////////////////////////////////////////////////////////////////////////////////

function PopupLayerManager() {
	if (window.popupLayerManager) alert('hey, i already exist, what gives?');
	//this.persistentModalStates    = {"setFormat" : 1, "setSkin" : 1, "setClickBehaviour" : 1};
	this.layerIdsActive = {};
	this.draggingLayer = false;
	this.resizingLayer = false;
	this.constrainedDraggingFollower = false;
	// used for both dragging and resizing...
	// TODO make a Point class...
	this.lastMouseX = false;
	this.lastMouseY = false;
	this.minResizingHeight = 200;
	this.minResizingWidth  = 400;
	this.maxResizingHeight = 700;
	this.maxResizingWidth  = 600;
	this._bodyGuardForIe = document.getElementById("popupLayerBodyGuard");

	// todo - rethink this setup, and whether to refactor into all PopupLayers
	//this.constrainHelpPanel();
	window.addOnresize("popupLayerManager.constrainHelpPanel();");

	var h5Elements = document.getElementsByTagName("H5");
	for (var i=0;i<h5Elements.length;i++) {
		var elt = h5Elements[i];
		if (util.isOfClass(elt, "popperUpper")) {
			elt.onclick = function(mozEvent) {
				popupLayerManager.handlePopperUpperRequest(this);
				util.cancelEventBubbling(mozEvent);
				return false;
			}
		}
	}

	addEvent(document,"keypress",  this.handleKeyPress.bind(this));
	addEvent(document,"mousemove", this.handleMouseMove.bind(this));
	addEvent(document,"mouseup",   this.handleMouseUp.bind(this));
}

/**
 * Keep the help assistant window within full view of the main window
 *
 */
PopupLayerManager.prototype.constrainHelpPanel = function() {
    
    //D.debug("constrainHelpPanel");
    
	var helpPanel = document.getElementById("helpPanel");
	if (!helpPanel) return false;
	
	var newLeft = Math.max(util.getWindowWidth()  - 500, 10);
	var newTop  = Math.max(util.getWindowHeight() - 500, 10);
	if ((helpPanel.offsetLeft > newLeft) || helpPanel.offsetTop > newTop || ((helpPanel.offsetLeft==0) & (helpPanel.offsetTop ==0))) {
		util.setLeft(helpPanel,newLeft);
		util.setTop(helpPanel, newTop);
		if (is.ie && is.ieVersion <7)
			this.deployBodyGuard(helpPanel);
	}
	return true;
}


PopupLayerManager.prototype.handleMouseMove = function(mozEvent) {
    
    // dump out if nothing to do
	if (!this.draggingLayer && !this.resizingLayer) return true;
	
	var ourEvent = util.getEvent(mozEvent);
	
	// first mousemove after a dragStart or resizeStart will fall in here. 
	if (!this.lastMouseX) {
		this.lastMouseX = ourEvent.clientX;
		this.lastMouseY = ourEvent.clientY;
	}

	// TODO - make a Point class
	var dx = ourEvent.clientX - this.lastMouseX;
	var dy = ourEvent.clientY - this.lastMouseY;

	//D.debug("received mouse move: " + dx + ", " + dy);

    // handling mouse dragging events
	if (this.draggingLayer) {
	    util.cancelEventBubbling(mozEvent);
		if (dx) util.setLeft(this.draggingLayer, this.draggingLayer.offsetLeft + dx);
		if (dy) util.setTop(this.draggingLayer, this.draggingLayer.offsetTop + dy);
		/*
		if (stateManager) {
			stateManager.stateChange("suppressSelection", true);
			if (stateManager.isState('adminState')) {
				util.addClass(util.getIframeDocument().getElementById("outerWrapper"), "suppressSelection")
			}
		}
		*/
		
		if (is.ie && is.ieVersion <7) {
			popupLayerManager.deployBodyGuard(this.draggingLayer);
			//document.onselectstart = function(){return false;}
		}
	}

    // handle window resize events
    // NOTE: currently this section is really only for the help assistant,
    // as it's the only window that is resizable
	if (this.resizingLayer) {
		var newWidth  = this.resizingLayer.offsetWidth + dx;
		var newHeight = this.resizingLayer.offsetHeight + dy;
		
		newWidth  = Math.max(newWidth,this.minResizingWidth);
		newWidth  = Math.min(newWidth,this.maxResizingWidth);

		newHeight = Math.max(newHeight,this.minResizingHeight);
		newHeight = Math.min(newHeight,this.maxResizingHeight);
		
		
		if (dx) util.setWidth(this.resizingLayer, newWidth - 14);       // TODO: the 14px is to compensate for the padding style on #popupContent, i.e. the resize layer
		if (dy) util.setHeight(this.resizingLayer, newHeight);
		if (dx) util.setWidth(this.resizingLayer.offsetParent, newWidth);

        // TODO: 
        // because the help viewer
        // has 2 viewing windows, we want to make sure to scale both viewers
        // whenever dragging the resize handle
        // the interger adjustment values are to compensate for CSS padding
        // on the viewer window
		if (this.resizingLayer.id == 'helpContent') {
		    if (dx) {
		        util.setWidth($('helpFrameViewer'), newWidth - 14);
		    }
    		if (dy) {
    		    util.setHeight($('helpFrameViewer'), newHeight - 30);
    		    util.setHeight($('helpBodyPage'), newHeight - 40);
    		}
		}

		D.debug("resizing layer dimensions to: " + newWidth + "x" + newHeight + '; actual is: ' + this.resizingLayer.offsetWidth + "x" + this.resizingLayer.offsetHeight + " [alt: " + this.resizingLayer.style.width + "x" + this.resizingLayer.style.height + "]");
		
		if (is.ie && is.ieVersion <7) {
			popupLayerManager.deployBodyGuard(this.resizingLayer.offsetParent);
		}
	}

	this.lastMouseX = ourEvent.clientX;
	this.lastMouseY = ourEvent.clientY;
	return true;

}
PopupLayerManager.prototype.handleMouseUp = function( mozEvent) {
	util.cancelEventBubbling(mozEvent);
	return popupLayerManager.stopAllDragging(mozEvent);
}
PopupLayerManager.prototype.dragStart = function(dragger) {
	//D.debug("dragStart");
	this.draggingLayer = dragger.offsetParent;
}

PopupLayerManager.prototype.stopAllDragging = function(mozEvent) {
   
	//D.debug("stopAllDragging");
    
	/*
	if (stateManager) {
		stateManager.stateChange("suppressSelection", false);
		if (stateManager.isState('adminState')) {
			util.removeClass(util.getIframeDocument().getElementById("outerWrapper"), "suppressSelection")
		}
	}
	*/
	//if (document.all && document.onselectstart && !document.onselectstart()) document.onselectstart = selectionHandler

	if (this.draggingLayer && this.resizingLayer) {
		var resetLeft = this.resizingLayer.offsetLeft + this.resizingLayer.offsetWidth - this.draggingLayer.offsetWidth ;
		var resetTop = this.resizingLayer.offsetTop + this.resizingLayer.offsetHeight - this.draggingLayer.offsetHeight + 17;
		util.setLeft(this.draggingLayer,resetLeft);
		util.setTop(this.draggingLayer,resetTop);
	}
	//this.constrainedDraggingFollower = this.draggingLayer = this.lastMouseX = this.lastMouseY = false;
	//D.debug("dragging stopped");
	this.draggingLayer = this.resizingLayer = this.lastMouseX = this.lastMouseY = false;
}

// NOTE:
// -- there's an invisible layer that stays with the mouse.  however we just hook this up to conventional dragging functionality,  and put a reference to him in draggingLayer.  
// we Also put a refernce to the content element, in resizingLayer,  and if resizingLayer is defined, we set height and width to values based on constrained dx and dy values on the dragging layer. 
// finally, onmouseup, invisible layer's position is always reset to the bottom right corner of the resizing layer again
PopupLayerManager.prototype.resizeStart = function(resizer) {
	this.draggingLayer = resizer;
	this.resizingLayer = document.getElementById("helpContent");
	
	//D.debug("init resize on dragging: " + this.draggingLayer.id + " resize: " + this.resizingLayer.id);
	
}


// takes all the input Fields in the popupLayer, and if the popperUpper has any attributes of same name,
// it'll clone those values into the fields.
// Also, and this is needed for the cascading menu part,  it'll create raw properties of same name on the
// popuplayer element.
PopupLayerManager.prototype.populatePopupFields = function(popperUpper, popupLayer) {

	popupLayer.opener = popperUpper;
	
	var walkingNode = popperUpper;
	// in a couple places, a popperUpper can open another popperUpper.
	// this will look to see if it's in a popupLayer, and steal the opener reference from it's parent.
	while (walkingNode.parentNode) {
		if (util.isOfClass(walkingNode, "popupLayer")) {
			popupLayer.opener = walkingNode.opener;
			break;
		}
		walkingNode = walkingNode.parentNode
	}
	var inputFields = popupLayer.getElementsByTagName("INPUT");
	this.fieldToFocus = false;
	for (var i=0; i<inputFields.length; i++) {
		var fieldName = inputFields[i].getAttribute("name")

		if (!fieldName) continue
		fieldName  = fieldName.toLowerCase();
		var fieldValue = "";
		if (popupLayer.opener.getAttribute(fieldName.toLowerCase())) {
			fieldValue = popupLayer.opener.getAttribute(fieldName);
		}
		if (fieldValue != "") {
			try {
				inputFields[i].value = fieldValue
				if (!this.fieldToFocus && inputFields[i].getAttribute("type")!="hidden") {
					this.fieldToFocus = inputFields[i];
					setTimeout("popupLayerManager.fieldToFocus.focus()", 100);
				}
			}
			catch (securityException) {
				// linux throws security exceptions if you even look at an input type="file". 
			}
		}
	}
	if (popupLayer.id == "tagType") {
		var typeId = popperUpper.getAttribute("typecode");
		if (typeId.indexOf("SP") ==-1) {
			typeId = "?" + typeId
		}
		$("displayedTypeId").innerHTML = typeId;
	}
	else if (popupLayer.id == "tagHost") {
		$("displayedHost").innerHTML = popperUpper.getAttribute("hostNameValue");
	}
}

PopupLayerManager.prototype.handleKeyPress = function(mozEvent) {
	var ourEvent = util.getEvent(mozEvent);
	if (ourEvent.keyCode == KEY_ESCAPE) {
		this.closeAll();
		if (stateManager) stateManager.stateChange('adminPopupLayerOpen', false);
	}
	return true;
}


/**
 * Handles requests to popup a window/menu/layer, etc.
 *
 * @param {object} popperUpper The object that fired the event to pop something
 * 					up.
 * @param {object} popupLayer The DOM node to pop up.
 *
 * @return {boolean}true if it was already popped up. False if it wasn't. 
 *
 */
PopupLayerManager.prototype.handlePopperUpperRequest = function(popperUpper, popupLayer) {
	
	//D.debugj("PopupLayerManager.handlePopperUpperRequest - START popperUpper=" + popperUpper.id);
	
	// if no popup layer object passed, then look at the requesting object to
	// see if there is one define there in 'layerid' attribute
	if (!popupLayer) {
		popupLayer   = document.getElementById(popperUpper.getAttribute("layerid"));
	}
	
	// stop if it's already popped up
	if (this.layerIdsActive[popupLayer.getAttribute("id")]) {	
		return true;
	}
	
	
	// close all other open popups
	if (popupLayer.getAttribute("id") != "histogramToolTipLayer") { this.closeAll();}
	if (window.typeAheadManager) window.typeAheadManager.closeAll();
	
	// notify stateManager of new popup state
	stateManager.stateChange(popupLayer.getAttribute("id") + "Open", true);
	
	// mark popup layer as 'active'
	this.layerIdsActive[popupLayer.getAttribute("id")] = true;
	
	// render the popup
	this.popupLayer(popperUpper, popupLayer);
	
	return false;
	
}


/**
 * Renders a popup layer
 *
 * @param {object} popperUpper The object that fired the event to pop something
 * 					up.
 * @param {object} popupLayer The DOM node to pop up.
 *
 */
PopupLayerManager.prototype.popupLayer = function(popperUpper, popupLayer) {
	
	//D.debugj("PopupLayerManager.popupLayer - START popupLayer=" + popupLayer.id);
	// reveal the popup layer
	popupLayer.style.display = "block";
	

	// set initial origin
	var top,left = -1;
	
	// if there is an originating element, draw the popup layer relative to it
	if (popperUpper) {
		
		// get the x-coordinate
		left = util.getLeft(popperUpper);
		
		// get alignment; some hang to the right, some hang to the left.
		if (popupLayer.getAttribute("alignment") == "right") {
			left +=  popperUpper.offsetWidth - popupLayer.offsetWidth;
		}
		
		// get the y-coordinate
		var popperUpperHeight = popperUpper.offsetHeight;
		if (!popperUpperHeight) {
			
			// floated or inlined elements such as the ones in the timeFields,
			// will report an offsetHeight of 0, which isnt really helpful to us.
			// What we do is look inside and see if the popperUpper wraps an
			// image, and get the image's height.
			if (popperUpper.childNodes[0] && (util.getTagName(popperUpper.childNodes[0])=="IMG")) {
				popperUpperHeight = parseInt(popperUpper.childNodes[0].getAttribute("height"),10) ;
			}
			
			// still strange side effects of our searchResults css;  mozilla 
			// calculates wrong offsetLeft positions for the popperUppers in the
			// search results.
			if (!document.all && ( popupLayer.id=="tagType" || popupLayer.id=="renameSourceType")) {
				popperUpperHeight = 0;
			}
			
		}
		top = util.getTop(popperUpper) + popperUpperHeight;

		// fill in the popup layer with its options
		this.populatePopupFields(popperUpper, popupLayer);
		
	}

	var windowHeight = util.getWindowHeight();
	var windowWidth  = util.getWindowWidth();

	// if any absolute atts are used, they override default offset-based values.
	if (popupLayer.getAttribute("t")) top = parseInt(popupLayer.getAttribute("t"),10);
	if (popupLayer.getAttribute("l")) left = parseInt(popupLayer.getAttribute("l"),10);
	else if (popupLayer.getAttribute("r")) {
		left = windowWidth - parseInt(popupLayer.getAttribute("r"),10);
	}
	
	// then check for offsets
	if (popupLayer.getAttribute("xoffset")) {
	 	left += parseInt(popupLayer.getAttribute("xoffset"),10);
	}
	if (popupLayer.getAttribute("yoffset")) {
		var resultsScroller = document.getElementById("resultsScroller");
		if (resultsScroller && util.firstIsParentOf(resultsScroller,popperUpper)) {
			top -= resultsScroller.scrollTop;
		}
		top += parseInt(popupLayer.getAttribute("yoffset"),10);
	}
	
	// correcting for boundary conditions.
	if (top + popupLayer.offsetHeight > windowHeight) {
		top = windowHeight - popupLayer.offsetHeight;
	}
	if (left < 0) left = 0;

	// constrain popup to visible window
	if (popupLayer.getAttribute("id") != "searchFieldTypeAhead") {
		if (left + popupLayer.offsetWidth > windowWidth ) {
			left = windowWidth - popupLayer.offsetWidth;	
		}
	}
	
	D.debug("PopupLayerManager.popupLayer left=" + left + ", top=" + top);

	if (util.isOfClass(popupLayer,"contextMenu")) {
		top -= util.getTop($("resultsScroller"));
	}

	// assign the new coordinates to the popup layer
	util.setLeft(popupLayer, left);
	util.setTop(popupLayer,top);

	
	
	if (is.ie && is.ieVersion <7) this.deployBodyGuard(popupLayer);
	
}



// the bodyguard iframe is an iframe that prevents selects from burning through superimposed positioned layers.
// the bodyguard trumps the select, and the layer trumps the bodyguard. 
// function specifically called from handlePopperUpperRequest, but someday might need to nudge it from outside.
// eg (if popupLayers ever start resizing on window resize)
PopupLayerManager.prototype.deployBodyGuard = function(popupLayer) {
	//debugMsg("deploying bodyGuard", "startTiming")
	util.setLeft(this._bodyGuardForIe,popupLayer.offsetLeft);
	util.setTop(this._bodyGuardForIe, popupLayer.offsetTop);
	util.setWidth(this._bodyGuardForIe,popupLayer.offsetWidth);
	util.setHeight(this._bodyGuardForIe,popupLayer.offsetHeight);
	// only show it after changing it's dimensions.  Might save us some extra render cycles
	this._bodyGuardForIe.style.display = "block"
	//debugMsg("deploying bodyGuard", "endTiming")
}

PopupLayerManager.prototype.hideBodyGuard = function(left, top, width, height) {
	//debugMsg("hiding bodyGuard", "startTiming")
	// hide it before changing it's dimensions.  Might save us some extra render cycles
	this._bodyGuardForIe.style.display = "none"
	util.setLeft(this._bodyGuardForIe,-200);
	util.setTop(this._bodyGuardForIe,0);
	util.setWidth(this._bodyGuardForIe,100);
	util.setHeight(this._bodyGuardForIe,100);
	//debugMsg("hiding bodyGuard", "endTiming")
}
// returns false if it couldnt find popupLayer containing formReference. true if it can. 
PopupLayerManager.prototype.closeContainingPopupLayer = function(formReference) { 
	var walkingElement = formReference;
	while (walkingElement.parentNode && walkingElement.className.indexOf("popupLayer")==-1 ) {
		walkingElement = walkingElement.parentNode;
		if (!walkingElement.parentNode) return false;
	}
	// if we're still here, then walkingElement is of className popupLayer
	var ourPopupLayer = walkingElement;
	ourPopupLayer.style.display = "none"
	ourPopupLayer.style.left = "-1000px";

	this.layerIdsActive[ourPopupLayer.getAttribute("id")] = false;
	if (is.ie && is.ieVersion <7) this.hideBodyGuard();
	return true;
}


/**
 * Close all open popup layers.
 *
 * this is the anchor man in onclick handling. If any popup layers are open, 
 * he will close them and trap the click.  First checking to make sure that
 * the event didnt originate within the layer itself.  Otherwise he'll step
 * off and return true.
 *
 * This method called at: 
 *		end of processTermClick
 *		stateChange into landingPageState
 *		clearStartTime, clearEndTime,  entryClearer
 *		typeAheadManager.closeAll();
 *		check and share splunkEvents
 *		document.onclick anything with an href
 *		anything not of the known set of originator tagNames
 *		label click, originator is of class menu
 *		any escape key anywhere
 *		handlePopperUpperRequest from elements that are not already open
 *
 * @param {DOMElement} originator The DOM element that fired the event that
 * 			called this method.
 */
PopupLayerManager.prototype.closeAll = function(originator) {

	// if called anonymously, scope this at document level
	if (!originator) originator = document;

	

	// loop through all the registered popup layers and close them;
	// if was open, supress all subsequent click actions
	for (layerId in this.layerIdsActive) {
		if (this._closeLayer(originator, layerId)) return false;
	}

	// notify stateManager of no popup state
	if (stateManager) stateManager.stateChange("noPopupLayersOpen",true);

	// return true allows click's default actions to take place. Anything from
	// scrollbars, right-click menus, you name it. 
	return true;

}



/**
 * Closes a specific popup layer, by DOM ID.
 *
 * @param {DOMElement} originator The DOM element that fired the event that
 *			called this method.
 * @param {string} layerId The DOM ID of the popup layer to close.
 *
 * @return {boolean} true if the layer was successfully closed; false if the 
 *			layer wasn't open to begin with.
 *
 */
PopupLayerManager.prototype._closeLayer = function(originator, layerId) {
	if (this.layerIdsActive[layerId]) {
		
		// get reference to layer; dump out if it doesn't exist
		var popupLayer = $(layerId);
		if (!popupLayer) return false;
		
		// remove any 'open' state associated with this layer
		if (stateManager) stateManager.stateChange(layerId + "Open", false);

		// if closing the distributed server layer, notify the query manager
		// of any selection changes
		if (queryFactory && (layerId=="searchServerChooserCloneTarget")) {
			queryFactory.checkForServerListChangeOnClose();
		}
		

		// TODO: just make these clients not even call _closeLayer
		// oh, and mozilla or someone has a <scrollbar> element which is annoying
		if ((util.firstIsParentOf(popupLayer, originator) || util.getTagName(originator) == "scrollbar") 
			&& !util.isOfClass(originator,"cancel")
		) {
			return false;
		}
		if (popupLayer.onLayerClose) popupLayer.onLayerClose();
		
		// otherwise, hide the layer and remove from active roster
		popupLayer.style.display = "none";
		popupLayer.style.left = "-1000px";
		delete this.layerIdsActive[layerId];
		if (is.ie && is.ieVersion <7) this.hideBodyGuard();

		return true;
	} 
	else {
		return false;	
	}
}



PopupLayerManager.prototype.attachModalHandlers = function(rootNode) {
	var ulElements;
	if(rootNode) ulElements = rootNode.getElementsByTagName("UL");
	else ulElements = document.getElementsByTagName("UL");
	for (var i=0;i<ulElements.length;i++) {
		var elt = ulElements[i];
		// not all ul elements are selectable modal menus
		if (util.isOfClass(elt,"modalOptions")) {

			elt.onclick = function(mozEvent) {
				var ourEvent = util.getEvent(mozEvent);
				popupLayerManager.handleModalClick(this,ourEvent);
				util.cancelEventBubbling(ourEvent);
				return false;
			}
			// not all selectable modal menus are necessarily persistent
			/*
			if (elt.id in this.persistentModalStates) {
				var ulId = elt.id
				var preferenceValue = stateManager.getProp(ulId);
				if (preferenceValue) { 
					var setterMethod = document.getElementById(ulId).getAttribute("setter");
					window.addOnload(setterMethod + "('" + preferenceValue + "');popupLayerManager.updateModalSelectionState(document.getElementById('" + ulId + "'),'" + preferenceValue + "')");
				}
			}
			*/
		}
	}
}
PopupLayerManager.prototype.handleModalClick = function(ulElement, ourEvent) {
	var originator = util.getOrigin(ourEvent);	
	if (!util.isOfClass(originator,"disabled")) {
		var setterMethod = ulElement.getAttribute("setter");
		var newValue = originator.getAttribute("argument")
		if (!newValue) newValue = util.getTextContent(originator);
		
		var returnValue = eval(setterMethod + "('"+ newValue + "');");
		if (returnValue) {
			this.updateModalSelectionState(ulElement, newValue);
		}
	}
	
}
PopupLayerManager.prototype.updateModalSelectionState = function(ulElement, selectedValue) {
	var labelElements = ulElement.getElementsByTagName("LABEL");
	if (util.isOfClass(ulElement, "allowMultiple")) {
		
		clickedOnElement = null
		for (var i=0;i<labelElements.length;i++) {
			var elt = labelElements[i];
			if (util.getTextContent(elt) == selectedValue) clickedOnElement = elt;
		}
		if (!util.isOfClass(clickedOnElement,"modalSelectionOn")) {
			util.addClass(clickedOnElement,"modalSelectionOn");
		}
		else {
			util.removeClass(clickedOnElement,"modalSelectionOn");
		}
	}
	else {
		for (var i=0;i<labelElements.length;i++) {
			var elt = labelElements[i];
			if (util.getTextContent(elt) == selectedValue) {
				util.addClass(elt,"modalSelectionOn");
			}
			else {
				util.removeClass(elt,"modalSelectionOn");
			}
		}
		setTimeout("popupLayerManager.closeAll();",150);
	}
}



////////////////////////////////////////////////////////////////////////////////
// Drag and drop handling for home page panels
////////////////////////////////////////////////////////////////////////////////



/**
 * Initialize a home page panel as a draggable object within the context of a
 * sorted group
 *
 * @param {DOMElement} panelObject The home page panel DIV object to init.
 * @param {string} sGroup The group name to add the panel to
 * @param {object} config Additional configuration info to pass to handler
 *
 */
PanelDragHandler = function(panelObject, sGroup, config) {

	// check for valid object
	if(!panelObject) {
		D.warn("PanelDragHandler - null panelObject received; drag init cancelled");
		return false;
	}
	
	// init on DDProxy
	this.init(panelObject, sGroup, config);
	
	// set drag handle to the panel summary bar
	this.setHandleElId('panelSummary' + panelObject.getAttribute('panelId'));
	
	// set panel id on the DOM object
	this.panelId = panelObject.getAttribute('panelId');
	
	// start DDM stuff
	this.initFrame();
	this.setPadding(-4);
	this.goingUp = false;
	this.lastY = 0;
	
}


/**
 * Cast the DragHandler function as DDProxy class, and add our own custom event
 * handlers.
 *
 */
if(window.YAHOO) {
	YAHOO.extend(PanelDragHandler, YAHOO.util.DDProxy, {

	    startDrag: function(x, y) {
	        //this.logger.log(this.id + " startDrag");

			// setup shortcut references
			var Dom = YAHOO.util.Dom;

	        var dragEl = this.getDragEl();
	        var clickEl = this.getEl();
	        Dom.setStyle(clickEl, "visibility", "hidden");

	        dragEl.innerHTML = clickEl.innerHTML;

			// set styles
	        Dom.setStyle(dragEl, "color", Dom.getStyle(clickEl, "color"));
	        Dom.setStyle(dragEl, "backgroundColor", Dom.getStyle(clickEl, "backgroundColor"));
	        Dom.setStyle(dragEl, "border", "2px solid gray");
	    },

	    endDrag: function(e) {

			var Dom = YAHOO.util.Dom;
	        Dom.setStyle(this.getDragEl(), "visibility", "hidden");
	        Dom.setStyle(this.getEl(), "visibility", "");

			// persist the new order
			skinManager.handlePanelReorder();
		
	    },

	    onDrag: function(e, id) {

	        // figure out which direction we are moving
	        var y = YAHOO.util.Event.getPageY(e);

	        if (y < this.lastY) {
	            this.goingUp = true;
	        } else if (y > this.lastY) {
	            this.goingUp = false;
	        }

	        this.lastY = y;

	    },

	    onDragOver: function(e, id) {
			var Dom = YAHOO.util.Dom;

	        var srcEl = this.getEl();
	        var destEl = Dom.get(id);

	        var p = destEl.parentNode;

	        if (this.goingUp) p.insertBefore(srcEl, destEl);
	        else p.insertBefore(srcEl, destEl.nextSibling);

	        YAHOO.util.DragDropMgr.refreshCache();
	    }

	});
}


