function popupMenu(level, item) {
	closePopups(level);
	activePopups[level] = item;
	if (document.getElementById('Everything')) {
		document.getElementById('Everything').className = 'nr-hide-selects';
	}
	item.style.visibility = 'visible';
    document.onclick = function() {closePopups(0)};
}
function closePopups(level) {
	for (var i = 0; i < activePopups.length; i++) {
		if (activePopups[i] != null) {
			activePopups[i].style.visibility = (i < level) ? 'visible' : 'hidden';
		}
	}
	if (document.getElementById('Everything')) {
		document.getElementById('Everything').className = '';
	}
}
var activePopups = new Array();

function openTab(tabId, paneId) {
	var pelem = document.getElementById(paneId);
	if (pelem.style.visibility == 'visible') {
		closeTab();
		return;
	}

	closeTab();
	activeTab = tabId;
	activePane = paneId;
	pelem.style.visibility = 'visible';
	pelem.style.position = 'static';
	
	if (document.getElementById(tabId + 'Cell')) {document.getElementById(tabId + 'Cell').className = 'nr-active';}
	
	if (document.getElementById('OpenTab')) {document.getElementById('OpenTab').value = tabId;}
	if (document.getElementById('OpenTabPane')) {document.getElementById('OpenTabPane').value = paneId;}
}
function closeTab() {
	if (activePane) {
		var pelem = document.getElementById(activePane);
		pelem.style.visibility = 'hidden';
		pelem.style.position = 'absolute';
		if (document.getElementById(activeTab + 'Cell')) {document.getElementById(activeTab + 'Cell').className = '';}
	}
	activeTab = null;
	activePane = null;
	if (document.getElementById('OpenTab')) {document.getElementById('OpenTab').value = "";}
	if (document.getElementById('OpenTabPane')) {document.getElementById('OpenTabPane').value = "";}
}
function openDefaultTab() {
	var tabInp = document.getElementById('OpenTab');
	var paneInp = document.getElementById('OpenTabPane');
	if (tabInp && tabInp.value != null && tabInp.value != "" &&	paneInp && paneInp.value != null && paneInp.value != "") 
	{
		openTab(tabInp.value, paneInp.value);
	}
}
var activeTab = null;
var activePane = null;

// Used on BuildPage:
function toggleTitle(btnId, rowId, thId, tdId, titleId, navId) {
	var btn = document.getElementById(btnId);
	var row = document.getElementById(rowId);
	var th = document.getElementById(thId);
	var td = document.getElementById(tdId);
	var title = document.getElementById(titleId);
	var nav = document.getElementById(navId);
	
	if (row.style.visibility != "hidden" && row.style.visibility != "collapse") {
		if ((nav.value == title.value) || confirm("Replace nav text (" + nav.value + ")\nwith title text (" + title.value + ")?")) {
			nav.value = "";
			btn.innerHTML = "+";
			try {
				row.style.visibility = "collapse";
			} catch (e) {
				row.style.visibility = "hidden";
				th.style.position = "absolute";
				td.style.position = "absolute";
			}
		}
	} else {
		nav.value = title.value;
		btn.innerHTML = "-";
		th.style.position = "static";
		td.style.position = "static";
		row.style.visibility = "visible";
	}
}
function insertPanel(panelTypeId, variantId) {
	gapMovePanelIdStr = null;
	gapPanelTypeId = panelTypeId;
	gapPanelVariantId = variantId;
	showGaps();
}
function movePanel(panelIdStr, moveBtnId, layoutHolderId) {
	gapPanelTypeId = null;
	gapPanelVariantId = null;
	gapMovePanelIdStr = panelIdStr;
	activeMoveBtn = moveBtnId;
	document.getElementById(moveBtnId).className = "nr-active";
	if (layoutHolderId) {
		if (document.getElementById(layoutHolderId)) {
			activeMoveLayout = layoutHolderId;
			document.getElementById(layoutHolderId).className = "nr-suppress-gaps";
		}
	}
	showGaps();
}
function showGaps() {
	document.getElementById('NRContent').className = "nr-show-gaps";
	document.onclick = hideGaps;
}
function hideGaps() {
	if (activeMoveBtn != null) {
		document.getElementById(activeMoveBtn).className = "";
		activeMoveBtn = null;
	}
	if (activeMoveLayout != null) {
		document.getElementById(activeMoveLayout).className = "";
		activeMoveLayout = null;
	}
	document.getElementById('NRContent').className = "";
}
function insertIntoGap(regionId, pos, ptypeId, pvariantId, moveId, ridId, posId, formId) {
	document.getElementById(ptypeId).value = gapPanelTypeId == null ? "" : gapPanelTypeId;
	document.getElementById(pvariantId).value = gapPanelVariantId == null ? "" : gapPanelVariantId;
	document.getElementById(moveId).value = gapMovePanelIdStr == null ? "" : gapMovePanelIdStr;
	document.getElementById(ridId).value = regionId;
	document.getElementById(posId).value = pos;
	document.getElementById(formId).submit();
}
function openModify(layoutHolderId, modifyCellId, modifyPaneId) {
	var layoutHolder = document.getElementById(layoutHolderId);
	var modifyCell = document.getElementById(modifyCellId);
	var modifyPane = document.getElementById(modifyPaneId);
	layoutHolder.style.position = "absolute";
	layoutHolder.style.visibility = "hidden";
	modifyPane.style.position = "static";
	modifyPane.style.visibility = "visible";
	modifyCell.className = "nr-active";
}
function closeModify(layoutHolderId, modifyCellId, modifyPaneId) {
	var layoutHolder = document.getElementById(layoutHolderId);
	var modifyCell = document.getElementById(modifyCellId);
	var modifyPane = document.getElementById(modifyPaneId);
	layoutHolder.style.position = "static";
	layoutHolder.style.visibility = "visible";
	modifyPane.style.position = "absolute";
	modifyPane.style.visibility = "hidden";
	modifyCell.className = "";
}
var activeMoveBtn = null;
var activeMoveLayout = null;
var gapPanelTypeId = null;
var gapPanelVariantId = null;
var gapMovePanelIdStr = null;

// Plan for loggedin and ordering:
// maintain a list in the following order:
//   (Doesn't-have or does-have-explicitly, initially) and revokable
//   doesn't have (initially) and unrevokable
//   does have and unrevokable
//   has implied
// Within each of those four categories, order by combination of is_special and alphabetical.
// To find the right position for a particular item, scan through the list categorizing each entry's current
// location. If they match the list you're moving to, increment a counter by one. When you hit the one you're
// moving, that's where you insert. Probably possible to shortcut this when moving multiple items.

// For Logged In, the trick is different.
// During normal processing of grant or revoke, SKIP logged in but set a flag.
// When finished, if that flag is set, move logged in in the hidden values and then re-run part of the
// same process that was run on permissionTab().

// Getting there from here:
// * refactor permissionTab into the initial stuff when the tab is clicked versus the
//   bits that need to happen when logged in gets moved
// * implement a 'hasPermission' function to determine whether a given role should
//   appear on the right or left; use that from the refactored part of permissionTab
// * implement the logic for logged in:
//   * set a flag if logged in moves during normal grant/revoke
//   * check the flag at the end and if set call refreshPerms
//   * modify that process to test whether logged in has the permission, and if it
//     does skip all roles except for logged in and not logged in.
// - implement the ordering logic
//   * for each item being moved scan through allroles until you reach it, testing
//     hasPermission and incrementing a counter if it's (true for grant, false for
//     revoke). Insert at the position identified by the counter.
//   - generate allRoles in the right order and pass it to permissionTab; remove it
//     from the startup script generated in the codebehind.

function permissionTab(permMgrId, tabId, permsId, impliedPerms, partSentence, description, sentenceDiv, descDiv, availListId, explicitListId, grantBtnId, revokeBtnId, allRoles) {
	var permMgr = document.getElementById(permMgrId);
	if (permMgr.selectedTab) {
		var selectedTab = document.getElementById(permMgr.selectedTab);
		if (selectedTab) selectedTab.className = 'nr-tab-unselected';
	}
	permMgr.selectedTab = tabId;
	permMgr.permsId = permsId;
	permMgr.impliedPerms = impliedPerms;
	permMgr.availListId = availListId;
	permMgr.explicitListId = explicitListId;
	permMgr.grantBtnId = grantBtnId;
	permMgr.revokeBtnId = revokeBtnId;
	permMgr.allRoles = allRoles;
	if (!permMgr.initialPerms) permMgr.initialPerms = document.getElementById(permsId).value;
	document.getElementById(tabId).className = 'nr-tab-selected';
	document.getElementById(sentenceDiv).innerHTML = 'Roles that can ' + partSentence;
	document.getElementById(descDiv).innerHTML = description;

	document.getElementById(permMgr.grantBtnId).disabled = true;
	document.getElementById(permMgr.revokeBtnId).disabled = true;

	refreshPerms(permMgrId);
}
function refreshPerms(permMgrId) {
	var permMgr = document.getElementById(permMgrId);
	var availList = document.getElementById(permMgr.availListId);
	var explicitList = document.getElementById(permMgr.explicitListId);
	var roleArr = permMgr.allRoles.split(",");
	var permsVal = document.getElementById(permMgr.permsId).value;

	while (availList.options.length > 0) availList.remove(0);
	while (explicitList.options.length > 0) explicitList.remove(0);
	var loggedInHas = roleHasPerm(permMgrId, loggedInRoleId);
	for (var i = 0; i < roleArr.length; i++) {
		var roleId = roleArr[i];
		if (roleId && (!loggedInHas || roleId == loggedInRoleId || roleId == notLoggedInRoleId)) {
			var opt = document.createElement("option");
			var has = roleHasPerm(permMgrId, roleId);
			if (has) {
				explicitList.options.add(opt);
				if (permsVal.indexOf(',' + roleId + ',') < 0) {
					opt.style.backgroundColor = "#e3e3e3";
					opt.style.color = "#555555";
				}
			} else {
				availList.options.add(opt);
			}
			opt.text = roleNames[roleId];
			opt.value = roleId;
			if (revokableRoles.indexOf(',' + roleId + ',') < 0) {
				opt.style.color = "#91a6cc";
				if (has && permMgr.initialPerms.indexOf(',' + roleId + ',') < 0 &&
					permMgr.impliedPerms.indexOf(',' + roleId + ',') < 0) {
					opt.text = '*' + opt.text;
				}
			}
		}
	}
}
function roleHasPerm(permMgrId, roleId) {
	var permMgr = document.getElementById(permMgrId);
	var permsVal = document.getElementById(permMgr.permsId).value;
	return (permsVal.indexOf(',' + roleId + ',') >= 0 ||
			permMgr.impliedPerms.indexOf(',' + roleId + ',') >= 0);
}
function permissionAvailSelect(permMgrId) {
	var permMgr = document.getElementById(permMgrId);
	var availList = document.getElementById(permMgr.availListId);
	var explicitList = document.getElementById(permMgr.explicitListId);
	var grantBtn = document.getElementById(permMgr.grantBtnId);
	var revokeBtn = document.getElementById(permMgr.revokeBtnId);
	if (availList.selectedIndex != -1) {
		explicitList.selectedIndex = -1;
		grantBtn.disabled = false;
		revokeBtn.disabled = true;
	} else {
		grantBtn.disabled = true;
	}
}
function permissionExplicitSelect(permMgrId) {
	var permMgr = document.getElementById(permMgrId);
	var availList = document.getElementById(permMgr.availListId);
	var explicitList = document.getElementById(permMgr.explicitListId);
	var grantBtn = document.getElementById(permMgr.grantBtnId);
	var revokeBtn = document.getElementById(permMgr.revokeBtnId);
	for (var i = 0; i < explicitList.options.length; i++) {
		var opt = explicitList.options[i];
		if (permMgr.impliedPerms.indexOf(',' + opt.value + ',') >= 0 ||
			(permMgr.initialPerms.indexOf(',' + opt.value + ',') >= 0 &&
			 revokableRoles.indexOf(',' + opt.value + ',') < 0)) opt.selected = false;
	}
	if (explicitList.selectedIndex != -1) {
		availList.selectedIndex = -1;
		revokeBtn.disabled = false;
		grantBtn.disabled = true;
	} else {
		revokeBtn.disabled = true;
	}
}
function permissionGrant(permMgrId) {
	var permMgr = document.getElementById(permMgrId);
	var availList = document.getElementById(permMgr.availListId);
	var explicitList = document.getElementById(permMgr.explicitListId);
	var grantBtn = document.getElementById(permMgr.grantBtnId);
	var revokeBtn = document.getElementById(permMgr.revokeBtnId);
	var perms = document.getElementById(permMgr.permsId);
	var roleArr = permMgr.allRoles.split(",");
	var didAny = false;
	var didLoggedIn = false;
	var didNotLoggedIn = false;
	for (var i = 0; i < availList.options.length; i++) {
		var opt = availList.options[i];
		if (opt.selected &&
			(revokableRoles.indexOf(',' + opt.value + ',') >= 0 ||
			 confirm('You do not have sufficient privileges to revoke permissions from ' + opt.text + '.\nIf you grant this permission, you will be unable to revoke it later.\nAre you sure you want to grant this permission to ' + opt.text + '?'))) {
			perms.value += opt.value + ',';
			var insPos = 0;
			for (var j = 0; j < roleArr.length && roleArr[j] != opt.value; j++) {
				if (roleArr[j] && roleHasPerm(permMgrId, roleArr[j])) insPos++;
			}
			availList.remove(i);
			explicitList.options.add(opt, insPos);
			if (revokableRoles.indexOf(',' + opt.value + ',') < 0) {
				opt.text = '*' + opt.text;
			}
			i--;
			didAny = true;
			if (opt.value == loggedInRoleId) didLoggedIn = true;
			if (opt.value == notLoggedInRoleId) didNotLoggedIn = true;
		} else {
			opt.selected = false;
		}
	}
	grantBtn.disabled = true;
	revokeBtn.disabled = !didAny;
	if (didLoggedIn) loggedInPermChanged(permMgrId, explicitList, didNotLoggedIn);
}
function permissionRevoke(permMgrId) {
	var permMgr = document.getElementById(permMgrId);
	var availList = document.getElementById(permMgr.availListId);
	var explicitList = document.getElementById(permMgr.explicitListId);
	var grantBtn = document.getElementById(permMgr.grantBtnId);
	var revokeBtn = document.getElementById(permMgr.revokeBtnId);
	var perms = document.getElementById(permMgr.permsId);
	var roleArr = permMgr.allRoles.split(",");
	var didAny = false;
	var didLoggedIn = false;
	var didNotLoggedIn = false;
	for (var i = 0; i < explicitList.options.length; i++) {
		var opt = explicitList.options[i];
		if (opt.selected &&
			permMgr.impliedPerms.indexOf(',' + opt.value + ',') < 0 &&
			(permMgr.initialPerms.indexOf(',' + opt.value + ',') < 0 ||
			 revokableRoles.indexOf(',' + opt.value + ',') >= 0)) {
			perms.value = perms.value.replace(',' + opt.value + ',', ',');
			var insPos = 0;
			for (var j = 0; j < roleArr.length && roleArr[j] != opt.value; j++) {
				if (roleArr[j] && !roleHasPerm(permMgrId, roleArr[j])) insPos++;
			}
			explicitList.remove(i);
			availList.options.add(opt, insPos);
			if (revokableRoles.indexOf(',' + opt.value + ',') < 0) {
				opt.text = opt.text.substring(1);
			}
			i--;
			didAny = true;
			if (opt.value == loggedInRoleId) didLoggedIn = true;
			if (opt.value == notLoggedInRoleId) didNotLoggedIn = true;
		} else {
			opt.selected = false;
		}
	}
	revokeBtn.disabled = true;
	grantBtn.disabled = !didAny;
	if (didLoggedIn) loggedInPermChanged(permMgrId, availList, didNotLoggedIn);
}
function loggedInPermChanged(permMgrId, list, didNotLoggedIn) {
	refreshPerms(permMgrId);
	for (var i = 0; i < list.options.length; i++) {
		var opt = list.options[i];
		if (opt.value == loggedInRoleId ||
			(opt.value == notLoggedInRoleId && didNotLoggedIn)) {
			opt.selected = true;
		}
	}
}
function widenerRoleCheckSystem(listId) {
	var list = document.getElementById(listId);
	var foundNonSel = false;
	for (var i = 0; i < list.options.length; i++) {
		var opt = list.options[i];
		if (!opt.selected) foundNonSel = true;
	}
	if (!foundNonSel) {
		alert("You must always leave at least one 'System' role in place.");
		return false;
	}
	return true;
}