    // widgets.js

    ////////////////
    // Globals
    ////////////////
    var AWMenuBorderWidth = 2;
    var AWMenuOffset = 15;
    var AWLinkId = null;
    var AWActiveMenu = null;
    var AWMenuLinkSenderIdKey = 'awmls';
    // active popup div is a direct decendent of the body tag. Used to display popups
    // for browsers that do not fully support positioning of elements
    var AWActivePopupDiv = null;
    var AWOrigDocumentOnMouseDown = window.document.onmousedown;

    ////////////////////
    // Common functions
    ////////////////////

    function awundisplayDiv (divObject)
    {
        if (divObject != null) {
            divObject.style.display = 'none';
            awsetElementsVisibility('SELECT', 'visible');
        }
    }

    function awunhiliteDiv (divObject)
    {
        if (divObject != null) {
            if (awstringEndsWith(divObject.className, ' check')) {
                divObject.className = 'awmenuCell check';
            }
            else if (awstringEndsWith(divObject.className, ' bullet')) {
                divObject.className = 'awmenuCell bullet';
            }
            else {
                divObject.className = 'awmenuCell';
            }
        }
    }

    function awhiliteDiv (divObject)
    {
        if (divObject != null) {
            if (awstringEndsWith(divObject.className, ' check')) {
                divObject.className = 'awmenuCellHilite check';
            }
            else if (awstringEndsWith(divObject.className, ' bullet')) {
                divObject.className = 'awmenuCellHilite bullet';
            }
            else {
                divObject.className = 'awmenuCellHilite';
            }
        }
    }

    function awhideActiveMenu ()
    {
        if (IsIEonMac) {
            // handles the special case for IE running on Mac OS
            // uses the popup div to display the menu contents instead of the menu div
            if (AWActivePopupDiv != null) {
                awdisableDocumentClick();
                awundisplayDiv(AWActivePopupDiv);
            }
            AWActivePopupDiv = null;
            AWActiveMenu = null;
        }
        else {
            if (AWActiveMenu != null) {
                awdisableDocumentClick();
                awundisplayDiv(AWActiveMenu);
            }
            AWActiveMenu = null;
        }
    }

    //////////////////
    // Event Handlers
    //////////////////

    /*
        Called when the user types a key on the popup menu link
    */

    function awmenuLinkOnKeyDown (positioningObject, menuName, linkId, mevent)
    {
        if (awkeyCode(mevent) == 13) {
            awmenuLinkOnClick(positioningObject, menuName, linkId, mevent);
            var firstMenuLink = awfirstMenuLink(menuName);
            if (firstMenuLink != null) {
                firstMenuLink.focus();
                return false;
            }
        }
        return true;
    }

    /**
    *  Recurses through the contents of the element looking for the first ocurrenc of <A> tag.
    */
    function awfirstMenuLinkRecursive (element)
    {
        var menuLink = null;
        var eleChildren = awgetChildren(element);
        var eleChildrenSize = eleChildren.length;
        var i = 0;
        for (i = 0; i < eleChildrenSize; i++) {
            var eleChild = eleChildren[i];
            if (typeof eleChild != "undefined") {
                if (eleChild.tagName == 'A') {
                    return eleChild;
                }
                else {
                    menuLink = awfirstMenuLinkRecursive(eleChild);
                    if (menuLink != null) {
                        return menuLink;
                    }
                }
            }
        }
        return menuLink;
    }

    function awfirstMenuLink (menuName)
    {
        var menuDiv = awgetElementById(menuName);
        return awfirstMenuLinkRecursive(menuDiv);
    }

    function awlastMenuLinkRecursive (element)
    {
        var eleChildren = awgetChildren(element);
        var i = 0;
        // look for last A tag
        for (i = eleChildren.length - 1; i > -1; i--) {
            var eleChild = eleChildren[i];
            if (typeof eleChild != "undefined") {
                if (eleChild.tagName == 'A') {
                    return eleChild;
                }
                else {
                    menuLink = awlastMenuLinkRecursive(eleChild);
                    if (menuLink != null) {
                        return menuLink;
                    }
                }
            }
        }
        return null;
    }

    function awlastMenuLink (menuName)
    {
        var menuDiv = awgetElementById(menuName);
        return awlastMenuLinkRecursive(menuDiv);
    }

    /**
        Called when user clicks a PopupMenuLink.
    */
    // used by both PopupMenu and PopupMenuLink to handle / cancel mouse down
    // both need to have the active menu closed and not affect any containing
    // component (table row select) -- use cover div in future to avoid having
    // to explicitly cancel mouse down.
    function awmenuOnMouseDown (mevent)
    {
        awhideActiveMenu();
        awcancelBubble(event);
        return false;
    }

    function awmenuLinkOnClick (positioningObject, menuName, linkId, mevent)
    {
        if (IsIEonMac) {
            // handles special case for IE running on Mac OS
            // uses the popup div to display the menu contents instead of the menu div
            return awmenuLinkOnClickMacIE(positioningObject, menuName, linkId, mevent);
        }

        if (!awisActionPending()) {
            var divObject = awgetElementById(menuName);
            if (AWActiveMenu != divObject) {
                // Note: do not set awsetActionPending(true) since
                // this only displays the menu.
                awhideActiveMenu();
                AWLinkId = linkId;
                AWActiveMenu = divObject;
                awenableDocumentClick(awhideActiveMenu);
                if (positioningObject != null) {

                    // must display first to get proper coordinates.
                    divObject.style.display = '';

                    // position to 0,0 to allow the popup to expand to full size
                    divObject.style.top = 0;
                    divObject.style.left = 0;

                    var newTop = awabsoluteTop(positioningObject) + positioningObject.offsetHeight;
                    var newLeft = awabsoluteLeft(positioningObject);
                    divObject.style.top = awcorrectForBottomEdge(newTop, divObject) + 'px';
                    divObject.style.left = awcorrectForRightEdge(newLeft, divObject) + 'px';
                    awdisplayDiv(divObject);
                }
                else {
                    awpositionAndDisplayDiv(divObject, mevent);
                }
            }
            else {
                awhideActiveMenu();
            }
        }
        // cancelBubble is required because the document.onmousedown gets called after this method is called,
        // and would, of course, call awhideActiveMenu which hides the menu displayed by this method.
        // To support netscape, cancelBubble needs to be set at the end of this method. On netscape,
        // execution of this event listener is stopped as soon as cancelBubble is set to true.
        awcancelBubble(mevent);
        return false;
    }


    // This method handles the special case for IE 5 running on Mac OS.
    // It utilizes the popup div to display the menu contents instead of using
    // the menu div directly.
    function awmenuLinkOnClickMacIE (positioningObject, menuName, linkId, mevent)
    {
        if (!awisActionPending()) {
            var menuDiv = awgetElementById(menuName);
            var popupDiv = awgetElementById('awpopupDiv');
            if (AWActiveMenu == null) {
                // Note: do not set awsetActionPending(true) since
                // this only displays the menu.
                awhideActiveMenu();
                AWLinkId = linkId;
                AWActiveMenu = menuDiv;
                AWActivePopupDiv = popupDiv;
                awenableDocumentClick(awhideActiveMenu);
                awpositionDisplayMacIE(menuDiv, popupDiv, mevent);
            }
            else {
                awhideActiveMenu();
            }
        }
        awcancelBubble(mevent);
        return false;
    }

    function awenableDocumentClick (func)
    {
        // this method makes it so a click
        // on the background makes the menu go away
        AWOrigDocumentOnMouseDown = window.document.onmousedown;
        window.document.onmousedown = func;
    }

    function awdisableDocumentClick ()
    {
        if (AWOrigDocumentOnMouseDown) {
            window.document.onmousedown = AWOrigDocumentOnMouseDown;
            AWOrigDocumentOnMouseDown = null;
        }
    }

    function awmenuKeyDown (menuCellDivLink, senderId, formId, mevent)
    {
        var returnVal = awShouldHandleMenuKeyDown(menuCellDivLink, mevent);
        if (returnVal == true) {
            returnVal = awmenuClicked(menuCellDivLink, senderId, formId);
            awhideActiveMenu();
        }
        return returnVal;
    }

    /**
        Called when user makes a menuItem choice.
    */
    function awmenuClicked (menuCellDiv, senderId, formId)
    {
        if (!awtestAndSetActionPending()) {
            // pass the menuItemSender and linkId as comma delimited list
            var senderList = (AWLinkId == null) ? senderId : AWLinkId + "," + senderId;
            if (formId != null) {
                formObject = awgetElementById(formId);
                awaddFormField(formObject, AWSenderIdKey, senderList);
                awsubmitForm(formObject);
            }
            else {
                var url = awformatUrl(senderList);
                AWLinkId = null;
                awsetDocumentLocation(url, null);
            }
        }
        return false;
    }

    function awmenuButtonOver (menuButtonDiv)
    {
        if (!awisActionPending()) {
            menuButtonDiv.className = "btnOnBrand";
        }
        return false;
    }

    function awmenuButtonOut (menuButtonDiv)
    {
        menuButtonDiv.className = "btnOffBrand";
        return false;
    }

    // Called when user mouse enters a menu cell
    function awcellMouseOver (divObject)
    {
        awhiliteDiv(divObject);
        return false;
    }

    function awcellMouseOut (divObject)
    {
        awunhiliteDiv(divObject);
        return false;
    }

    ///////////
    // Alerts
    ///////////
    function awunsupportedBrowser ()
    {
        alert("PopupMenus not supported on this browser");
    }

    function awNotImplemented ()
    {
        alert("This feature is under construction and not currently available.");
        return false;
    }

    ///////////////
    // AWButton
    ///////////////
    function awbtnMouseOver (divObject, styleName)
    {
        if (!awisActionPending()) {
            divObject.className = styleName;
            awapplyFilterToImages(divObject, "invert");
        }
    }

    function awbtnMouseOut (divObject, styleName)
    {
        divObject.className = styleName;
        awapplyFilterToImages(divObject, "");
    }

    function awapplyFilterToImages (divObject, filterName)
    {
        var childImages = divObject.getElementsByTagName("IMG");
        for (var i=0; i < childImages.length; i++) {
            childImages[i].style.filter = filterName;
        }
    }

    //////////////////////
    // Lazy Loading Divs
    //////////////////////
    /**
        This utility function is for the convenience
        of the menu system and allows for the placement of
        an <AWLazyDiv> tag within another div (divObject) that the system
        knows about.  It searches for a child div within divObject
        and calls awloadLazyDiv(child) until its loaded.
    */
    function awloadLazyChildren (divObject)
    {
        var childrenArray = awgetChildren(divObject);
        var arrayLength = childrenArray.length;
        var index = 0;
        var val = false;
        for (index = 0; index < arrayLength; index++) {
            var childDiv = childrenArray[index];
            if (childDiv.tagName == 'DIV') {
                val = val || awloadLazyDiv(childDiv);
            }
        }
        return val;
    }

    function awDownloadContent (srcUrl)
    {
        var iframe = awCreateRequestIFrame("AWDownload");
        iframe.src = srcUrl;
    }

    /**
        Force a lazy div, divObject, to fetch from the server and copy
        results into the div.
    */
    function awloadLazyDiv (divObject)
    {
        if (awdivNeedsLoading(divObject)) {
            var iframe = awCreateRefreshIFrame();
            iframe.src = awformatSenderUrl(divObject.id);
            awStartRefreshTimer();
            return true;
        }
        else if (awloadLazyChildren(divObject)) {
            return true;
        }

        return false;
    }

    function awcopyFromDocument (sourceDocument, divId)
    {
        // This is only called from the iframe's document.
        var sourceDiv = sourceDocument.getElementById('AWLazyDivSource');
        var destDiv = awgetElementById(divId);
        destDiv.innerHTML = sourceDiv.innerHTML;
        awPostLoadLazyDiv();
    }

    ////////////////////
    // Util for LazyDiv
    ////////////////////
    function awdivNeedsLoading (divObject)
    {
        // it is necessary to convert it into uppercase for Netscape
        var divInnerHtml = divObject.innerHTML.toUpperCase();
        var needsLoading = divInnerHtml.indexOf('<AW_NEEDS_LOADING') == 0;
        return needsLoading;
    }

    function awChildrenNeedLoading (divObject)
    {
        var childrenArray = awgetChildren(divObject);
        var arrayLength = childrenArray.length;
        var index = 0;
        for (index = 0; index < arrayLength; index++) {
            var childDiv = childrenArray[index];
            if (childDiv.tagName == 'DIV') {
                if (awdivNeedsLoading(childDiv)) {
                    return true;
                }
            }
        }
        return false;
    }

    /////////////
    // Util
    /////////////

    function awpositionAndDisplayDiv (divObject, mevent)
    {
        awpositionMenu(divObject, mevent);
        // call awdisplayDiv after awpositionMenu so that
        // menu is in final place before computing the intersections
        awdisplayDiv(divObject);
    }

        ////////////////////
        // Menu Positioning
        ////////////////////
    function awclientWidth (docElement)
    {
        var clientWidth = docElement.clientWidth;
        clientWidth += docElement.scrollLeft;
        return clientWidth;
    }

    function awcorrectForRightEdge (menuLeft, menuDiv)
    {
        var clientWidth = awclientWidth(awdocumentElement());
        var adjustedMenuLeft = clientWidth - menuDiv.offsetWidth;
        if (menuLeft > adjustedMenuLeft) {
            menuLeft = adjustedMenuLeft;
        }
        return menuLeft;
    }

    function awcorrectForBottomEdge (menuTop, menuDiv)
    {
        var clientHeight = awclientHeight(awdocumentElement());
        var adjustedMenuTop = clientHeight - menuDiv.offsetHeight;
        if (menuTop > adjustedMenuTop) {
            menuTop = adjustedMenuTop;
        }
        return menuTop;
    }

    function awrepositionDivToWindow (menuDiv)
    {
        var menuTop = awabsoluteTop(menuDiv);
        var menuLeft = awabsoluteLeft(menuDiv);
        var adjustedTop = awcorrectForBottomEdge(menuTop, menuDiv);
        var adjustedLeft = awcorrectForRightEdge(menuLeft, menuDiv);
        menuDiv.style.top = adjustedTop + 'px';
        menuDiv.style.left = adjustedLeft + 'px';
    }

    function awabsoluteLeft (element)
    {
        var absoluteLeft = element.offsetLeft;
        var parentElement = element.offsetParent;
        while (parentElement != null) {
            absoluteLeft += parentElement.offsetLeft;
            if (parentElement != awdocumentElement()) {
                // subtract scrollLeft for positioning inside of scrollable elements
                absoluteLeft -= parentElement.scrollLeft;
            }
            parentElement = parentElement.offsetParent;
        }
        return absoluteLeft;
    }

    /**
    * These functions are part of the "DateField" component
    */
    function awdateFieldClicked (date, clientFormatString, targetName)
    {
        var textField = awgetElementById(targetName);
        var dateString = null;
        if (clientFormatString != null && clientFormatString.length > 0) {
            dateString = awformatDate(date, clientFormatString)
        }
        else {
            dateString = date.toString();
        }
        textField.value = dateString;
    }

    function awdateFieldClickedRefresh (date, clientFormatString, targetName)
    {
        awdateFieldClicked(date, clientFormatString, targetName);
        var textField = awgetElementById(targetName);
        _awtextRefresh(textField);
    }

    //////////////
    // Dialog box scripts
    //////////////
    var AWCover;


    function awDisablePage ()
    {
        AWCover = document.createElement("div");
        document.body.appendChild(AWCover);
        AWCover.onclick="return false;";
        AWCover.style.position="absolute";

        AWCover.documentOverflow = null;

        if( typeof( window.innerWidth ) == 'number' ) {
            // NS
            var container = document.body;

            // since we can't turn off the scroll bars, position at top left corner and
            // make the cover the maximum of either the size of the page or the monitor
            // (to handle resize)
            AWCover.style.left = "0px";
            AWCover.style.top = "0px";

            var height = container.scrollHeight > screen.availHeight ?
                            container.scrollHeight : screen.availHeight;
            var width = container.scrollWidth > (screen.availWidth) ?
                            container.scrollWidth : (screen.availWidth);

            AWCover.style.width = width + "px";
            AWCover.style.height = height + "px";
        }
        else {
            var container = document.documentElement;

            // hold onto the scroll bars style for redisplay later
            AWCover.documentOverflow = container.style.overflow;
            container.style.overflow="hidden";

            // position cover at current scroll -- killing scroll bars so only have to
            // worry about resizing of window
            AWCover.style.left = container.scrollLeft + "px";
            AWCover.style.top = container.scrollTop + "px";

            // user can resize browser window so resize this to the size of the monitor
            AWCover.style.width = screen.availWidth + "px";
            AWCover.style.height = screen.availHeight + "px";

            // hide all selects since this collides with cover div
            awsetElementsVisibility('SELECT', 'hidden');
        }

//        debug("cover: " + AWCover.style.width + " " + AWCover.style.height +
//              " scrollLeft: " + container.scrollLeft + " scrollTop: " + container.scrollTop);

        AWCover.style.zIndex = "5";
        AWCover.style.filter = "alpha(opacity=070)";
        AWCover.style.background = "white";
        AWCover.style.visibility = "visible";
        //AWCover.style.border="1px red solid";
    }

    function awEnablePage ()
    {
        if (AWCover) {
            // turn scroll bars back on
            if (AWCover.documentOverflow != null) {
                document.documentElement.style.overflow = AWCover.documentOverflow;
                awsetElementsVisibility('SELECT', 'visible');
            }
            document.body.removeChild(AWCover);
            AWCover = null;
        }
    }


    function awPositionDialogBox (target)
    {
        var container;
        if (window.innerHeight) {
            // NS
            container = document.body;
        }
        else {
            // IE
            container = document.documentElement;
        }

        target.style.left =
            container.clientWidth/2 - target.offsetWidth/2 + container.scrollLeft + "px";
        target.style.top =
            container.clientHeight/2 - target.offsetHeight/2 + container.scrollTop + "px";
    }

    var AWActiveDialogDiv;
    function awShowDialogDiv (target, preOpenFunction, documentClickFunction)
    {
        // displays the dialog and positions it in the middle of the browser window
        // optional documentClickFunction can be registered which will get called
        // on any click

        // if there was a previous dialog div, then call it's closer first
        if (AWActiveDialogDiv && AWActiveDialogDiv.awCloseDialogFunc) {
            var modal = AWActiveDialogDiv.awCloseDialogFunc();
            if (modal) {
                // modal so don't let other div's open
                return;
            }
        }

        if (preOpenFunction) {
            preOpenFunction();
        }

        AWActiveDialogDiv = target;

        if (target.style.display != "block") {
            target.style.display="block";
        }

        awPositionDialogBox(target);

        if (documentClickFunction) {
            awenableDocumentClick(documentClickFunction);
        }

        awhideIntersectingSelects(target);

        return false;
    }

    function awHideDialogDiv (evt)
    {
        if (AWActiveDialogDiv) {
            awdisableDocumentClick();
            awundisplayDiv(AWActiveDialogDiv);
            AWActiveDialogDiv = null;
        }
        return false;
    }

    //////////////
    // About box scripts
    //////////////
    function awToggleAboutBox (targetId, evt)
    {
        var evt = (evt) ? evt : event;

        // if a tab key caused the about box to be called, then noop
        if (evt.type == "keydown" && awkeyCode(evt) != 13) {
            return true;
        }

        // This method must be registered on the mouse down event since the
        // awdisableDocumentClick is registered on the mouse down event.  If there is
        // an active dialog, then the user must have caused the awToggleAboutBox to be
        // called while the dialog is open so we should "close" the dialog.  In this case
        // cancelBubble so the document level click handler does not get called.

        // If there is not an active dialog, then we should open the dialog.  In this case
        // cancelBubble so the document.onMouseDown=awHideDialogDivthat we're going to
        // register via awShowDialogDiv doesn't get called.
        if(AWActiveDialogDiv) {
            awHideDialogDiv(evt);
        }
        else {
            var toggleDiv = awgetElementById(targetId);

            if (awChildrenNeedLoading(toggleDiv)) {
                awloadLazyChildren(toggleDiv);
            }
            awShowDialogDiv(toggleDiv, null, awHideDialogDiv);
            toggleDiv.awCloseDialogFunc = awHideDialogDiv;
        }
        awcancelBubble(evt);

        return false;
    }

    //////////////
    // Aliases
    //////////////
    function aww01 (divObject, styleName)
    {
        return awbtnMouseOut(divObject, styleName);
    }

    function aww02 (divObject, styleName)
    {
        return awbtnMouseOver(divObject, styleName)
    }

    // called in window onLoad to fix the window background image to match width of the TOC alley
    function awFixTocWidth ()
    {
        var alley = awgetElementById("tocAlley");
        if (alley) {
            var newWidth = -366 + alley.offsetWidth;
            var newPosString = newWidth+"px" + " 0px";
            var currPosString;
            if (document.body.currentStyle) {
                // ie
                currPosString = document.body.currentStyle.backgroundPositionX + " " +
                                document.body.currentStyle.backgroundPositionY;
            }
            else {
                // ns
                currPosString = document.body.style.backgroundPosition;
                if ( currPosString == "") {
                    currPosString = awGetClassProperty("body",
                                                       document.body.className,
                                                       "backgroundPosition");
                }
            }
            if (currPosString != newPosString) {
                document.body.style.backgroundPosition = newPosString;
            }
        }
    }

    function awGetClassProperty (tag, className, property)
    {
        try {
            var sheets = document.styleSheets;
            if(sheets.length > 0) {
                // loop over each sheet
                for(var x = 0; x < sheets.length; x++) {
                    // grab stylesheet rules
                    var rules = sheets[x].cssRules;
                    if(rules.length > 0) {
                        // check each rule
                        for(var y = 0; y < rules.length; y++) {
                            var style = rules[y].style;
                            if(((style[property] != "") && (style[property] != null)) &&
                               ((rules[y].selectorText == className) ||
                                (rules[y].selectorText == (tag + "." + className)))) {
                                return style[property];
                            }
                        }
                    }
                }
            }
        }
        catch (e) {
            // if stylesheets are not readable, then just return null
        }
    }

// Make sure to fix the TOC width any time we update the page
awDomRegisterRefreshCallback (awFixTocWidth);
