// Global.js - Global javascript source file for the Thirteen namespace
// Dependencies: Prototype Javascript Framework, http://www.prototypejs.org
// Developed entirely by Richard Vance, created circa 2008
// http://www.13d.org

// global variables
var globals = { };
var timerID = null;
var currentAjaxRequest;

// The Thirteenth Dimension namespace
var Thirteen = {

	Library:
	{
		_prototypeLoaded: false,
		_scriptaculousLoaded: false,
		_logLoaded: false,
		_passLoaded: false,
	
		init: 
			function() 
			{
				if (typeof Prototype == "undefined")
				{
					document.write("<script type='text/javascript'>alert('Prototype not loaded properly.);</script>");
					return;
				}
				
				this._prototypeLoaded = true;
				this.finishInit();
			},
		
		finishInit:
			function()
			{
				Object.extend(Prototype.Browser, { Safari: navigator.userAgent.indexOf("Safari") > -1 });
				Object.extend(Prototype.Browser, { Konqueror: navigator.userAgent.indexOf("Konqueror") > -1 });
				Object.extend(Prototype.Browser, { MacIE: navigator.userAgent.match(/MSIE.*Mac/) });

				$$("script").findAll( this._examineScriptTag.bind(this) ).each( this._findLibraryAndLoad.bind(this) );
			},
	
		load: 
			function(lib) 
			{
				document.write("<script type='text/javascript' src='" + lib + "'><\/script>");
			},
		
		_examineScriptTag:
			function(obj)
			{
				if (!obj.src)
				{
					return false;
				}
				this._prototypeLoaded = this._prototypeLoaded || obj.src.match(/prototype\.js/);
				this._scriptaculousLoaded = this._scriptaculousLoaded || obj.src.match(/scriptaculous\.js/);
				this._logLoaded = this._logLoaded || obj.src.match(/log_include|log_whatnot/);
				this._passLoaded = this._passLoaded || obj.src.match(/include\.js\.cfm/);
				return obj.src.match(/Global\.js/);
			},
	
		_findLibraryAndLoad:
			function(globalPath)
			{
				var includePath = globalPath.src.replace(/Global\.js/, "");
				$A( [ "scriptaculous/scriptaculous.js" ] ).each(
						function(lib) 
						{ 
							Thirteen.Library.load(includePath + lib) 
						}
					);
			}
	}
};

Thirteen.Library.init();

Object.extend(Thirteen,

{



// ********************************************************************************************************************

//
// TransferListsHandler - encapsulates client-side functionality for two "transfer lists", or select controls with 
//                          options that can move between the controls.
//
// constructor parameters:  - leftSelectID (required) - the ID of the left select control
//                          - leftListID (required) - the ID of the left hidden field
//                          - rightSelectID (required) - the ID of the right select control
//                          - rightListID (required) - the ID of the right hidden field
//                          - leftListIsSupplier (optional) - a boolean indicating which list is the supplier, because 
//                              the other list's options need to be removed from the supplier list during 
//                              initialization; defaults to true
//                          - listDelimiter (optional) - the delimiter separating the options in the hidden field values; 
//                              defaults to "^"
//                          - pairDelimiter (optional) - the delimiter separating the value and text pairs for each 
//                              option in the hidden field values; defaults to "~"
//
// public functions:        - moveAllLeft() - moves all options from the right select to the left select 
//                          - moveAllRight() - moves all options from the left select to the right select
//                          - moveSelectionToLeft() - moves all selected options from the right select to the left select
//                          - moveSelectionToRight() - moves all selected options from the left select to the right select

TransferListsHandler: Class.create(
    {
        initialize:
                function(leftSelectID, leftListID, rightSelectID, rightListID, leftListIsSupplier, listDelimiter, pairDelimiter)
                {
                    this.leftSelectID = leftSelectID;
                    this.leftListID = leftListID;
                    this.rightSelectID = rightSelectID;
                    this.rightListID = rightListID;
                    
                    if (leftListIsSupplier != undefined)
                    {
                        this.leftListIsSupplier = leftListIsSupplier;
                    }
                    else
                    {
                        this.leftListIsSupplier = true;
                    }
                    if (listDelimiter != undefined)
                    {
                        this.listDelim = listDelimiter;
                    }
                    else
                    {
                        this.listDelim = "^";
                    }
                    if (pairDelimiter != undefined)
                    {
                        this.pairDelim = pairDelimiter;
                    }
                    else
                    {
                        this.pairDelim = "~";
                    }
                    
                    this.leftSelect = $(this.leftSelectID);
                    this.leftList = $(this.leftListID);
                    this.rightSelect = $(this.rightSelectID);
                    this.rightList = $(this.rightListID);
                    
                    if (this.leftListIsSupplier)
                    {
                        this._populateLeftSelect();
                        this._populateRightSelect();
                    }
                    else
                    {
                        this._populateRightSelect();
                        this._populateLeftSelect();
                    }
                },
        
        type:   "TransferListsHandler",
        
        moveAllLeft:
                function()
                {
                    for (var i = 0; i < this.rightSelect.options.length; i++)
                    {
                        this._addToLeft(this.rightSelect.options[i].value, this.rightSelect.options[i].text);
                    }
                    
                    this._removeAllFromRight();
                    this._recalcLeftList();
                    this._recalcRightList();
                },
        
        moveAllRight:
                function()
                {
                    for (var i = 0; i < this.leftSelect.options.length; i++)
                    {
                        this._addToRight(this.leftSelect.options[i].value, this.leftSelect.options[i].text);
                    }
                    
                    this._removeAllFromLeft();
                    this._recalcLeftList();
                    this._recalcRightList();
                },
                    
        moveSelectionToLeft:
                function()
                {
                    if (this.rightSelect.selectedIndex == -1)
                    {
                        return;
                    }
                    
                    var selectedOptions = this._getSelectedOptions(this.rightSelect);
                    this.rightSelect.selectedIndex = -1;

                    for (var i = 0; i < selectedOptions.length; i++)
                    {
                        this._removeFromRight(selectedOptions[i][0]);
                        this._addToLeft(selectedOptions[i][1], selectedOptions[i][2]);
                    }
                    
                    this.leftSelect.selectedIndex = -1;
                    this._recalcLeftList();
                    this._recalcRightList();
                },

        moveSelectionToRight:
                function()
                {
                    if (this.leftSelect.selectedIndex == -1)
                    {
                        return;
                    }
                    
                    var selectedOptions = this._getSelectedOptions(this.leftSelect);
                    this.leftSelect.selectedIndex = -1;

                    for (var i = 0; i < selectedOptions.length; i++)
                    {
                        this._removeFromLeft(selectedOptions[i][0]);
                        this._addToRight(selectedOptions[i][1], selectedOptions[i][2]);
                    }
                    
                    this.rightSelect.selectedIndex = -1;
                    this._recalcLeftList();
                    this._recalcRightList();
                },
                
        refresh:
                function()
                {
                    if (this.leftListIsSupplier)
                    {
                        this._populateLeftSelect();
                        this._populateRightSelect();
                    }
                    else
                    {
                        this._populateRightSelect();
                        this._populateLeftSelect();
                    }
                },
                
        _getSelectedOptions:
                function(selectObj)
                {
                    var selections = new Array();
                    for (var i = selectObj.options.length - 1; i >= 0 ; i--)
                    {
                        if (selectObj.options[i].selected)
                        {
                            selections[selections.length++] = new Array(i, selectObj.options[i].value, selectObj.options[i].text);
                        }
                    }
                    
                    return selections;
                },
                
        _addToLeft:
                function(value, text)
                {
                    var newIdx = this.leftSelect.options.length++;
                    this.leftSelect.options[newIdx].value = value;
                    this.leftSelect.options[newIdx].text = text;
                },
                
        _addToRight:
                function(value, text)
                {
                    var newIdx = this.rightSelect.options.length++;
                    this.rightSelect.options[newIdx].value = value;
                    this.rightSelect.options[newIdx].text = text;
                },
        
        _removeFromLeft:
                function(index)
                {
                    for (var i = index; i < (this.leftSelect.options.length - 1); i++)
                    {
                        this.leftSelect.options[i].value = this.leftSelect.options[i + 1].value;
                        this.leftSelect.options[i].text = this.leftSelect.options[i + 1].text;
                    }
                    
                    this.leftSelect.options.length--;
                },
                
        _removeFromRight:
                function(index)
                {
                    for (var i = index; i < (this.rightSelect.options.length - 1); i++)
                    {
                        this.rightSelect.options[i].value = this.rightSelect.options[i + 1].value;
                        this.rightSelect.options[i].text = this.rightSelect.options[i + 1].text;
                    }
                    
                    this.rightSelect.options.length--;
                },
                        
        _removeAllFromLeft:
                function()
                {
                    this.leftSelect.selectedIndex = -1;
                    this.leftSelect.options.length = 0;
                },
                
        _removeAllFromRight:
                function()
                {
                    this.rightSelect.selectedIndex = -1;
                    this.rightSelect.options.length = 0;
                },
                
        _recalcLeftList:
                function()
                {
                    var newList = "";
                    var delim = "";
                    for (var i = 0; i < this.leftSelect.options.length; i++)
                    {
                        newList += delim + this.leftSelect.options[i].value + this.pairDelim + this.leftSelect.options[i].text;
                        delim = this.listDelim;
                    }
                    this.leftList.value = newList;
                },
                
        _recalcRightList:
                function()
                {
                    var newList = "";
                    var delim = "";
                    for (var i = 0; i < this.rightSelect.options.length; i++)
                    {
                        newList += delim + this.rightSelect.options[i].value + this.pairDelim + this.rightSelect.options[i].text;
                        delim = this.listDelim;
                    }
                    this.rightList.value = newList;
                },
                
        _indexOfValueInSelect:
                function(val, selectObj)
                {
                    var idx = -1;
                    for (var i = 0; i < selectObj.options.length; i++)
                    {
                        if (selectObj.options[i].value == val)
                        {
                            idx = i;
                            break;
                        }
                    }
                    return idx;
                },
        
        _populateLeftSelect:
                function()
                {
                    this._removeAllFromLeft();
                    if (this.leftList == null || this.leftList.value.length == 0)
                    {
                        return;
                    }
                    
                    var pairs = this.leftList.value.split(this.listDelim);
                    for (var i = 0; i < pairs.length; i++)
                    {
                        var parts = pairs[i].split(this.pairDelim);
                        if (this.leftListIsSupplier == false && this._indexOfValueInSelect(parts[0], this.rightSelect) != -1)
                        {
                            this._removeFromRight( this._indexOfValueInSelect(parts[0], this.rightSelect) );
                            this._recalcRightList();
                        }
                        this._addToLeft(parts[0], parts[1]);
                    }
                },
                
        _populateRightSelect:
                function()
                {
                    this._removeAllFromRight();
                    if (this.rightList == null || this.rightList.value.length == 0)
                    {
                        return;
                    }
                    
                    var pairs = this.rightList.value.split(this.listDelim);
                    
                    for (var i = 0; i < pairs.length; i++)
                    {
                        var parts = pairs[i].split(this.pairDelim);
                        if (this.leftListIsSupplier == true && this._indexOfValueInSelect(parts[0], this.leftSelect) != -1)
                        {
                            this._removeFromLeft( this._indexOfValueInSelect(parts[0], this.leftSelect) );
                            this._recalcLeftList();
                        }
                        this._addToRight(parts[0], parts[1]);
                    }
                }
    }
),

// ********************************************************************************************************************
Util:
{

	globalOnBodyLoad: function(basePath)
	{
	    if (basePath != undefined)
	    {
	        globals["basePath"] = basePath;
	    }
	    
	    Thirteen.Util.preloadWaitingImage();
	    
	    if (globals["onBodyLoad"] != undefined)
	    {
	        globals["onBodyLoad"]();
	    }
	    
	    if (Thirteen.Workspace.onBodyLoaded != undefined)
	    {
	    	Thirteen.Workspace.onBodyLoaded();
	    }
	},
	
	preloadWaitingImage: function()
	{
	    Thirteen.Util.preloadedWaiter = new Image;
	    Thirteen.Util.preloadedWaiter.onload = Thirteen.Util.onWaitImgLoaded;
	    Thirteen.Util.preloadedWaiter.onerror = Thirteen.Util.onWaitImgError;
	    Thirteen.Util.preloadedWaiter.onabort = Thirteen.Util.onWaitImgAbort;
	    
	    Thirteen.Util.waitingImageLoaded = false;
	    Thirteen.Util.waitingImagePath = "/images/";
	    Thirteen.Util.waitingImageSrc = "snake_transparent.gif";
	    Thirteen.Util.preloadedWaiter.src = globals["basePath"] + Thirteen.Util.waitingImagePath + Thirteen.Util.waitingImageSrc;
	},
	
	onWaitImgLoaded: function()
	{
		Thirteen.Util.waitingImageLoaded = true;
		Thirteen.Util.onWaitImgComplete();
	},
	
	onWaitImgError: function()
	{
		Thirteen.Util.onWaitImgComplete();
	},
	
	onWaitImgAbort: function()
	{
		Thirteen.Util.onWaitImgComplete();
	},
	
	onWaitImgComplete: function()
	{
	},

	executeAfterPageLoad: function( func )
	{
	    if (document.all)
	    {
	        document.body.onload = function() { func(); };
	    }
	    else if (document.addEventListener)
	    {
	        document.addEventListener(
	            'DOMContentLoaded',
	            function() { func(); },
	            true);
	    }
	
	},

	numberValidate: function(fld, alertText)
	{
		if ($F(fld) == "")
		{
			return true;
		}
		var isValid = !isNaN($F(fld));
		if (!isValid)
		{
			if (alertText != undefined && alertText != null && alertText != "")
			{
				alert(alertText);
			}
			fld.focus();
			fld.select();
		}
		return isValid;
	},

	wholeNumberValidate: function(fld, alertText)
	{
		if ($F(fld) == "")
		{
			return true;
		}
		var isValid = Thirteen.Util.numberValidate(fld);
		isValid = isValid && ($F(fld).indexOf(".") == -1);
		if (!isValid)
		{
			if (alertText != undefined && alertText != null && alertText != "")
			{
				alert(alertText);
			}
			fld.focus();
			fld.select();
		}
		return isValid;
	},

	dateValidate: function(fld, alertText)
	{
		var value = $F(fld);
		var isValid = true;
		if (value == "")
		{
			return isValid;
		}
		
		isValid = !(/[a-zA-Z]/.test(value));
		
		try
		{
			var testValue = new Date(value);
			isValid = isValid && !isNaN(testValue.getTime()) && (testValue.getTime() > 0);
		}
		catch (e)
		{
			isValid = isValid && false;
		}
	
		if (!isValid)
		{
			if (alertText != undefined && alertText != null && alertText != "")
			{
				alert(alertText);
			}
			fld.focus();
			fld.select();
		}	
		return isValid;
	},
	
	getDateString: function(dateValue)
	{
		var monthPart = "" + (dateValue.getMonth() + 1);
		if (monthPart.length == 1)
		{
			monthPart = "0" + monthPart;
		}
		var dayPart = "" + dateValue.getDate();
		if (dayPart.length == 1)
		{
			dayPart = "0" + dayPart;
		}
		var yearPart = dateValue.getFullYear();
		
		return monthPart + "/" + dayPart + "/" + yearPart;
	},

	getTimeString: function(dateValue)
	{
		var hourPart = "" + dateValue.getHours();
		if (hourPart.length == 1)
		{
			hourPart = "0" + hourPart;
		}
		var minutePart = "" + dateValue.getMinutes();
		if (minutePart.length == 1)
		{
			minutePart = "0" + minutePart;
		}
		var secondPart = dateValue.getSeconds();
		if (secondPart.length == 1)
		{
			secondPart = "0" + secondPart;
		}
		
		return hourPart + ":" + minutePart + ":" + secondPart;
	},

	getDateTimeString: function(dateValue)
	{
		return Thirteen.Util.getDateString(dateValue) + " " + Thirteen.Util.getTimeString(dateValue);
	},
	
	dollarFormat: function(fld, commaDelimitFlag)
	{        
	    var dollarAmount = fld.value.replace("$", "");
	    var digits = null;
	    var valLength = dollarAmount.length;
	    var pointIdx = dollarAmount.indexOf(".", 0, valLength);
	    
	    if (isNaN(dollarAmount)) 
	    {
	        return;
	    }
	    if (commaDelimitFlag == undefined)
	    {
	        commaDelimitFlag = false;
	    }
	    if (pointIdx == -1)
	    {
	        digits = 0;
	    }
	    else             
	    {
	        digits = valLength - pointIdx;
	    }
	
	    switch (digits)
	    {
	        case 0:
	            dollarAmount += ".00";
	            break;
	        case 1:
	            dollarAmount += "00";
	            break;
	        case 2:
	            dollarAmount += "0";
	            break;
	        case 3:
	            break;
	        default:
	            dollarAmount = dollarAmount.substr(0, valLength - digits + 3);
	            break;
	    }
	    if (commaDelimitFlag == true)
	    {
	        var phraseIndex = 6;
	        
	        while (dollarAmount.length > phraseIndex)
	        {
	            dollarAmount = dollarAmount.substr(0, dollarAmount.length - phraseIndex) + "," + dollarAmount.substr(dollarAmount.length - phraseIndex, phraseIndex);
	            phraseIndex += 4;
	        }
	    }
	    dollarAmount = "$" + dollarAmount;
	    
	    fld.value = dollarAmount;
	},

	dollarValidate: function(fld, formatFlag, commaDelimitFlag, alertText)
	{
	    var validChars = "0123456789.,$";
	    var stripRE = /[\$,]/g;
	    var fieldValue = fld.value;
	    var digitCount = 0;
	    var replaceComma = false;
	    var isValid = true;
	
	    if (fieldValue == "")
	    {
	        return;
	    }
	    
	    if (formatFlag == undefined)
	    {
	        formatFlag = false;
	    }
	    if (commaDelimitFlag == undefined)
	    {
	        commaDelimitFlag = false;
	    }
	    
	    // make sure that only valid characters are present
	    for (var i = 0; i < fieldValue.length; i++)
	    {
	        if (validChars.indexOf(fieldValue.charAt(i)) == -1)
	        {
	            isValid = false;
	        }
	    }
	    
		if (!isValid)
		{
			if (alertText != undefined && alertText != null && alertText != "")
			{
				alert(alertText);
			}
			fld.focus();
			fld.select();
		}
		if (isValid)
		{
			fld.value = fieldValue.replace(stripRE, "");
		    if (formatFlag)
		    {
		        Thirteen.Util.dollarFormat(fld, commaDelimitFlag);
		    }
	    }
		return isValid;
	},
    
	debugWatchAlert: function(fieldlist)
	{
	    var flds;
	    eval("flds = { " + fieldlist + " };");
	    var alertText = "";
	    $H(flds).each(
	                    function(fld)
	                    {
	                        alert(fld.key);
	                    }
	                );
	    
	},

	debugGlobalsAlert: function()
	{
	    $H(globals).each(
	                    function(fld)
	                    {
	                        alert("globals[" + fld.key + "] = '" + fld.value + "'");
	                    }
	                );
	    
	},

	getQueryStringParam: function(key)
	{
	    var qs = document.location.search;
	    var qh = $H(qs.toQueryParams());
	    
	    qh.keys().each(
	            function(browseKey)
	            {
	                if (qh.get(browseKey.toUpperCase()) == undefined)
	                {
	                    qh.set(browseKey.toUpperCase(), qh.get(browseKey));
	                }
	            }
	        );
	        
	    if (qh.get(key.toUpperCase()) != undefined)
	    {
	        return unescape(qh.get(key.toUpperCase()));
	    }
	    else
	    {
	        return qh.get(key.toUpperCase());
	    }
	},

	disableEnterKey: function()
	{
	    document.onkeypress = killEnterKey;
	    if (document.layers) 
	    {
	        document.captureEvents(Event.KEYPRESS);
	    }
	},

	killEnterKey: function(e) 
	{
	    var pK = e ? e.which : window.event.keyCode;
	    return pK != 13;
	},

	rerouteEnterKeyTo: function(btn)
	{
	    document.onkeypress = checkEnterKeyForReroute;
	    globals["rerouteEnterKeyToDestination"] = $(btn);
	    if (document.layers)
	    {
	        document.captureEvents(Event.KEYPRESS);
	    }
	},

	checkEnterKeyForReroute: function(e)
	{
	    var pK = e ? e.which : window.event.keyCode;
	    if (pK != 13)
	    {
	        return true;
	    }
	    else if (globals["rerouteEnterKeyToDestination"].click)
	    {
	        globals["rerouteEnterKeyToDestination"].click();
	        return false;
	    }
	},

	resetDivHeight: function(divID)
	{
	    if ( $(divID).style.removeAttribute )
	    {
	        $(divID).style.removeAttribute("height");
	    }
	    else
	    {
	        var saver = $(divID).scrollHeight + "px";
	        $(divID).style.height = "";
	        $(divID).style.height = saver;
	        $(divID).style.minHeight = saver;
	    }
	},

	applyDivHeight: function(divID, targetHeight)
	{
	    if ($(divID).clientHeight > targetHeight)
	    {
	        $(divID).style.height = targetHeight + "px";
	        $(divID).style.minHeight = targetHeight + "px";
	    }
	},
	
	getVisibleTableDisplayValue: function()
	{
		var val = "table";
		if (Prototype.Browser.IE)
		{
			val = "block";
		}
		return val;
	},
	
	getVisibleRowDisplayValue: function()
	{
		var val = "table-row";
		if (Prototype.Browser.IE)
		{
			val = "block";
		}
		return val;
	},
	
	getVisibleCellDisplayValue: function()
	{
		var val = "table-cell";
		if (Prototype.Browser.IE)
		{
			val = "block";
		}
		return val;
	}
},


// ********************************************************************************************************************
// Floating Message Divs - allow javascript to display waiting messages, error messages, and confirmation messages
// within the HTML document.
//
// constructor parameters:  - divID (required) - the id of the div coded into the page where the message div will be contained.
//                          - width (optional) - the initial width of the message div; default is 250
//                          - height (optional) - the initial height of the message div; default is 120
//
// public functions:        - showWaiting(msg) - show the message div with the provided message and a spinner
//                          - showComment(msg, duration) - show the message div with the provided message for
//                              the provided duration in seconds; defaults to 1 second
//                          - showAlert(msg) - show the message div with the provided message and an OK button to 
//                              close the message div
//                          - showError(title, msg) - show the message div with the provided title and message, and
//                              an OK button to close the message div
//                          - showConfirmation(msg, resultFunc) - show the message div with the provided message, a Yes button,
//                              and a No button, returning the results to the specified function
//                          - showConfirmationWithDetails(msg, details, resultFunc) - similar to showConfirmation, except
//                              details about the topic being decided are also displayed in the body of the div
//                          - hide() - hide the message div
//                          - resize(width, height) - resize the message div to the provided width and height
// ********************************************************************************************************************

FloatingMessageDiv: Class.create(
    {
        initialize:
                function(divID, options)
                {
                    this.outerDivID = divID;
                    this.outerDiv = $(this.outerDivID);
                    if (Prototype.Browser.IE)
                    {
                        this.outerDiv.style.position = "absolute";
                        this.outerDiv.style.left = "0";
                        this.outerDiv.style.top = "0";
                    }

                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
                                        width: 250, 
										height: 120,
										zIndex: "75",
										defaultHeaderText: "The Thirteenth Dimension says",
										cssClass: "floatingMessageDiv",
										headerClass: "floatingMessageHeader",
										bodyClass: "floatingMessageBody",
										buttonClass: "floatingMessageButton",
										elementsToHide: null,
										commandQueue: null,
										iframeID: "divMessageCenter_IFrame"
                                    }
                                );
                    Object.extend(opt, options);

 					this.defaultHeaderText = opt.defaultHeaderText;
                    this.cssClass = opt.cssClass;
					this.headerClass = opt.headerClass;
					this.bodyClass = opt.bodyClass;
					this.buttonClass = opt.buttonClass;
					this.outerDiv.style.zIndex = opt.zIndex;
					this.elementsToHide = opt.elementsToHide;
					this.commandQueue = opt.commandQueue;
                    this.iframeID = opt.iframeID;
					this.inUse = false;
                    this.divID = "divMessageCenter";
                    this.headerID = "divMessageCenter_Header";
					this.titleID = "divMessageCenter_Title";
                    this.bodyID = "divMessageCenter_Body";
					this.ctrlID = "divMessageCenter_ConrolPanel";
					this.hideButtonID = "divMessageCenter_ButtonHide";
					this.goButtonID = "divMessageCenter_ButtonGo";
                    this.yesButtonID = "divMessageCenter_ButtonYes";
                    this.noButtonID = "divMessageCenter_ButtonNo";
                    this._createDiv();
                    this.div = new Thirteen.LayoutDiv(this.divID, { overflow: "hide", iframeID: this.iframeID });
                    this.header = $(this.headerID);
					this.title = $(this.titleID);
                    this.body = $(this.bodyID);
					this.controlPanel = $(this.ctrlID);
                    this.hideButton = $(this.hideButtonID);
					this.hideButton.value = "OK";
                    this.hideButton.observe("click", this.hide.bind(this));
                    this.goButton = $(this.goButtonID);
					this.goButton.value = "OK";
					this.goButton.observe("click", this.hide.bind(this));
					this.goButton.observe("click", this._stopAlertWaiting.bind(this));
					this.yesButton = $(this.yesButtonID);
					this.yesButton.value = "Yes";
					this.yesButton.observe("click", this._confirmYes.bind(this));
					this.noButton = $(this.noButtonID);
					this.noButton.value = "No";
					this.noButton.observe("click", this._confirmNo.bind(this));
                    this.timerID = null;
					
					this.div.div.observe("Thirteen:LayoutDivShown", this._reactToResize.bind(this));
					this.div.div.observe("Thirteen:FloatingMsgResize", this._reactToResize.bind(this));

					this.resize(opt.width, opt.height);
                    this.div.hide();
                },
        
        type:   "FloatingMessageDiv",
        
        showWaiting:
                function(msg, options)
                {
                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
										imagesPath: "/images/",
										spinnerImage: "snake_transparent.gif",
										headerText: this.defaultHeaderText
                                    }
                                );
                    Object.extend(opt, options);

                    if (this.timerID != null)
                    {
                        clearInterval(this.timerID);
                        this.timerID = null;
                    }
                    this.header.innerHTML = opt.headerText;
					this.title.style.display = "none";
                    this.body.style.display = "block";
					this.body.className = this.bodyClass;
                    this.body.style.overflow = "visible";
                    this.body.innerHTML = "<div style='margin: 0px;'>" + msg + "</div><div style='margin: 5px;'><img src='" + globals["basePath"] + opt.imagesPath + opt.spinnerImage + "' alt='' /></div>";
					this.controlPanel.style.display = "none";
                    this.div.show();
                },
        
        showComment:
                function(msg, options)
                {
                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
										duration: 1,
										headerText: this.defaultHeaderText
                                    }
                                );
                    Object.extend(opt, options);

					var amount = opt.duration * 1000;
                    this.header.innerHTML = opt.headerText;
					this.title.style.display = "none";
                    this.body.style.display = "block";
					this.body.className = this.bodyClass;
					this.body.style.overflow = "visible"
					this.body.innerHTML = msg;
					this.controlPanel.style.display = "none";
                    this.div.show();
                    this.timerID = setInterval(this.hide.bind(this), amount);
                },
                
        showAlert:
                function(msg, options)
                {
					this.alertMsg = msg;

                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
										elementsToHide: null,
										commandQueue: null,
										headerText: this.defaultHeaderText
                                    }
                                );
                    Object.extend(opt, options);

                    if (this.timerID != null)
                    {
                        clearInterval(this.timerID);
                        this.timerID = null;
                    }
					this.headerText = opt.headerText;
					if (opt.elementsToHide != null)
					{
						this.elementsToHide = opt.elementsToHide;
					}
					if (opt.elementsToHide != null)
					{
						this.commandQueue = opt.commandQueue;
					}

					if (this.elementsToHide != null && this.commandQueue != null)
					{
	                    this.goButton.style.display = "inline";
	                    this.noButton.style.display = "none";
						this.hideButton.style.display = "none";
						this.yesButton.style.display = "none";
						this._showAlertAndWait();
					}
					else
					{
	                    this.hideButton.style.display = "inline";
	                    this.noButton.style.display = "none";
						this.goButton.style.display = "none";
						this.yesButton.style.display = "none";
						this._showAlert();
					}
                },
                
        showError:
                function(title, msg, options)
                {
                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
										headerText: this.defaultHeaderText,
										titleClass: "floatingMessageSummary",
										detailsClass: "floatingMessageDetails"
                                    }
                                );
                    Object.extend(opt, options);

                    if (this.timerID != null)
                    {
                        clearInterval(this.timerID);
                        this.timerID = null;
                    }
                    this.header.innerHTML = opt.headerText;
					this.title.style.display = "inline";
					this.title.className = opt.titleClass;
					this.title.innerHTML = title;
                    this.body.style.display = "block";
					this.body.className = opt.detailsClass;
					this.body.innerHTML = msg;
                    this.body.style.overflow = "auto";
					this.controlPanel.style.display = "inline";
                    this.hideButton.style.display = "inline";
					this.goButton.style.display = "none";
					this.yesButton.style.display = "none";
                    this.noButton.style.display = "none";
                    this.div.show();
                },
        
        showConfirmation:
                function(msg, resultFunc, options)
                {

                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
										headerText: this.defaultHeaderText
                                    }
                                );
                    Object.extend(opt, options);

                    if (this.timerID != null)
                    {
                        clearInterval(this.timerID);
                        this.timerID = null;
                    }
                    this._confirmResultFunc = resultFunc;
                    this.header.innerHTML = opt.headerText;
					this.title.style.display = "none";
                    this.body.style.display = "inline";
					this.body.className = this.bodyClass;
					this.body.innerHTML = msg;
					this.body.style.overflow = "visible";
					this.controlPanel.style.display = "block";
                    this.yesButton.style.display = "inline";
                    this.noButton.style.display = "inline";
					this.goButton.style.display = "none";
					this.hideButton.style.display = "none";

					if (this.inUse)
					{
						return;
					}
					
					this.inUse = true;
					
					if (this.commandQueue != null)
					{
	                    this.commandQueue.enqueue( this._showConfirmTask.bind(this), this.isCurrentProcessFinished.bind(this) );
					}
					else
					{
						this._showConfirmTask();
					}
                },
                
        showConfirmationWithDetails:
                function(msg, details, resultFunc, options)
                {
                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
										headerText: this.defaultHeaderText,
										messageClass: "floatingMessageSummary",
										detailsClass: "floatingMessageDetails"
                                    }
                                );
                    Object.extend(opt, options);

                    if (this.timerID != null)
                    {
                        clearInterval(this.timerID);
                        this.timerID = null;
                    }
                    this._confirmResultFunc = resultFunc;
                    this.header.innerHTML = opt.headerText;
					this.title.style.display = "inline";
					this.title.className = opt.messageClass;
					this.title.innerHTML = msg;
                    this.body.style.display = "block";
					this.body.className = opt.detailsClass;
					this.body.innerHTML = details;
                    this.body.style.overflow = "auto";
					this.controlPanel.style.display = "inline";
                    this.yesButton.style.display = "inline";
                    this.noButton.style.display = "inline";
					this.goButton.style.display = "none";
					this.hideButton.style.display = "none";
                    this.div.show();
                },
                
        hide:
                function()
                {
                    if (this.timerID != null)
                    {
                        clearInterval(this.timerID);
                        this.timerID = null;
                    }
                    this.div.hide();
                },
        
        resize:
                function(width, height)
                {
                    var widthVal = parseInt(width);
                    var heightVal = parseInt(height);
                    if (isNaN(widthVal) || isNaN(heightVal))
                    {
                        return;
                    }

                    this.div.resize( { width: widthVal, height: heightVal } );
                    this.div.center();
                    
					this.title.style.width = (widthVal - 25) + "px";
                    this.body.style.width = (widthVal - 25) + "px";
                    this.body.style.marginTop = "5px";
                    this.body.style.marginBottom = "5px";

					try
					{
						this.div.div.fire("Thirteen:FloatingMsgResize", { newHeight: heightVal });
					}
					catch (e) { }
                    
                    this.goButton.style.height = "20px";
                    this.goButton.style.margin = "auto";
                    this.hideButton.style.height = "20px";
                    this.hideButton.style.margin = "auto";
                    this.yesButton.style.height = "20px";
                    this.yesButton.style.margin = "auto";
                    this.noButton.style.height = "20px";
                    this.noButton.style.margin = "auto";
                },
                
        isCurrentProcessFinished:
                function()
                {
                    return !this.inUse;
                },

		_reactToResize:
				function(evt)
				{
					var divHeight = 0;
					if (evt.eventName == "Thirteen:LayoutDivShown")
					{
						divHeight == this.div.getDimensions().height;
					}
					else if (evt.eventName == "Thirteen:FloatingMsgResize")
					{
						divHeight = evt.memo.newHeight;
					}
					
					if (divHeight == 0)
					{
						return;
					}
					
					if (this.title.style.display == "none")
					{
						this.body.style.height = "" + (divHeight - 70) + "px";
					}
					else if (divHeight > 70)
					{
						this.body.style.height = "" + (divHeight - this.title.getHeight() - 64) + "px";
					}
					else
					{
						this.body.style.height = "0px";
					}
					
				},

		_showConfirmTask:
				function()
				{
					this.div.show();
					this._confirmKeyDownBinding = this._confirmKeyDown.bind(this);
					document.observe("keydown", this._confirmKeyDownBinding);
				},
				
		_confirmKeyDown:
				function(evt)
				{
					var key = event.which || event.keyCode;
					if (key == 89)
					{
						this._confirmYes();
					}
					if (key == 78)
					{
						this._confirmNo();
					}
					
					Event.stop(evt);
				},
				
		_showAlert:
				function()
				{
					this.header.innerHTML = this.headerText;
					this.title.style.display = "none";
					this.body.style.display = "inline";
					this.body.className = this.bodyClass;
					this.body.innerHTML = this.alertMsg;
					this.controlPanel.style.display = "block";
                    this.div.show();
				},
				
		_showAlertAndWait:
				function()
				{
					var hiders;
					if (this.elementsToHide.type == "LayoutDiv" || this.elementsToHide == "FloatingMessageDiv" 
						|| Object.isString(this.elementsToHide) || Object.isElement(this.elementsToHide))
					{
						hiders = $A([ this.elementsToHide ]);
					}
					else
					{
						hiders = $A(this.elementsToHide);
					}
					for (var i = 0; i < hiders.length; i++)
					{
						if (hiders[i].type == "LayoutDiv")
						{
							hiders[i].hide();
						}
						else if (hiders[i].type == "FloatingMessageDiv")
						{
							hiders[i].div.hide();
						}
						else
						{
							hiders[i].style.display = "none";
						}
					}
                    this.commandQueue.enqueue( this._showAlertTask.bind(this), this.isCurrentProcessFinished.bind(this) );
					
				},
				
		_showAlertTask:
				function()
				{
					if (this.inUse)
					{
						return;
					}
					
					this.inUse = true;
					
					this._showAlert();
				},
				
		_stopAlertWaiting:
				function()
				{
					this.inUse = false;

					var hiders;
					if (this.elementsToHide.type == "LayoutDiv" || this.elementsToHide == "FloatingMessageDiv" 
						|| Object.isString(this.elementsToHide) || Object.isElement(this.elementsToHide))
					{
						hiders = $A([ this.elementsToHide ]);
					}
					else
					{
						hiders = $A(this.elementsToHide);
					}

					for (var i = 0; i < hiders.length; i++)
					{
						if (hiders[i].type == "LayoutDiv")
						{
							hiders[i].show();
						}
						else if (hiders[i].type == "FloatingMessageDiv")
						{
							hiders[i].div.show();
						}
						else
						{
							hiders[i].style.display = "block";
						}
					}
				},
				
        _confirmYes:
                function()
                {
					document.stopObserving("keydown", this._confirmKeyDownBinding);
                    this.hide();
                    this.inUse = false;
                    this._confirmResultFunc(true);
                },
                
        _confirmNo:
                function()
                {
					document.stopObserving("keydown", this._confirmKeyDownBinding);
                    this.hide();
                    this.inUse = false;
                    this._confirmResultFunc(false);
                },
                
        _createDiv:
                function()
                {
                    var code = "<div id='" + this.divID + "' class='" + this.cssClass + "' style='z-index: 6000;'>";
                    code += "<div id='" + this.headerID + "' class='" + this.headerClass + "'></div>";
					code += "<div id='" + this.titleID + "'></div>";
                    code += "<div id='" + this.bodyID + "' class='" + this.bodyClass + "'></div>";
                    code += "<div id='" + this.ctrlID + "' style='margin: 8px; padding: 0px;'>";
                    code += "<input type='button' class='" + this.buttonClass + " style='margin: 5px;' id='" + this.yesButtonID + "'><span>&nbsp;&nbsp;</span>";
                    code += "<input type='button' class='" + this.buttonClass + " style='margin: 5px;' id='" + this.goButtonID + "'>";
                    code += "<input type='button' class='" + this.buttonClass + "' style='margin: 5px;' id='" + this.hideButtonID + "'><span>&nbsp;&nbsp;</span>";
                    code += "<input type='button' class='" + this.buttonClass + " style='margin: 5px;' id='" + this.noButtonID + "'></div>";
                    code += "</div>";
                    
                    if (Prototype.Browser.IE)
                    {
                        code += "<iframe id='" + this.iframeID + "' style='position: absolute; z-index:5999;' scrolling='no' frameborder='0'></iframe>";
                    }
                    
                    this.outerDiv.innerHTML = code;
                }
    }
),


// ********************************************************************************************************************
// Command Queue - allows multiple javascript commands to be queued, especially when multiple asynchronous requests
// might possibly be active.
//
// constructor parameters:  - none
//
// public functions:        - enqueue(cmd, checkFunc) - adds the specified command to the Command Queue; if the 
//                              Command Queue is currently empty, execution of the specified command will begin 
//                              immediately.  If a checkFunc is specified, Command Queue knows to call that function
//                              to determine when the specified command is truly finished.
//							- queueJump(cmd, checkFunc, returnFunc) - returns the currently running command to the
//								beginning of the Command Queue, and begins running the specified command immediately.
//								After the specified checkFunc indicates that the command is finished, the command that
//								was running before the queue was jumped will begin again by calling the specified
//								returnFunc.
// ********************************************************************************************************************

CommandQueue: Class.create(
    {
        initialize:
                function()
                {
                    this.commandInProgress = false;
                    this.queue = $A();
                    this.checkerQueue = $A();
					this.tokenQueue = $A();
                    this.currentIndex = -1;
                    this.currentCheckFunc = null;
                    this.timerID = null;
                },
                
        type:   "CommandQueue",
        
        enqueue:
                function(cmd, checkFunc, token)
                {
                    if (this.commandInProgress == false)
                    {
                        this._executeCommand(cmd, checkFunc);
                    }
                    else if (token == undefined || token == null || this.tokenQueue.indexOf(token) == -1)
                    {
                        if (Object.isFunction(cmd))
                        {
                            this.queue.push(cmd);
                        }
                        else
                        {
                            this.queue.push( function() { eval(cmd); } );
                        }
                        this.checkerQueue.length = this.queue.length;
                        this.checkerQueue[this.queue.length-1] = (checkFunc == undefined || checkFunc == null) ? null : checkFunc;
						this.tokenQueue.length = this.queue.length;
						this.tokenQueue[this.queue.length-1] = (token == undefined || token == null) ? null : token;
                    }
                },
                
		queueJump:
				function(cmd, checkFunc, returnFunc)
				{
					var checkerSave = this.currentCheckFunc;
					this._stopChecking();
					if (this.commandInProgress == false)
					{
						this._executeCommand(cmd, checkFunc, returnFunc);
					}
					else
					{
						this.commandInProgress = true;
						if (returnFunc == undefined || returnFunc == null)
						{
							this.queue.unshift(null);
						}
						else
						{
							this.queue.unshift(returnFunc);
						}
						this.checkerQueue.unshift(checkerSave);
						this.currentCheckFunc = checkFunc;
						this._beginChecking();
						if (Object.isFunction(cmd))
						{
							cmd();
						}
						else if (cmd != null)
						{
							eval(cmd);
						}
					}
				},
				
        _executeCommand:
                function(cmd, checkFunc)
                {
                    this.commandInProgress = true;
                    if (checkFunc != undefined && checkFunc != null)
                    {
                        this.currentCheckFunc = checkFunc;
                        this._beginChecking();
                    }
                    if (Object.isFunction(cmd))
                    {
                        cmd();
                    }
                    else if (cmd != null)
                    {
                        eval(cmd);
                    };
                    if (this.currentCheckFunc == null)
                    {
                        this._dequeue();
                    }
                },

        _beginChecking:
                function()
                {
                    this.timerID = setInterval(this._periodicCheckFuncHandler.bind(this), 500);
                },
                
        _stopChecking:
                function()
                {
                    if (this.timerID != null)
                    {
                        clearInterval(this.timerID);
                        this.timerID = null;
                    }
                    this.currentCheckFunc = null;
                },
                
        _periodicCheckFuncHandler:
                function()
                {
                    if (this.currentCheckFunc())
                    {
                        this._stopChecking();
                        this._dequeue();
                    }
                },
                
        _dequeue:
                function()
                {
                    if (this.queue.length > 0)
                    {
                        var nextCmd = this.queue.shift();
                        var nextChecker = this.checkerQueue.shift();
                        this._executeCommand(nextCmd, nextChecker);
                    }
                    else
                    {
                        this.commandInProgress = false;
                    }
                }
    }
),

// ********************************************************************************************************************
// Ajax Hubs - uses the Prototype AJAX library, the Floating Message Div, and commonly used practices within the app
// to house the most commonly used AJAX code.
//
// constructor parameters:  - usageType (required) - the type of AjaxHub to instantiate; valid values are "load", 
//                              "save", "delete", "confirm", and "generic"
//                          - url (required) - the URL to be accessed
//                          - messager (required) - the FloatingMessageDiv instance to use for status messages
//							- options (optional) - a hash of optional parameters that can be set for this instance
//								upon instantiation.
//                          	= commandQueue - the CommandQueue instance to use to make sure none of these
//                              	asynchronous events collide
//								= method - the method of the AJAX call ("get" or "post")
//								= waitingMessage - the message to display in the messager while the AJAX call is active
//
// public functions:        - isCurrentProcessFinished() - used by the CommandQueue to determine when to move on to the
//                              next command in the queue
//                          - clearParameters() - remove all previously added parameters from this Ajax Hub instance
//                          - addParameter(key, value) - add a parameter and its value for use in a subsequent AJAX 
//                              call
//                          - attachParameter(key, id) - add a parameter and the ID of the field to reference in
//                              a subsequent AJAX call.
//                          - load(resultsDiv, onComplete) - when usageType is "load", this function retrieves 
//                              the information using the previously added parameters, and places the results in the 
//                              specified results div; an optional onComplete function can also be called afterwards 
//                              if specified
//                          - loadIntoField(resultsDiv, onComplete) - similar to the load function, except the results
//                              are placed into the value of the specified form field
//                          - loadForValue(onComplete) - similar to the load function, except the results are merely 
//                              returned as a parameter to the onComplete function
//                          - loadFor(pars, resultsDiv, onComplete) - similar to the load function, except the 
//                              parameters are specified as a string
//                          - save(onComplete) - when usageType is "save", this function makes the AJAX save call
//                              using the previously added parameters; an optional onComplete function can also
//                              be called afterwards with a parameter indicating whether the save  succeeded
//                          - del(onComplete) - when usageType is "delete", this function displays a confirmation
//                              message, and if the user clicks "Yes", it then makes the AJAX delete call using the
//                              previously added parameters; an optional onComplete function can also be called 
//                              afterwards with a parameter indicating whether the delete was confirmed and succeeded
//                          - deleteWithDetails(details, onComplete) - similar to the del function, except it includes
//                              details about the delete action that are to be displayed in the body of the
//                              confirmation window
//                          - deleteWithDetailsLoader(loader, onComplete) - similar to the del function, except it
//                              includes an Ajax Hub instance with usage type "load" that loads details to be 
//                              included in the body of the confirmation window
//                          - deleteFor(pars, onComplete) - similar to the del function, except the parameters are
//                              specified as a string
//                          - call(onComplete) - when usageType is "generic", this function makes an AJAX call, and
//                              calls the specified onComplete function with a parameter containing the resulting
//                              response text
//                          - confirmThenCall(message, details, onComplete) - when usageType is "confirm", this
//                              function displays the specified confirmation message along with the specified details
//                              in the body of the confirmation window, then makes the AJAX call with the resulting
//                              response text being returned to the specified onComplete function
//                          - loadConfirmThenCall(message, loader, onComplete) - similar to the confirmThenCall
//                              function, except it includes an Ajax Hub instance with usage type "load" that loads
//                              details to be included in the body of the confirmation window
// ********************************************************************************************************************

AjaxHub: Class.create(
    {
        initialize:
                function(usageType, url, messager, options)
                {
                    this.usageType = usageType;
                    this.url = url;
                    this.messager = messager;
					
                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
                                        commandQueue: null, 
										method: "get",
										waitingMessage: null,
										waitingMessageWidth: 250,
										waitingMessageHeight: 88,
										successMessage: null,
										successMessageWidth: 250,
										successMessageHeight: 88,
										error500Message: null,
										errorMessageWidth: 300,
										errorMessageHeight: 240,
										confirmMessageText: null,
										confirmMessageWidth: null,
										confirmMessageHeight: null,
										jsScriptsToEval: null
                                    }
                                );
                    switch (this.usageType)
                    {
                        case "load":
								Object.extend(opt,
									{
										waitingMessage: "<br />Loading...<br /><br />",
										error500Message: "The server was unable to get the requested information."
									}
								);
                                break;
                        case "save":
								Object.extend(opt,
									{
										waitingMessage: "<br />Saving...<br /><br />",
										successMessage: "The information was successfully saved.",
										error500Message: "The server was unable to get the requested information.",
										method: "post"
									}
								);
                                break;
                        case "delete":
								Object.extend(opt,
									{
										waitingMessage: "<br />Deleting...<br /><br />",
										error500Message: "The server was unable to perform the requested delete.",
										confirmMessageText: "Are you sure you want to delete this?<br /><br />",
										confirmMessageWidth: 250,
										confirmMessageHeight: 96,
										successMessageWidth: 250,
										successMessageHeight: 70
									}
								);
                                break;
                        case "confirm":
								Object.extend(opt,
									{
										waitingMessage: "<br />Please wait...<br /><br />",
										error500Message: "The server was unable to perform the requested action.",
										confirmMessageWidth: 250,
										confirmMessageHeight: 88,
										successMessageWidth: 250,
										successMessageHeight: 70
									}
								);
                                break;
                        case "generic":
								Object.extend(opt,
									{
										waitingMessage: "<br />Please wait...<br /><br />",
										error500Message: "The server was unable to perform the requested action."
									}
								);
                                break;
                    }
                    Object.extend(opt, options);
					
					this.commandQueue = opt.commandQueue;
                    this.method = opt.method;
                    this.waitingMessage = opt.waitingMessage;
                    this.waitingMessageWidth = opt.waitingMessageWidth;
                    this.waitingMessageHeight = opt.waitingMessageHeight;
                    this.successMessage = opt.successMessage;
                    this.successMessageWidth = opt.successMessageWidth;
                    this.successMessageHeight = opt.successMessageHeight;
                    this.error500Message = opt.error500Message;
                    this.errorMessageWidth = opt.errorMessageWidth;
                    this.errorMessageHeight = opt.errorMessageHeight;
					this.confirmMessageText = opt.confirmMessageText;
					this.confirmMessageWidth = opt.confirmMessageWidth;
					this.confirmMessageHeight = opt.confirmMessageHeight;
					this.jsScriptsToEval = opt.jsScriptsToEval;
                    this.pars = $H();
                    this.paramFields = $H();
                    this.inUse = false;
                    this.resultsDiv = null;
                    this.resultsField = null;
                },
                
        type:   "AjaxHub",
                
        isCurrentProcessFinished:
                function()
                {
                    return !this.inUse;
                },

        clearParameters:
                function()
                {
                    this.pars = $H();
                    this.paramFields = $H();
                },
                
        addParameter:
                function(key, value)
                {
                    this.pars.set(key, value);
                },
                
        attachParameter:
                function(key, id)
                {
                    this.paramFields.set(key, id);
                },
                
        load:
                function(resultsDiv, onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.resultsDiv = resultsDiv;
                    this.resultsField = null;
                    this.onComplete = onComplete;

					if (this.messager)
					{
	                    this.messager.showWaiting(this.waitingMessage);
    	                this.messager.resize(this.waitingMessageWidth, this.waitingMessageHeight);
					}
					
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._loadTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._loadTask();
                    }
                },
                
        loadForValue:
                function(onComplete)
                {
                    this.load(null, onComplete);
                },
                
        loadFor:
                function(pars, resultsDiv, onComplete)
                {
                    this.pars = $H(pars.toQueryParams());
                    this.load(resultsDiv, onComplete);
                },
                
        loadIntoField:
                function(resultsField, onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.resultsField = resultsField;
                    this.resultsDiv = null;
                    this.onComplete = onComplete;

					if (this.messager)
					{
	                    this.messager.showWaiting(this.waitingMessage);
    	                this.messager.resize(this.waitingMessageWidth, this.waitingMessageHeight);
					}
					
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._loadTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._loadTask();
                    }
                },
                
        _loadTask:
                function()
                {
                    this._evalParamFields();
                    var params = this.pars.toQueryString();

                    currentAjaxRequest = new Ajax.Request(
                        this.url,
                        {
                            method: this.method,
                            parameters: params,
                            onComplete: this._onLoadComplete.bind(this)
                        });
                },
                
        _onLoadComplete:
                function(results)
                {
                    var success = false;
                    
                    if (results.status == 200)
                    {
                        success = true;
						if (this.messager)
						{
	                        this.messager.hide();
	                    }
                        if (this.resultsDiv != null)
                        {
                            $(this.resultsDiv).innerHTML = results.responseText;
                        }
                        else if (this.resultsField != null)
                        {
                            $(this.resultsField).value = results.responseText;
                        }
						if (this.jsScriptsToEval != null)
						{
							this._evalJS(results.responseText);
						}
                    }
                    else if (results.status == 500)
                    {
						if (this.messager)
						{
	                        this.messager.resize(this.errorMessageWidth, this.errorMessageHeight);
    	                    this.messager.showError(this.error500Message, results.responseText);
						}
                        results.responseText = null;
                    }
                    else
                    {
						if (this.messager)
						{
	                        this.messager.resize(this.errorMessageWidth, this.errorMessageHeight);
    	                    this.messager.showError("Error Status: " + results.status, "<br />" + results.statusText + "<br /><br />");
						}
                        results.responseText = null;
                    }
                    
                    if ( this.onComplete != undefined && this.onComplete != null )
                    {
                        if (this.resultsDiv != null || this.resultsField != null)
                        {
                            this.commandQueue.enqueue( this.onComplete(success) );
                        }
                        else
                        {
                            this.commandQueue.enqueue( this.onComplete(results.responseText) );
                        }
                    }
                    
                    this.inUse = false;
                },
                
        del:
                function(onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.deleteDetails = null;
                    this.onComplete = onComplete;

                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._delTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._delTask();
                    }
                },
                
        deleteWithDetails:
                function(details, onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.deleteDetails = details;
                    this.onComplete = onComplete;

                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._delTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._delTask();
                    }
                },
                
        deleteWithDetailsLoader:
                function(loader, onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.deleteDetails = null;
                    this.onComplete = onComplete;

                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( loader.loadForValue(this._delOnLoaderComplete.bind(this)) );
                    }
                    else
                    {
                        loader.loadForValue(this._delOnLoaderComplete.bind(this));
                    }
                },
                
        deleteFor:
                function(pars, onComplete)
                {
                    this.pars = $H(pars.toQueryParams());
                    this.del(onComplete);
                },
                
        _delOnLoaderComplete:
                function(results)
                {
                    this.deleteDetails = results;
                    
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._delTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._delTask();
                    }
                },
                
        _delTask:
                function()
                {
                    if (this.deleteDetails == null)
                    {
                        this.messager.showConfirmation(this.confirmMessageText, this._delConfirmResponse.bind(this));
                    }
                    else
                    {
                        this.messager.showConfirmationWithDetails(this.confirmMessageText, this.deleteDetails, this._delConfirmResponse.bind(this));
                    }
                    this.messager.resize(this.confirmMessageWidth, this.confirmMessageHeight);

                },

        _delConfirmResponse:
                function(isConfirmed)
                {
                    if (!isConfirmed)
                    {
                        if ( this.onComplete != undefined && this.onComplete != null )
                        {
                            this.commandQueue.enqueue( this.onComplete(false) );
                        }
                        this.inUse = false;
                        return;
                    }
                    
                    this._evalParamFields();

                    this.messager.showWaiting(this.waitingMessage);
                    this.messager.resize(this.waitingMessageWidth, this.waitingMessageHeight);

                    currentAjaxRequest = new Ajax.Request(
                        this.url,
                        {
                            method: this.method,
                            parameters: this.pars.toQueryString(),
                            onComplete: this._onDelComplete.bind(this)
                        });
                },
                                
        _onDelComplete:
                function(results)
                {
                    var success = false;

                    if (results.status == 200)
                    {
                        success = true;
                        this.messager.resize(this.successMessageWidth, this.successMessageHeight);
                        this.messager.showComment(results.responseText, { duration: 2});
                    }
                    else if (results.status == 500)
                    {
                        this.messager.resize(this.errorMessageWidth, this.errorMessageHeight);
                        this.messager.showError(this.error500Message, results.responseText);
                    }
                    else
                    {
                        this.messager.resize(this.errorMessageWidth, this.errorMessageHeight);
                        this.messager.showError("Error Status: " + results.status, "<br />" + results.statusText + "<br /><br />");
                    }
                    
                    if ( this.onComplete != undefined && this.onComplete != null )
                    {
                        this.commandQueue.enqueue( this.onComplete(success) );
                    }
                    
                    this.inUse = false;
                },
                
        call:
                function(onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.onComplete = onComplete;
                    
					if (this.messager)
					{
	                    this.messager.showWaiting(this.waitingMessage);
    	                this.messager.resize(this.waitingMessageWidth, this.waitingMessageHeight);
					}
                    
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._callTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._callTask();
                    }
                },
                
        confirmThenCall:
                function(message, details, onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.confirmMessageText = message;
                    this.callDetails = details;
                    this.onComplete = onComplete;
                    
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._callConfirmTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._callConfirmTask();
                    }
                },
                
        loadConfirmThenCall:
                function(message, loader, onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.confirmMessageText = message;
                    this.callDetails = null;
                    this.onComplete = onComplete;
                    
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( loader.loadForValue(this._callOnLoaderComplete.bind(this)) );
                    }
                    else
                    {
                        loader.loadForValue(this._callOnLoaderComplete.bind(this));
                    }
                },
                
        _callOnLoaderComplete:
                function(results)
                {
                    this.callDetails = results;
                    
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._callConfirmTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._callConfirmTask();
                    }
                },
                
        _callConfirmTask:
                function()
                {
                    if (this.callDetails == null)
                    {
                        this.messager.showConfirmation(this.confirmMessageText, this._callConfirmResponse.bind(this));
                    }
                    else
                    {
                        this.messager.showConfirmationWithDetails(this.confirmMessageText, this.callDetails, this._callConfirmResponse.bind(this));
                    }
                },
                
        _callConfirmResponse:
                function(isConfirmed)
                {
                    if (!isConfirmed)
                    {
                        if ( this.onComplete != undefined && this.onComplete != null )
                        {
                            this.commandQueue.enqueue( this.onComplete(null) );
                        }
                        this.inUse = false;
                        return;
                    }
                    
                    this.messager.showWaiting(this.waitingMessage);
                    this.messager.resize(this.waitingMessageWidth, this.waitingMessageHeight);
                    
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._callTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._callTask();
                    }
                },
                
        _callTask:
                function()
                {
                    this._evalParamFields();
                    var params = this.pars.toQueryString();

                    currentAjaxRequest = new Ajax.Request(
                        this.url,
                        {
                            method: this.method,
                            parameters: params,
                            onComplete: this._onCallComplete.bind(this)
                        });
                },
                
        _onCallComplete:
                function(results)
                {
                    if (results.status == 200)
                    {
                        if (this.successMessage == null)
                        {
							if (this.messager)
							{
	                            this.messager.hide();
							}
                        }
                        else if (this.messager)
                        {
                            this.messager.resize(this.successMessageWidth, this.successMessageHeight);
                            this.messager.showComment(this.successMessage, { duration: 2});
                        }
                    }
                    else if (results.status == 500)
                    {
						if (this.messager)
						{
	                        this.messager.resize(this.errorMessageWidth, this.errorMessageHeight);
	                        this.messager.showError(this.error500Message, results.responseText);
						}
                        results.responseText = null;
                    }
                    else
                    {
						if (this.messager)
						{
	                        this.messager.resize(this.errorMessageWidth, this.errorMessageHeight);
	                        this.messager.showError("Error Status: " + results.status, "<br />" + results.statusText + "<br /><br />");
						}
                        results.responseText = null;
                    }
                    
                    if ( this.onComplete != undefined && this.onComplete != null )
                    {
                        this.commandQueue.enqueue( this.onComplete(results.responseText) );
                    }
                    
                    this.inUse = false;
                },
                
        save:
                function(onComplete)
                {
                    if (this.inUse)
                    {
                        return;
                    }
                    
                    this.inUse = true;
                    this.onComplete = onComplete;
                    
					if (this.messager)
					{
	                    this.messager.showWaiting(this.waitingMessage);
	                    this.messager.resize(this.waitingMessageWidth, this.waitingMessageHeight);
					}
                    
                    if (this.commandQueue != null)
                    {
                        this.commandQueue.enqueue( this._saveTask.bind(this), this.isCurrentProcessFinished.bind(this) );
                    }
                    else
                    {
                        this._saveTask();
                    }
                },
                
        _saveTask:
                function()
                {
                    this._evalParamFields();
                    var params = this.pars.toQueryString();
                    
                    currentAjaxRequest = new Ajax.Request(
                        this.url,
                        {
                            method: this.method,
                            parameters: params,
                            onComplete: this._onSaveComplete.bind(this)
                        });
                },
                
        _onSaveComplete:
                function(results)
                {
                    var success = false;
                    
                    if (results.status == 200)
                    {
                        success = true;
                        if (this.successMessage == null)
                        {
							if (this.messager)
							{
	                            this.messager.hide();
							}
                        }
                        else if (this.messager)
                        {
                            this.messager.resize(this.successMessageWidth, this.successMessageHeight);
                            this.messager.showComment(this.successMessage, { duration: 2 });
                        }
                    }
                    else if (results.status == 500)
                    {
						if (this.messager)
						{
	                        this.messager.resize(this.errorMessageWidth, this.errorMessageHeight);
	                        this.messager.showError(this.error500Message, results.responseText);
						}
                    }
                    else if (this.messager)
                    {
                        this.messager.resize(this.errorMessageWidth, this.errorMessageHeight);
                        this.messager.showError("Error Status: " + results.status, "<br />" + results.statusText + "<br /><br />");
                    }
                    
                    if ( this.onComplete != undefined && this.onComplete != null )
                    {
                        this.commandQueue.enqueue( this.onComplete(success) );
                    }
                    
                    this.inUse = false;
                },
                
        _evalParamFields:
                function()
                {
                    this.paramFields.each(  function(pair) { this.addParameter(pair.key, $F(pair.value)); } );
                },
				
		_evalJS:
				function(results)
				{
					results.scan(/<script[^>]*id="([^"]*)"[^>]*>(([^<]+(<[^\/])?)+)<\/script>/, this._evalJSProspect.bind(this));
				},
				
		_evalJSProspect:
				function(match)
				{
					var scripts;
					if (Object.isString(this.jsScriptsToEval))
					{
						scripts = $A([ this.jsScriptsToEval ]);
					}
					else
					{
						scripts = $A(this.jsScriptsToEval);
					}

					// match[0] - the full match string
					// match[1] - the script id
					// match[2] - the script innerHTML
					for (var i = 0; i < scripts.length; i++)
					{
						if (match[1] == scripts[i])
						{
					        eval(match[2]);
						}
					}
				}
    }
),

// ********************************************************************************************************************
// Layout Div - makes the process of handling absolutely positioned div's much more manageable.
//
// constructor parameters:  - divID (required) - the ID of the div element that should be made into a Positioned Div
//                          - maxDimensions (optional) - if specified, this sets the maximum width and/or height that
//                              the div can grow to if the contents of the div are too much for the current dimensions
//
// public functions:        - show() - make sure that the div is visible, redraw the div, and make sure that the
//                              relevant browser events are being observed
//                          - hide() - make the div invisible and stop observing browser events
//                          - resize(dimensions, maxDimensions) - set a new width and/or height for the div; if 
//                              maxDimensions is specified, resets the maximum width and/or height that the div can
//                              grow to if the contents of the div are too much for the specified dimensions
//                          - reposition(coordinates) - set a new x and/or y position for the div
//                          - freeze() - stop redrawing the div in response to observed browser events
//                          - getContents() - returns the inner HTML contents of the div
//                          - setContents(val) - set the inner HTML contents of the div to the specified value
//                          - setVerticalAlignment(val) - determines whether the position of the div is relative to the
//                              top, bottom, or middle, or offset from both the top and bottom of the browser's view
//                          - setHorizontalAlignment(val) - determines whether the position of the div is relative to 
//                              the left, right, or center, or offset from both the left and right of the browser's view
//                          - center() - sets the div's position horizontally and vertically to the center of the
//                              browser's view
//                          - getBottomMostPosition() - gets the highest numeric value of the top coordinate for the 
//                              current div at the current size for the current browser's view
//                          - getRightMostPosition() - gets the highest numeric value of the left coordinate for the
//                              current div at the current size for the current browser's view
//                          - getMiddlePosition() - gets the numeric value of the top coordinate for the current div at
//                              the current size that would position it vertically in the middle of the browser's view
//                          - getCenterPosition() - gets the numeric value of the left coordinate for the current div
//                              at the current size that would position it horizontally in the center of the browser's
//                              view
// ********************************************************************************************************************

LayoutDiv: Class.create(
    {
        initialize:
                function(divID, options)
                {
                    this.div = $(divID);
                    this.div.style.margin = "0px";
                    this.div.absolutize();

                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
                                        maxDimensions: { }, 
                                        commandQueue: null, 
                                        onOutOfRange: null, 
                                        overflow: "scroll",
										overflowDivs: null,
										sourceDiv: null,
                                        onOverflow: null,
                                        iframeID: null,
										overshadow: false
                                    }
                                );
                    Object.extend(opt, options);
                    this.maxDimensions = { width: null, height: null };
                    Object.extend( this.maxDimensions, opt.maxDimensions );
                    this.commandQueue = opt.commandQueue || (new Thirteen.CommandQueue());
                    this.onOutOfRange = opt.onOutOfRange;
                    this.overflowType = opt.overflow;
					this.overflowDivs = opt.overflowDivs;
					this.sourceDiv = opt.sourceDiv;
                    this.onOverflow = opt.onOverflow;
                    this.iframeID = opt.iframeID;
                    this.iframe = this.iframeID != null ? $(this.iframeID) : null;
					this.overshadow = opt.overshadow;
					this.effect = "none";
					this.effectApplied = true;
					this.overshadowHold = $H();
                    this.inUse = false;
					this.timerID = null;
					this.isVisible = false;
					this.overflowSettingUp = false;
                    this.overflowInProgress = false;
					this.settingContents = false;
                    
                    this.dimensions = this.div.getDimensions();
                    var offsets = this.div.cumulativeOffset();
                    this.coordinates = { x: offsets.left + "px", y: offsets.top + "px", horizontalPosition: "left", verticalPosition: "top" };

                    this.wordLimitIndex = null;
                    if (this.overflowType == "reservoir")
                    {
                        this._wordParse( this.div.innerHTML );
                    }
                    this._calcSizeDiscrepancy();
                    this._showTaskBinding = this._showTaskHandler.bind(this);
                    
					if (this.overflowDivs != null)
					{
						this.commandQueue.queueJump( this._setupOverflow.bind(this, opt), this._overflowSetupIsFinished.bind(this), this.show.bind(this) );
					}
					else
					{
                    	this.show();
					}
                },
        
        type:   "LayoutDiv",
        
        isCurrentProcessFinished:
                function()
                {
                    return !this.inUse;
                },

        show:
                function(options)
                {
                    this.inUse = true;
                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
                                        effect: "none" 
                                    }
                                );
                    Object.extend(opt, options);
					this.effect = opt.effect;
					this.effectApplied = false;

                    Event.observe(window, "scroll", this._showTaskBinding);
                    Event.observe(window, "resize", this._showTaskBinding);
					Event.observe(document, "Thirteen:layoutChange", this._showTaskBinding);
                    
					if (this.overshadow)
					{
						this._overshadowOn();
					}
                    
                    this._showTask();
                },
        
        hide:
                function(options)
                {
                    this.inUse = true;
                    options = options || { };
                    var opt = { };
                    Object.extend(opt, 
                                    { 
                                        effect: "none" 
                                    }
                                );
                    Object.extend(opt, options);
					this.effect = opt.effect;
					this.effectApplied = false;

                    Event.stopObserving(window, "scroll", this._showTaskBinding);
                    Event.stopObserving(window, "resize", this._showTaskBinding);
					Event.stopObserving(document, "Thirteen:layoutChange", this._showTaskBinding);
                    
					if (this.overshadow)
					{
						this._overshadowOff();
					}

                    this._hideTask();
                    this.inUse = false;
                },
        
        resize:
                function(dimensions, maxDimensions)
                {
                    this.inUse = true;
                    Object.extend(this.dimensions, dimensions || { });
                    Object.extend(this.maxDimensions, maxDimensions || { });
                    Object.extend(this.maxDimensions, this.dimensions);

					if (this.div.style.display != "none")
					{
	                    this._adjustToFit(this.dimensions, this.maxDimensions);
					}
                    this.inUse = false;
                },
        
		getDimensions:
				function()
				{
					return this.dimensions;
				},
        
        reposition:
                function(coordinates)
                {
                    this.inUse = true;
                    Object.extend(this.coordinates, coordinates || { });

                    if (Object.isString(this.coordinates.x) == false || this.coordinates.x.indexOf("px") == -1)
                    {
                        this.coordinates.x = this.coordinates.x + "px";
                    }
                    if (Object.isString(this.coordinates.y) == false || this.coordinates.y.indexOf("px") == -1)
                    {
                        this.coordinates.y = this.coordinates.y + "px";
                    }

                    this._showTask();
                },
                
        freeze:
                function()
                {
                    this.coordinates.verticalPosition = "frozen";
                    this.coordinates.horizontalPosition = "frozen";
                    
                    Event.stopObserving(window, "scroll", this._showTaskBinding);
                    Event.stopObserving(window, "resize", this._showTaskBinding);
					Event.stopObserving(document, "Thirteen:layoutChange", this._showTaskBinding);
                },
                
        getContents:
                function()
                {
                    return this.div.innerHTML;
                },
        
        setContents:
                function(val)
                {
                    this._setContentsTask(val);
                },
        
        setVerticalAlignment:
                function(val)
                {
                    switch (val)
                    {
                        case "top":
                            Object.extend(this.coordinates, { y: "0px", topOffset: "", bottomOffset: "", verticalPosition: "top" });
                            break;
                        case "middle":
                            Object.extend(this.coordinates, { y: "", topOffset: "", bottomOffset: "", verticalPosition: "middle" });
                            break;
                        case "bottom":
                            Object.extend(this.coordinates, { y: "0px", topOffset: "", bottomOffset: "", verticalPosition: "bottom" });
                            break;
                        case "offset":
                            Object.extend(this.coordinates, { y: "", topOffset: "0px", bottomOffset: "0px", verticalPosition: "offset" });
                            break;
                        default:
                            this.coordinates.verticalPosition = "top";
                            break;
                    }
                    this.show();
                },
                
        setHorizontalAlignment:
                function(val)
                {
                    switch (val)
                    {
                        case "left":
                            Object.extend(this.coordinates, { x: "0px", leftOffset: "", rightOffset: "", horizontalPosition: "left" });
                            break;
                        case "center":
                            Object.extend(this.coordinates, { x: "", leftOffset: "", rightOffset: "", horizontalPosition: "center" });
                            break;
                        case "right":
                            Object.extend(this.coordinates, { x: "0px", leftOffset: "", rightOffset: "", horizontalPosition: "right" });
                            break;
                        case "offset":
                            Object.extend(this.coordinates, { x: "", leftOffset: "0px", rightOffset: "0px", horizontalPosition: "offset" });
                            break;
                        default:
                            this.coordinates.horizontalPosition = "left";
                            break;
                    }
                    this.show();
                },
                
        center:
                function()
                {
                    this.setVerticalAlignment("middle");
                    this.setHorizontalAlignment("center");
                },
                
        setOverflowType:
                function(val)
                {
                    this.overflowType = val;
                    if (this.overflowType == "reservoir")
                    {
                        this.wordLimitIndex = null;
                        this._wordParse( this.div.innerHTML );
                    }
                },
                
        getBottomMostPosition:
                function(dim)
                {
                    var currentDim = dim || this.div.getDimensions();
                    var dvBottomVal = (this.viewOffset == undefined || this.viewSize == undefined) ? 0 : (this.viewOffset.top + this.viewSize.height - currentDim.height);
                    
                    if (Prototype.Browser.Opera)
                    {
                        dvBottomVal = self.innerHeight  - currentDim.height;
                    }
                    if (Prototype.Browser.Safari || Prototype.Browser.Konqueror || Prototype.Browser.MacIE)
                    {
                        var vd = document.documentElement.getDimensions();
                        if (vd.height > this.viewSize.height || vd.width > this.viewSize.width)
                        {
                        	dvBottomVal = document.documentElement.clientHeight  - currentDim.height;
						}
                    }
                    
                    return dvBottomVal;
                },
        
        getRightMostPosition:
                function(dim)
                {
                    if (this.viewOffset == undefined || this.viewSize == undefined)
                    {
                        return 0;
                    }
                    var currentDim = dim || this.div.getDimensions();
                    var dvRightVal = this.viewOffset.left + this.viewSize.width - currentDim.width;

                    if (Prototype.Browser.Gecko)
                    {
                        var vd = document.documentElement.getDimensions();
                        if (vd.height > this.viewSize.height || vd.width > this.viewSize.width)
                        {
                            dvRightVal -= self.innerWidth - document.documentElement.clientWidth;   // scrollbar correction
                        }
                    }
                    if (Prototype.Browser.Opera)
                    {
                        dvRightVal -= self.innerWidth - document.documentElement.clientWidth;   // scrollbar correction
                    }
                    if (Prototype.Browser.Safari || Prototype.Browser.Konqueror || Prototype.Browser.MacIE)
                    {
                        var vd = document.documentElement.getDimensions();
                        if (vd.height > this.viewSize.height || vd.width > this.viewSize.width)
                        {
                        	dvRightVal = document.documentElement.clientWidth - currentDim.width;   // scrollbar correction
						}
                    }

                    return dvRightVal;
                },
                
        getMiddlePosition:
                function(dim)
                {
                    var currentDim = dim || this.div.getDimensions();
                    return (this.viewOffset == undefined || this.viewSize == undefined) ? 0 : (this.viewOffset.top + ((this.viewSize.height - currentDim.height) / 2));
                },
        
        getCenterPosition:
                function(dim)
                {
                    var currentDim = dim || this.div.getDimensions();
                    return (this.viewOffset == undefined || this.viewSize == undefined) ? 0 : (this.viewOffset.left + ((this.viewSize.width - currentDim.width) / 2));
                },
                
		_showTaskHandler:
				function(evt)
				{
					if (evt.eventName == "Thirteen:layoutChange" && this.effect != "none")
					{
						this._applyEffectTimer();
					}
					else if (this.commandQueue && this.overflowType != "reservoir")
					{
						this.commandQueue.enqueue(this._showTask.bind(this), this.isCurrentProcessFinished.bind(this));
					}
					else
					{
						this._showTask();
					}
				},
				
		_applyEffectTimer:
				function()
				{
                    this.timerID = setInterval(this._afterEffectFinished.bind(this), 1500);
					
				},
				
		_afterEffectFinished:
				function()
				{
                    if (this.timerID != null)
                    {
                        clearInterval(this.timerID);
                        this.timerID = null;
                    }
					
					this.commandQueue.enqueue(this._showTask.bind(this), this.isCurrentProcessFinished.bind(this));
				},
				
        _showTask:
                function()
                {
                    this.inUse = true;
					var holdOverflow = this.div.style.overflow;
					var setIframe = false;
					this.isVisible = true;
					if (!this.effectApplied)
					{
						switch (this.effect)
						{
							case "none": this.div.style.display = "block";
										break;
							case "grow": Effect.Grow(this.div);
										break;
							case "blind": Effect.BlindDown(this.div);
										break;
							case "slide": Effect.SlideDown(this.div);
										break;
							default: this.div.style.display = "block";
										break;
						}
						this.effectApplied = true;
						setIframe = true;
						$(document).fire("Thirteen:layoutChange");
					}
                    this.div.style.overflow = "hidden";
                    this.viewSize = document.viewport.getDimensions();
                    this.viewOffset = document.viewport.getScrollOffsets();
                    
                    this._adjustToFit(this.dimensions);
					
                    switch (this.coordinates.verticalPosition)
                    {
                        case "top":
                            this.div.style.top = (this.viewOffset.top + this._yCoordinateValue()) + "px";
                            break;
                        case "middle":
                            this.div.style.top = this.getMiddlePosition() + "px";
                            break;
                        case "bottom":
                            this.div.style.top = (this.getBottomMostPosition() - this._yCoordinateValue()) + "px";
                            break;
                        case "offset":
                            this.div.style.top = (this.viewOffset.top + this._offsetCoordinateValue("top")) + "px";
                            this.resize( { height: (this.getBottomMostPosition() + this.dimensions.height - this._offsetCoordinateValue("bottom") - this._offsetCoordinateValue("top")) } );
                            break;
                    }
                    switch (this.coordinates.horizontalPosition)
                    {
                        case "left":
                            this.div.style.left = (this.viewOffset.left + this._xCoordinateValue()) + "px";
                            break;
                        case "center":
                            this.div.style.left = this.getCenterPosition() + "px";
                            break;
                        case "right":
                            this.div.style.left = (this.getRightMostPosition() - this._xCoordinateValue()) + "px";
                            break;
                        case "offset":
                            this.div.style.left = (this.viewOffset.left + this._offsetCoordinateValue("left")) + "px";
                            this.resize( { width: (this.getRightMostPosition() + this.dimensions.width - this._offsetCoordinateValue("right") - this._offsetCoordinateValue("left")) } );
                            break;
                    }
                    if (Prototype.Browser.IE && this.iframe != null)
                    {
						if (setIframe)
						{
	                        this.iframe.style.display = "block";
						}
                        this.iframe.style.left = this.div.style.left;
                        this.iframe.style.top = this.div.style.top;
                        this.iframe.style.border = "1px solid white";
                    }
                    
                    if (this.overflowType != "reservoir" && holdOverflow != undefined)
                    {
						this.div.style.overflow = holdOverflow;
					}
                    
					this.div.fire("Thirteen:LayoutDivShown");
                    this.inUse = false;
                },
        
        _hideTask:
                function()
                {
					this.isVisible = false;
					if (!this.effectApplied)
					{
						switch (this.effect)
						{
							case "none": this.div.style.display = "none";
										break;
							case "shrink": Effect.Shrink(this.div);
										break;
							case "switch": Effect.SwitchOff(this.div);
										break;
							case "squish": Effect.Squish(this.div);
										break;
							case "blind": Effect.BlindUp(this.div);
										break;
							case "slide": Effect.SlideUp(this.div);
										break;
							default: this.div.style.display = "none";
										break;
						}
						this.effectApplied = true;
					}
                    if (Prototype.Browser.IE && this.iframe != null)
                    {
                        this.iframe.style.display = "none";
                    }
                },

		_overshadowOn:
				function()
				{
					this._overshadowUp(this.div, 0.3);
				},
				
		_overshadowOff:
				function()
				{
					this._overshadowUp(this.div, 1);
				},
				
		_overshadowUp:
				function(obj, opacityVal)
				{
					if (obj.tagName == "BODY")
					{
						return;
					}

					if (obj.setOpacity && obj.identify() != this.div.identify())
					{
						//obj.setOpacity(opacityVal);
	
						var objs = obj.siblings().findAll(function(item) { return (["DIV", "TABLE", "SPAN", "FORM"].indexOf(item.tagName) != -1); });
						for (var i = 0; i < objs.length; i++)
						{
							if (objs[i].style.display != "none")
							{
								this._overshadowDown(objs[i], opacityVal);
							}
						}
					}
					
					this._overshadowUp($(obj.parentNode), opacityVal);
				},
				
		_overshadowDown:
				function(obj, opacityVal)
				{
					if (obj.setOpacity)
					{
						obj.setOpacity(opacityVal);
					}
					
					var objs = obj.childElements().findAll(function(item) { return (["DIV", "TABLE", "SPAN", "FORM"].indexOf(item.tagName) != -1); });
					for (var i = 0; i < objs.length; i++)
					{
						this._overshadowDown(objs[i], opacityVal);
					}
				},
				
		_setupOverflow:
				function(options)
				{
					this.overflowSettingUp = true;
					var restDivs = $A(this.overflowDivs).clone();
					var firstDiv = restDivs.shift();
					if (restDivs.length == 0)
					{
						restDivs = null;
					}
					if (firstDiv.type != "LayoutDiv")
					{
						this.instantiating = false;
						this.commandQueue.queueJump( 
							this._instantiateOverflowTask.bind(this, options, firstDiv, restDivs), 
							this._instantiatingIsFinished.bind(this),
							this._returnFromInstantiating.bind(this) );
					}
					else
					{
						firstDiv.commandQueue = this.commandQueue;
						this.overflowSettingUp = false;
					}
				},
				
		_overflowSetupIsFinished:
				function()
				{
					return !this.overflowSettingUp;
				},
				
		_instantiateOverflowTask:
				function(options, firstDiv, restDivs)
				{
					this.instantiating = true;
					options.overflowDivs = restDivs;
					options.commandQueue = this.commandQueue;
					options.sourceDiv = this;
					this.instantiatedDiv = new Thirteen.LayoutDiv($(firstDiv).id, options);
					this.instantiating = false;
				},
				
		_instantiatingIsFinished:
				function()
				{
					return !this.instantiating;
				},

		_returnFromInstantiating:
				function()
				{
					this.overflowDivs = [ this.instantiatedDiv ].concat( this.instantiatedDiv.overflowDivs );
					this.overflowSettingUp = false;
				},

        _setContentsTask:
                function(val)
                {
                    this.div.innerHTML = val;
                    if (this.overflowType == "reservoir")
                    {
						this.wordLimitIndex = null;
                        this._wordParse( this.div.innerHTML );
                    }
					this.show();
                },
        
        _setSize:
                function(dimensions)
                {
                    if (dimensions.height < 0 || dimensions.width < 0)
                    {
                        this.hide();
                        Object.extend(this.coordinates, { x: 0, y: 0 });
                        Object.extend(this.dimensions, { width: 100, height: 100, widthDiscrepancy: 0, heightDiscrepancy: 0 });
                        if (this.onOutOfRange != null)
                        {
                            this.onOutOfRange(this);
                        }
                        this.inUse = false;
                        return;
                    }
                    
                    Object.extend(this.dimensions, dimensions);

                    this.div.style.width = (this.dimensions.width - (this.dimensions.widthDiscrepancy || 0) <= 0) ? "0px" : parseInt(this.dimensions.width - (this.dimensions.widthDiscrepancy || 0)) + "px";
                    this.div.style.height = (this.dimensions.height - (this.dimensions.heightDiscrepancy || 0) <= 0) ? "0px" : parseInt(this.dimensions.height - (this.dimensions.heightDiscrepancy || 0)) + "px";
                    
                    if (Prototype.Browser.IE && this.iframe != null)
                    {
                        this.iframe.style.width = (this.div.getWidth() + 1) + "px";
                        this.iframe.style.height = (this.div.getHeight() + 1) + "px";
                        this.iframe.style.border = "1px solid white";
                    }
                },
        
        _calcSizeDiscrepancy:
                function()
                {
                    if (this.dimensions.width > 0)
                    {
                        this.div.style.width = this.dimensions.width + "px";
                        this.dimensions.widthDiscrepancy = this.div.getWidth() - this.dimensions.width;
                        this.div.style.width = (this.dimensions.width - this.dimensions.widthDiscrepancy <= 0) ? "0px" : (this.dimensions.width - this.dimensions.widthDiscrepancy) + "px";
                    }
                    if (this.dimensions.height > 0)
                    {
                        this.div.style.height = this.dimensions.height + "px";
                        this.dimensions.heightDiscrepancy = this.div.getHeight() - this.dimensions.height;
                        this.div.style.height = (this.dimensions.height - this.dimensions.heightDiscrepancy <= 0) ? "0px" : (this.dimensions.height - this.dimensions.heightDiscrepancy) + "px";
                    }
                    
                    if (Prototype.Browser.IE && this.iframe != null)
                    {
                        this.iframe.style.width = (this.div.getWidth() + 1) + "px";
                        this.iframe.style.height = (this.div.getHeight() + 1) + "px";
                        this.iframe.style.border = "1px solid white";
                    }
                    
                },
                
        _checkBoundaries:
                function(innerDimensions, outerDimensions)
                {
                    var resized = false;
                    if (outerDimensions.width < innerDimensions.width)
                    {
                        innerDimensions.width = outerDimensions.width;
                        resized = true;
                    }
                    if (outerDimensions.height < innerDimensions.height)
                    {
                        innerDimensions.height = outerDimensions.height;
                        resized = true;
                    }
                    
                    return resized;
                },
        
        _checkClipping:
                function(maxDimensions)
                {
                    if (this._xCoordinateValue() > this.getRightMostPosition(maxDimensions))
                    {
                        maxDimensions.width -= this._xCoordinateValue() - this.getRightMostPosition(maxDimensions);
                    }
                    if (this._yCoordinateValue() > this.getBottomMostPosition(maxDimensions))
                    {
                        maxDimensions.height -= this._yCoordinateValue() - this.getBottomMostPosition(maxDimensions);
                    }
                    return maxDimensions;
                },
                
        _applyOverflow:
                function(maxDimensions)
                {
                    this.overflowInProgress = true;
                    switch (this.overflowType)
                    {
                        case "scroll":
                            this.div.style.overflow = "auto";
                            break;
                        case "hide":
                            this.div.style.overflow = "hidden";
                            break;
                        case "reservoir":
                            var divHeight = this.div.getHeight();
                            if (this.wordLimitIndex == null)
                            {
                                this.wordLimitIndex = this.divWords.length;
                                var splitterIndex = Math.floor(this.wordLimitIndex / 2);
                                var highestFitter = 0;
                                var lowestMisser = this.divWords.length;
                                while (splitterIndex > 0)
                                {
                                    var testContents = this.divWords.slice(0, this.wordLimitIndex).join(" ");
                                    this.div.innerHTML = testContents;

                                    if (this.div.scrollHeight > divHeight)
                                    {
                                        lowestMisser = this.wordLimitIndex < lowestMisser ? this.wordLimitIndex : lowestMisser;
                                        this.wordLimitIndex -= splitterIndex;
                                    }
                                    else
                                    {
                                        highestFitter = this.wordLimitIndex > highestFitter ? this.wordLimitIndex : highestFitter;
                                        this.wordLimitIndex += splitterIndex;
                                    }
                                    splitterIndex = Math.floor(splitterIndex / 2);
                                    if (splitterIndex == 0)
                                    {
                                        this.wordLimitIndex = lowestMisser;
                                        testContents = this.divWords.slice(0, this.wordLimitIndex).join(" ");
                                        this.div.innerHTML = testContents;
                                    }
                                }
                            }
                            while (this.div.scrollHeight > divHeight)
                            {
                                var testContents = this.divWords.slice(0, --this.wordLimitIndex).join(" ");
                                this.div.innerHTML = testContents;
                            }
							if (this.overflowDivs != null && this.divWords.length > 0)
							{
								var overflow = this.divWords.splice(this.wordLimitIndex, this.divWords.length - this.wordLimitIndex).join(" ");
								this.overflowDivs[0].setContents(overflow);
							}
							else if (this.onOverflow != null)
							{
								this.onOverflow(overflow);
							}
							
                            break;
                    }
                    this.overflowInProgress = false;
                },
                
        _isOverflowFinished:
                function()
                {
                    return !this.overflowInProgress;
                },
                
        _wordParse:
                function(contents)
                {
                    var searcher = new RegExp("([^<>\\s]+|(<[^>]+>))", "g");
                    this.divWords =  $A(contents.match(searcher));
                },
                
        _adjustToFit:
                function(targetDimensions, maxDimensions)
                {
                    if (Object.isUndefined(maxDimensions))
                    {
                        maxDimensions = { width: this.maxDimensions.width || this.viewSize.width, height: this.maxDimensions.height || this.viewSize.height };
                    }
                    maxDimensions = this._checkClipping(maxDimensions);
                    if (targetDimensions.width > maxDimensions.width)
                    {
                        targetDimensions.width = maxDimensions.width;
                    }
                    if (targetDimensions.height > maxDimensions.height)
                    {
                        targetDimensions.height = maxDimensions.height;
                    }
                    
                    this._setSize(targetDimensions);
                    this._calcSizeDiscrepancy();
                    if (targetDimensions.width == maxDimensions.width && targetDimensions.height == maxDimensions.height)
                    {
                        this.commandQueue.enqueue( 
								this._applyOverflow.bind(this, maxDimensions), 
								this._isOverflowFinished.bind(this), 
								$(this.div).id + "_applyOverflow" );
                        return;
                    }
                    while (this.div.scrollHeight > this.div.getHeight())
                    {
                        targetDimensions.height += 20;
                        targetDimensions.width += 20;
                        
                        if (targetDimensions.width > maxDimensions.width)
                        {
                            targetDimensions.width = maxDimensions.width;
                        }
                        if (targetDimensions.width < maxDimensions.width && targetDimensions.height > maxDimensions.height)
                        {
                            targetDimensions.height = maxDimensions.height;
                        }
                        if (targetDimensions.width >= maxDimensions.width && targetDimensions.height >= maxDimensions.height)
                        {
                            this._setSize(maxDimensions);
                            this.commandQueue.enqueue( 
									this._applyOverflow.bind(this, maxDimensions), 
									this._isOverflowFinished.bind(this),
									$(this.div).id + "_applyOverflow" );
                            break;
                        }
                        if (this._checkBoundaries( targetDimensions, this.viewSize ))
                        {
                            break;
                        }
                        
                        this._setSize(targetDimensions);
                    }
                },
                
        _yCoordinateValue:
                function()
                {
                    if (this.coordinates.y == "" && this.coordinates.topOffset != "")
                    {
                        return this._offsetCoordinateValue("top");
                    }
                    else if (this.coordinates.y == "")
                    {
                        return 0;
                    }
                    return parseInt(this.coordinates.y);
                },
        
        _xCoordinateValue:
                function()
                {
                    if (this.coordinates.x == "" && this.coordinates.leftOffset != "")
                    {
                        return this._offsetCoordinateValue("left");
                    }
                    else if (this.coordinates.x == "")
                    {
                        return 0;
                    }
                    return parseInt(this.coordinates.x);
                },
                
        _offsetCoordinateValue:
                function(pos)
                {
                    if ($H(this.coordinates).get(pos + "Offset") == "")
                    {
                        return 0;
                    }
                    return parseInt( $H(this.coordinates).get(pos + "Offset") );
                },
                
        _dimToString:
                function(dim)
                {
                    if (dim != null && dim != undefined)
                    {
                        return dim.width + ", " + dim.height;
                    }
                    else
                    {
                        return "n/a";
                    }
                }
    }
),

// ********************************************************************************************************************
// Work Space - a common area for namespacing JavaScript fields and methods that a page can extend on the fly
// ********************************************************************************************************************

Workspace: 
	{
		defaultSpace:
			{
				extend: 
					function(newScripts) 
					{ 
						Object.extend(this, newScripts); 
					} 
			},
			
		extend:
			function(scripts)
			{
				if (!Thirteen.Workspace.each)
				{
					Object.extend(Thirteen.Workspace, Enumerable);
				}

				Object.extend(this, scripts);
				Object.keys(scripts).each(
					function(ns)
					{
						Object.extend( $H(Thirteen.Workspace).get(ns), Thirteen.Workspace.defaultSpace );
					}
				);

			}
	}

}
);
        
