
// globals
var checkLists = new Object();
var checklistExpansion = 3.5; // height multiplier
var checklistExpansionMax = 500; // height limit
var popUpwards = true;

function transformMultiSelects() {
	var elems = document.getElementsByTagName("SELECT");
	var selElem, selPos, optElem, listElem, buttonDeselectElem;
	var i, j, selWidth, selHeight, selDims;
	var stringBuilder = new Array(0);
	var listId, chkName, selName, groupName;
	var inGroup;
	
	if (typeof(document.getElementById) == "undefined" || typeof(document.createElement) == "undefined")
		return;
	
	for (i = 0; i < elems.length; i++) {
		if (typeof(elems[i].multiple) != "undefined" && elems[i].multiple) {
			// get details about <SELECT> element
			selElem = elems[i];
			selDims = getDimensions(selElem);
			selWidth = selDims.x;
			selHeight = selDims.y;
			if (!selElem.id) {
				selElem.id = String(i) + "_sel";
			}
			listId = "chklst_" + selElem.id;
			selName = selElem.name;
			
			// create a UL to overlay it
			listElem = document.createElement("UL");
			listElem.id = listId;
			listElem.className = "checklist";
			listElem.style.width = String(selWidth) + "px";
			listElem.style.height = String(selHeight) + "px";
			listElem.style.zIndex = 999;
			listElem.onmouseover = checklistActivate;
			listElem.onmouseout = checklistDelayedDeactivate;
			listElem.innerHTML = buildCheckList(selElem, listId);
			selElem.parentNode.insertBefore(listElem, selElem);
			
			// build selected options display
			displayElem = document.createElement("DIV");
			displayElem.id = listId + "_display";
			displayElem.className = "checklistDisplay";
			displayElem.style.width = String(selWidth) + "px";
			displayElem.style.height = String(selHeight) + "px";
			displayElem.onmouseover = checklistDisplayOver;
			displayElem.onmouseout = checklistDisplayOut;
			displayElem.onclick = checklistActivate;
			displayElem.innerHTML = buildSelectedOptions(selElem);
			selElem.parentNode.insertBefore(displayElem, selElem);
			
			// build the 'select' button
			buttonSelectElem = document.createElement("A");
			buttonSelectElem.id = listId + "_button_select";
			buttonSelectElem.style.width = String(selWidth) + "px";
			buttonSelectElem.style.position = "absolute";
			buttonSelectElem.style.zIndex = 1000;
			buttonSelectElem.className = "checklistButton";
			buttonSelectElem.innerHTML = "Select";
			buttonSelectElem.href = "#";
			buttonSelectElem.onmouseover = checklistDisplayOver;
			buttonSelectElem.onmouseout = checklistDisplayOut;
			buttonSelectElem.onclick = checklistActivate;
			listElem.parentNode.insertBefore(buttonSelectElem, listElem);
			
			// build the 'deselect all' button
			buttonDeselectElem = document.createElement("A");
			buttonDeselectElem.id = listId + "_button_deselect";
			buttonDeselectElem.style.width = String(selWidth) + "px";
			buttonDeselectElem.style.position = "absolute";
			buttonDeselectElem.style.zIndex = 1000;
			buttonDeselectElem.className = "checklistButton";
			buttonDeselectElem.innerHTML = "Deselect All";
			buttonDeselectElem.href = "#";
			buttonDeselectElem.onmouseover = checklistActivate;
			buttonDeselectElem.onmouseout = checklistDelayedDeactivate;
			buttonDeselectElem.onclick = checklistDeselectAll;
			listElem.parentNode.insertBefore(buttonDeselectElem, listElem);
			
			// hide stuff
			selElem.style.display = "none";
			listElem.style.display = "none";
			buttonDeselectElem.style.display = "none";
			buttonSelectElem.style.display = "none";
			
			// store some details about the checklist
			checkLists[listId] = {
				"id": listId,
				"origHeight": selHeight,
				"activated": false,
				"timerId": null,
				"selElemId": selElem.id
			};
		}
	}
}

function buildCheckList(selElem, listId) {
	var stringBuilder = new Array(0);
	var optElem, chkName;
	var inGroup = false;
	var groupName = "";
	var groupSelected;
	var rowCount = 0;
	
	for (var j = 0; j < selElem.options.length; j++) {
		optElem = selElem.options[j];
		chkName = listId + "_" + String(j);
		inGroup = (optElem.parentNode && optElem.parentNode.tagName.toLowerCase() == "optgroup");
		if (inGroup && optElem.parentNode.label != groupName) {
			groupName = optElem.parentNode.label;
			groupSelected = isGroupSelected(optElem.parentNode);
			stringBuilder.push("<li id='group_li_", chkName, "'>");
			stringBuilder.push("<a id='group_a_", chkName, "' title='", groupName, "' style='", optElem.parentNode.style.cssText, "' href='#' onclick='checklistClickLink(this, \"", listId, "\",", j,", \"", groupName, "\");return false;' class='style", String(rowCount++%2+1), (groupSelected ? "active" : "")," group'>");
			stringBuilder.push("<input onclick='checklistClickCheckbox(this, event, \"", listId, "\",", j,", \"", groupName, "\")' id='group_chk_", chkName, "' type='checkbox' value='", groupName, "'", (groupSelected ? " checked='checked'" : "") ," />");
			stringBuilder.push(groupName, "</a></li>");
		}
		stringBuilder.push("<li id='li_", chkName, "'><a id='a_", chkName, "' title='", optElem.text, "' style='", optElem.style.cssText, "' href='#' onclick='checklistClickLink(this, \"", listId, "\",", j,");return false;' class='style", String(rowCount++%2+1), (optElem.selected ? "active" : ""),(inGroup ? " ingroup" : ""), "'>");
		stringBuilder.push("<input onclick='checklistClickCheckbox(this, event, \"", listId, "\",", j,")' id='chk_", chkName, "' type='checkbox' value='", optElem.value, "'", (optElem.selected ? " checked='checked'" : "") ," />");
		stringBuilder.push(optElem.text, "</a></li>");
		if (inGroup) {
			optElem.groupName = groupName;
		}
	}
	return stringBuilder.join("");
}

function isGroupSelected(optGroup) {
	return false;
}

function buildSelectedOptions(selElem) {
	var stringBuilder = new Array(0);
	var optionsHtml = "<div class='checklistDisplayNoneSelected'>None selected</div>";
	
	for (var j = 0; j < selElem.options.length; j++) {
		if (selElem.options[j].selected) {
			stringBuilder.push((stringBuilder.length > 0 ? "~" : ""), selElem.options[j].text);
		}
	}
	if (stringBuilder.length > 0) {
		optionsHtml = stringBuilder.join("").replace(/~([^~]*)$/gi, " &amp; $1").replace(/~/gi, ", ");
	}
	return "<div class='checklistDisplayInner'>" + optionsHtml + "</div>";
}

function checklistClickLink(linkElem, listId, optIndex, groupName, checked) {
	var checkList = checkLists[listId];
	var selElem = document.getElementById(checkList.selElemId);
	var optElem, subLinkElem;
	
	checked = (checked == null ? !linkElem.firstChild.checked : checked);
	
	if (!groupName) {
		selElem.options[optIndex].selected = checked;
	} else {
		setGroupChecked(groupName, selElem, listId, optIndex, checked);
	}
	
	linkElem.firstChild.checked = checked;
	checklistSetLinkClass(linkElem, checked);
}

function checklistClickCheckbox(chkboxElem, e, listId, optIndex, groupName, checked) {
	var checkList = checkLists[listId];
	var selElem = document.getElementById(checkList.selElemId);
	
	checked = (checked == null ? chkboxElem.checked : checked);
	
	if (!groupName) {
		selElem.options[optIndex].selected = checked;
	} else {
		setGroupChecked(groupName, selElem, listId, optIndex, checked);
	}
	
	checklistSetLinkClass(chkboxElem.parentNode, checked)
	cancelBubble(e);
}

function setGroupChecked(groupName, selElem, listId, optIndex, checked) {
	var subLinkElem;
	
	for (var i = optIndex; i < selElem.options.length; i++) {
		optElem = selElem.options[i];
		if (optElem.groupName == groupName) {
			if (optElem.selected != checked) {
				subLinkElem = document.getElementById("a_" + listId + "_" + String(i));
				checklistClickLink(subLinkElem, listId, i, null, checked)
			}
		} else {
			break;
		}
	}
}

function checklistSetLinkClass(linkElem, checked) {
	linkElem.className = linkElem.className.replace(/style([12])(active)?/, "style$1" + (checked ? "active" : ""));
}

function checklistDisplayOver(e) {
	var checkList = getChecklistFromId(this.id);
	var displayElem = document.getElementById(checkList.id + "_display");
	var buttonSelectElem = document.getElementById(checkList.id + "_button_select");
		
	buttonSelectElem.style.display = "block";
	buttonSelectElem.style.top = ((findPos(displayElem).top - buttonSelectElem.offsetHeight) + 1) + "px";		
}

function checklistDisplayOut(e) {
	var checkList = getChecklistFromId(this.id);
	var buttonSelectElem = document.getElementById(checkList.id + "_button_select");
		
	buttonSelectElem.style.display = "none";
}

function checklistActivate(e) {
	var checkList = getChecklistFromId(this.id);
	var listElem = document.getElementById(checkList.id);
	var buttonSelectElem = document.getElementById(checkList.id + "_button_select");
	var buttonDeselectElem = document.getElementById(checkList.id + "_button_deselect");
	if (!e) var e = window.event;
	
	if (checkList.timerId)
		clearTimeout(checkList.timerId);
	if (!checkList.activated) {
		checkList.activated = true;
		listElem.style.position = "absolute";
		listElem.style.display = "block";
		listElem.style.height = checkList.origHeight + "px";
		listElem.style.height = Math.min(Math.min(Math.floor(checkList.origHeight * checklistExpansion), checklistExpansionMax), listElem.scrollHeight) + "px";
		
		buttonDeselectElem.style.display = "block";
		buttonDeselectElem.style.top = (findPos(listElem).top + listElem.clientHeight + 2) + "px";
		
		buttonSelectElem.innerHTML = "OK";
		buttonSelectElem.onmouseover = checklistActivate;
		buttonSelectElem.onmouseout = checklistDelayedDeactivate;
		buttonSelectElem.onclick = checklistNoDelayDeactivate;
		
		var yOverflow = (findPos(buttonDeselectElem).top + buttonDeselectElem.offsetHeight) - (f_clientHeight() + f_scrollTop());
		if (yOverflow > 0) {
			window.scroll(0, yOverflow);
		}
	}
		
	buttonSelectElem.style.display = "block";
	buttonSelectElem.style.top = ((findPos(listElem).top - buttonSelectElem.offsetHeight) + 1) + "px";
	
	return false;
}

function checklistDelayedDeactivate(e) {
	var checkList = getChecklistFromId(this.id);
	if (!e) var e = window.event;
	
	if (checkList.timerId)
		clearTimeout(checkList.timerId);
	checkList.timerId = setTimeout("checklistDeactivate('" + checkList.id + "')", 500);
	
	return false;
}

function checklistNoDelayDeactivate(e) {
	var checkList = getChecklistFromId(this.id);
	if (!e) var e = window.event;
	
	if (checkList.timerId)
		clearTimeout(checkList.timerId);
	checklistDeactivate(checkList.id);
	
	return false;
}

function checklistDeactivate(listId) {
	var checkList = checkLists[listId];
	var listElem = document.getElementById(checkList.id);
	var buttonSelectElem = document.getElementById(checkList.id + "_button_select");
	var buttonDeselectElem = document.getElementById(checkList.id + "_button_deselect");

	checkList.timerId = null;
	checkList.activated = false;
	listElem.style.display = "none";
	listElem.style.position = "";
	
	checklistUpdateOptionsText(checkList.id);

	buttonSelectElem.innerHTML = "Select";
	buttonSelectElem.onmouseover = checklistDisplayOver;
	buttonSelectElem.onmouseout = checklistDisplayOut;
	buttonSelectElem.onclick = checklistActivate;
	buttonSelectElem.style.display = "none";
	buttonSelectElem.blur();

	buttonDeselectElem.style.display = "none";
}

function checklistUpdateOptionsText(listId) {
	var checkList = checkLists[listId];
	var displayElem = document.getElementById(listId + "_display");
	var selElem = document.getElementById(checkList.selElemId);
	// it would be nice just to set checkList.displayElem.innerHTML to our new list
	// but for no apparent reason IE throws a runtime error if you try
	// so instead we do this...
	displayElem.innerHTML = "";
	var displayElemText = document.createElement("DIV");
	displayElemText.className = "checkistDisplayInner";
	displayElemText.innerHTML = buildSelectedOptions(selElem);
	displayElem.appendChild(displayElemText);
}

function checklistDeselectAll(e) {
	var checkList;
	var selElem;
	var subLinkElem;
	var groupName = "";
	
	if (typeof(e) == "string") {
		checkList = getChecklistFromId(e);
	} else {
		checkList = getChecklistFromId(this.id);
		if (!e) var e = window.event;
		this.blur();
	}
	selElem = document.getElementById(checkList.selElemId);
	
	for (var j = 0; j < selElem.options.length; j++) {
		if (selElem.options[j].groupName && selElem.options[j].groupName != groupName) {
			subLinkElem = document.getElementById("group_a_" + checkList.id + "_" + String(j));
			checklistClickLink(subLinkElem, checkList.id, j, groupName, false);
		}
		groupName = selElem.options[j].groupName;
		//if (selElem.options[j].selected) {
			selElem.options[j].selected = false;
			document.getElementById("chk_" + checkList.id + "_" + String(j)).checked = false;
			checklistSetLinkClass(document.getElementById("a_" + checkList.id + "_" + String(j)), false);
		//}
	}
	
	checklistUpdateOptionsText(checkList.id);
	
	return false;
}

function getChecklistFromId(anyId) {
	if (anyId.substr(0, 7) != "chklst_") {
		anyId = "chklst_" + anyId;
	}
	return checkLists[anyId.replace(/_(button_select|button_deselect|display)$/gi, "")];
}

function findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return { "left": curleft, "top": curtop };
}

function cancelBubble(e) {
	if (!e) e = window.event;
	e.cancelBubble = true;
	if (e.stopPropagation)
		e.stopPropagation();
}

function onDomReady(funcToCall) {
		if (document.addEventListener) {
            document.addEventListener("DOMContentLoaded", funcToCall, false);
        } else {
            document.write("<scr" + "ipt id='__ieinit' defer='true' " + "src='//:'><\/script>");
            var script = document.getElementById("__ieinit");
            script.onreadystatechange = function() {
                if (this.readyState != "complete") return;
                this.parentNode.removeChild(this);
                funcToCall();
            }
            script = null;
        }
};

function f_clientWidth() {
	return f_filterResults (
		window.innerWidth ? window.innerWidth : 0,
		document.documentElement ? document.documentElement.clientWidth : 0,
		document.body ? document.body.clientWidth : 0
	);
}
function f_clientHeight() {
	return f_filterResults (
		window.innerHeight ? window.innerHeight : 0,
		document.documentElement ? document.documentElement.clientHeight : 0,
		document.body ? document.body.clientHeight : 0
	);
}
function f_scrollLeft() {
	return f_filterResults (
		window.pageXOffset ? window.pageXOffset : 0,
		document.documentElement ? document.documentElement.scrollLeft : 0,
		document.body ? document.body.scrollLeft : 0
	);
}
function f_scrollTop() {
	return f_filterResults (
		window.pageYOffset ? window.pageYOffset : 0,
		document.documentElement ? document.documentElement.scrollTop : 0,
		document.body ? document.body.scrollTop : 0
	);
}
function f_filterResults(n_win, n_docel, n_body) {
	var n_result = n_win ? n_win : 0;
	if (n_docel && (!n_result || (n_result > n_docel)))
		n_result = n_docel;
	return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
}

function getDimensions(elem, dontTryShowHide) {
	var dims = { x: 0, y: 0 };
	
	dims.x = elem.offsetWidth;
	if (!dims.x) {
		if (!dontTryShowHide) {
			dims = getDimensionsShowHide(elem);
		}
	} else {
		dims.y = elem.offsetHeight;
	}
	
	return dims;
}

function getDimensionsShowHide(elem) {
	var parent = elem;
	var elems = [];
	var dims = { x: 0, y: 0 };
	
	while (parent) {
		if ((parent.style && parent.style.display == "none")) { // (parent.currentStyle && parent.currentStyle.display == "none") || 
			parent.style.display = "block";
			elems[elems.length] = parent;
		}
		parent = parent.parentElement || parent.parentNode || parent.offsetParent;
	}
	if (elems.length > 0) {
		dims = getDimensions(elem, true);
		for (var i = elems.length - 1; i >= 0; i--) {
			elems[i].style.display = "none";
		}
	}
	
	return dims;
}

// transform
onDomReady(transformMultiSelects);

