/* 
 * ================================================================
 * New popupwindows-on-steroids!
 * ================================================================
 */

function isIpad()
{
    return navigator.platform == 'iPad';
}

var PopupWindowUtils = {
    /*
     * ViewPortSize(): Get the size of the current viewport (that is, 
     * the entire scrolled region of the current document).  This may
     * be larger than the physical size of the screen.
     */
    ViewPortSize: function () {
        if (typeof window.innerHeight != 'undefined' && typeof window.scrollMaxY != 'undefined') {  // Firefox
            pageWidth = window.innerWidth + window.scrollMaxX;
            pageHeight = window.innerHeight + window.scrollMaxY;
        } else if (document.body.scrollHeight > document.body.offsetHeight) { // all but Explorer Mac
            pageWidth = document.body.scrollWidth;
            pageHeight = document.body.scrollHeight;
        } else { // works in Explorer 6 Strict, Mozilla (not FF) and Safari
            //pageWidth = document.body.offsetWidth + document.body.offsetLeft; 
            //pageHeight = document.body.offsetHeight + document.body.offsetTop;
            pageWidth = document.body.offsetWidth;
            pageHeight = document.body.offsetHeight;
        }
        return {w: (isIpad() ? 1100 : pageWidth), h: pageHeight}
    },

    ScrollOffset: function () {
        var dx = 0;
        var dy = 0;

        if (window.pageXOffset) {
            dx = window.pageXOffset;
        } else if (document.body.scrollLeft) {
            dx = document.body.scrollLeft;
        } else if (document.documentElement && document.documentElement.scrollLeft) {
            dx = document.documentElement.scrollLeft;
        }

        if (window.pageYOffset) {
            dy = window.pageYOffset;
        } else if (document.body.scrollTop) {
            dy = document.body.scrollTop;
        } else if (document.documentElement && document.documentElement.scrollTop) {
            dy = document.documentElement.scrollTop;
        }

        return {x: dx, y: dy}
    },

    ScrollBarSize: function() {
        document.body.style.overflow = 'hidden';

        var width = document.body.clientWidth;

        document.body.style.overflow = 'scroll';

        width -= document.body.clientWidth;

     
        if (!width) width = document.body.offsetWidth-document.body.clientWidth;


        document.body.style.overflow = '';

        return width;

        /*
        if (window.innerWidth && document.documentElement) {
            return (window.innerWidth - document.documentElement.clientWidth);
        } else {
            return 0;
        }
        */
    },

    /*
     * ScreenSize(): Return the size of the actual client area of the
     * browser.
     */
    ScreenSize: function () {
        if (window.innerWidth) {
            screenWidth = window.innerWidth;
            screenHeight = window.innerHeight;
        } else if (document.documentElement) {
            screenWidth = document.documentElement.clientWidth;
            screenHeight = document.documentElement.clientHeight;
        } else if (document.body.clientWidth) {
            screenWidth = document.body.clientWidth;
            screenHeight = document.body.clientHeight;
        } else {
            screenWidth = document.body.offsetWidth;
            screenHeight = document.body.offsetHeight;
        }
        return {w: (isIpad() ? 1100 : screenWidth), h: screenHeight}
    },

    GetAbsolutePosition: function (element) {
        var leftPos = element.offsetLeft;
        var topPos = element.offsetTop;
        var parentElement = element.offsetParent;

        while (parentElement != null) {
            leftPos += parentElement.offsetLeft;
            topPos += parentElement.offsetTop;
            parentElement = parentElement.offsetParent;
        }
        return {x: leftPos, y:topPos};
    },

    /*
     * ConvertToPixels(): Convert a CSS measurement (em, pt, %) to
     * actual pixels.  "str" is the measurement, "context" is the
     * context (i.e. the element) in which to evaluate the 
     * measurement.
     */
    ConvertToPixels: function(str, context) {
        if (/px$/.test(str)) { return parseInt(str); }

        var tmp = document.createElement('div');
        tmp.style.visibility = 'hidden';
        tmp.style.position = 'absolute';           
        tmp.style.lineHeight = '0';          

        if (/%$/.test(str)) {
            context = context.parentNode || context;
            tmp.style.height = str;
        } else {
            tmp.style.borderStyle = 'solid';
            tmp.style.borderBottomWidth = '0';
            tmp.style.borderTopWidth = str;
        }
        if (!context) { context = document.body; }

        context.appendChild(tmp);
        var px = tmp.offsetHeight;
        context.removeChild(tmp);

        return px + 'px';
    },

    /*
     * GetComputedStyle(): A somewhat browser-independant
     * GetComputedStyle() function, that also converts all non-pixel
     * units to pixels.
     */
    GetComputedStyle: function(elem, style) {   
        var nonPixels = /(em|ex|pt|%)$/;

        var computedStyle;
        if (typeof elem.currentStyle != 'undefined') {
            computedStyle = elem.currentStyle;
        } else { 
            computedStyle = document.defaultView.getComputedStyle(elem, null);
        }
        var val = computedStyle[style];
        if (nonPixels.test(val)) { 
            return PopupWindowUtils.ConvertToPixels(val, elem); 
        } else if (val == "thin") {
        // IE CSS border widths...
            return 1;
        } else if (val == "medium") {
            return 2;
        } else if (val=="thick") {
            return 4;
        } else {
            return val;
        }
    }
};

var PopupWindow = {
    kCalloutMargin: 8,
    _openPopups: [],
    _openDialogs: 0,
    _popupCount: 0,
    _registeredTypes: {},

    minTop: 0,
    minLeft: 0,

    /*
     * Create(): This creates a popup, adding it to the top of the popup 
     * stack.  In general, don't use this, it's primarily meant for internal 
     * use.  Instead use Register() and CreateRegistered().  "params" are 
     * the creation params of the popup.  This code could be cleaned up, since 
     * a lot of the code here (particularly with respect to DIV/IFRAME 
     * sizing) is now done in Fix().
     *
     * TODO: Clean this up!
     */
    Create: function (params) {
        var popupContainer = document.getElementById("popupContainer");
        var screenSize = PopupWindowUtils.ScreenSize();

        if (!params) params = {};

        if (params.preLoad) {
            params.preLoad(params);
        }

        this._popupCount += 1;

        var divName = "_popupdiv_" + this._popupCount;
        var frameName = "_popupframe_" + this._popupCount;

        var popupDiv = document.createElement("DIV");
        popupDiv.id = divName;

        var popupTitle = document.createElement("H1");
        if (params.titleClass) {
            popupTitle.className = params.titleClass;
        } else if (params.isDialog) {
            popupTitle.className = "popupDialogTitle";
        } else {
            popupTitle.className = "popupWindowTitle";
        }

        popupTitle.innerHTML = params.title ? params.title: "Popup";
        this._CreateCloseButton(popupTitle, params.isDialog);
        popupDiv.appendChild(popupTitle);

        var popupIframe = document.createElement("IFRAME");
        popupIframe.name = frameName;
        popupIframe.id = frameName;
        if (params.secure) {
            params.alreadyClosed = false;
            Events.RegisterEvent(popupIframe, "load", function() {
                if (popupIframe.style.visibility == "hidden") {
                    PopupWindow.Fix(frameName);
                } else if (popupIframe.style.visibility == "visible" && !params.alreadyClosed) {
                    params.alreadyClosed = true;
                    PopupWindow.Close();
                }
            });
        }

        var windowW = params.width ? params.width: "400px";
        var windowH = params.height ? params.height: "300px";

        popupIframe.frameBorder = "0";

        popupDiv.style.visibility = "hidden";
        popupDiv.appendChild(popupIframe);

        popupContainer.appendChild(popupDiv);

        // Let's handle all the different 1001 browsers...
        // This actually craps out IE, so I've removed it...
        //var frameBody;
        //if (popupIframe.contentWindow) {
        //    frameBody = popupIframe.contentWindow.document.body;
        //} else if (popupIframe.document) {
        //    frameBody = popupIframe.document.body;
        //} else if (popupIframe.contentDocument) {
        //    frameBody = popupIFrame.contentDocument.body;
        //} else {
        //    frameBody = window.frames[frameName].document.body;
        //}
        //// TODO: Fix to use styles instead
        //frameBody.innerHTML = "<html><body><center>Loading...</center></body></html>";

        if (params.isDialog) {
            popupDiv.className = params.className ? params.className : "popupDialog";
        } else if (params.callout) {
            popupDiv.className = params.className ? params.className : "popupCallout";
        } else {
            popupDiv.className = params.className ? params.className : "popupWindow";
        }

        popupDiv.style.position = "absolute";
        popupDiv.style.left = "0px";
        popupDiv.style.top = "0px";

        popupDiv.style.width = windowW;
        popupDiv.style.height = windowH;

        if (params.isDialog || params.callout) {
            popupDiv.style.zIndex = "50004";
        } else {
            popupDiv.style.zIndex = "50002";
        }

        popupIframe.style.visibility = "hidden";

        // Find out how big our DIV actually is...
        var measureW = popupDiv.offsetWidth;
        var measureH = popupDiv.offsetHeight;

        // And center it by default
        //var scrollOffset = PopupWindowUtils.ScrollOffset();
        var posX = ((screenSize.w - measureW)/2); // + scrollOffset.x;
        var posY = ((screenSize.h - measureH)/2); // + scrollOffset.y;

        // And resize the iframe to be inside it
        // GetComputedStyle ALWAYS returns either "0" or "$FOOpx", so parseInt()
        // will return a pixel size.
        var borderH = parseInt(PopupWindowUtils.GetComputedStyle(popupDiv, "borderTopWidth")) +
            parseInt(PopupWindowUtils.GetComputedStyle(popupDiv, "borderBottomWidth"));
        var borderW = parseInt(PopupWindowUtils.GetComputedStyle(popupDiv, "borderLeftWidth")) +
            parseInt(PopupWindowUtils.GetComputedStyle(popupDiv, "borderTopWidth"));

        popupIframe.style.top = popupTitle.offsetHeight+"px";

        popupIframe.style.width = (measureW - borderW)+"px";
        popupIframe.style.height = (measureH - borderH - popupTitle.offsetHeight)+"px";

        popupDiv.style.left = params.x ? params.x : (posX + "px");
        popupDiv.style.top = params.y ? params.y : (posY + "px");

        var currentPopup = {
            div: popupDiv, 
            title: popupTitle,
            iframe: popupIframe, 
            params: params,
            response: {}
        };

        if (!params.noBarrier) {
            var pos = this._openPopups.push(currentPopup);
            if (pos > 1) {
                if (!params.isDialog && !params.callout) {
                    this._openPopups[pos-2].div.style.zIndex = "50000";
                }
            }

            var barrier = document.getElementById((params.isDialog || params.callout)?"dialogBarrier":"popupBarrier");

            if (params.isDialog || params.callout) {
                this._openDialogs += 1;
            }

            var vpSize = PopupWindowUtils.ViewPortSize();
            
            var sbW = 0;
            var sbH = 0;
            if (vpSize.h > screenSize.h) {
                sbW = PopupWindowUtils.ScrollBarSize();
            }
            if (vpSize.w > screenSize.w) {
                sbH = PopupWindowUtils.ScrollBarSize();
            }
            
            // console.log("Initial create setting barrier with to " + (vpSize.w - sbW) + " pixels");
            
            // FIXME: vpSize includes the scrollbar size, so we
            // need to fix this somehow.
            barrier.style.cursor = "wait";
            barrier.style.width = (vpSize.w - sbW) + "px";
            barrier.style.height = (vpSize.h - sbH) + "px";
            barrier.style.visibility = "visible";

            if (params.isDialog || params.callout) {
                barrier.style.zIndex = "50003";
            } else {
                barrier.style.zIndex = "50001";
            }
        }

        if (params.url) {
            this._LoadPopup(currentPopup, params.url);
            // Always fix the window, even if it doesn't do it itself
            if (params.fixTimeout) {
                currentPopup.fixTimeout = setTimeout("PopupWindow.Fix('"+frameName+"')", params.fixTimeout);
            } else {
                currentPopup.fixTimeout = setTimeout("PopupWindow.Fix('"+frameName+"')", 10000);
            }
        } else if (params.staticContent) {
            this._SetPopupContent(currentPopup, params.staticContent);
        }

        return currentPopup;
    },

    /*
     * Close(): Close the topmost popup.
     */
    Close: function () {
        if (this._openPopups.length == 0) {
            throw "No open popups!";
        }
        var popupName = this._openPopups[this._openPopups.length-1].iframe.name;
        this.HandleEvent(popupName, "onClose");
        
        var popupContainer = document.getElementById("popupContainer");
        var popup = this._openPopups.pop();

        popup.div.style.visibility = "hidden";
        popup.iframe.style.visibility = "hidden";

        if (this._openPopups.length > 0) {
            this._openPopups[this._openPopups.length - 1].div.style.zIndex = "50002";
        } else {
            if (!popup.params.noBarrier) {
                var barrier = document.getElementById("popupBarrier");
                barrier.style.visibility = "hidden";
                barrier.style.width = "0";
                barrier.style.height = "0";
                barrier.style.zIndex = "-50001";
                barrier.style.backgroundColor = "";
            }
        }

        if (!popup.params.noBarrier) {
            if (popup.params.isDialog || popup.params.callout) {
                this._openDialogs -= 1;
                if (this._openDialogs == 0) {
                    var barrier = document.getElementById("dialogBarrier");
                    barrier.style.visibility = "hidden";
                    barrier.style.width = "0";
                    barrier.style.height = "0";
                    barrier.style.zIndex = "-50003";
                    barrier.style.backgroundColor = "";
                }
            }
        }
        /* 
         * Doing this here crashes Safari in event handlers, so we defer until 
         * we're back in the main event loop.
         */
        // WAS: popupContainer.removeChild(popup.div);
        //popupContainer.removeChild(popup.div);
        setTimeout("document.getElementById('popupContainer').removeChild(document.getElementById('"+popup.div.id+"'))", 0);

        if (popup.registeredName) {
            this._ResetHash();
        }
    },

    ReplaceTop: function (params) {
        if (this._openPopups.length == 0) {
            throw "No open popups";
        }
        var currentPopup = this._openPopups[this._openPopups.length-1];
        var frameName = currentPopup.iframe.name;
        if (params.url) {
            currentPopup.iframe.style.visibility = "hidden";
            currentPopup.div.style.cursor = "wait";
            currentPopup.params = params;
            this._LoadPopup(currentPopup, params.url);
            // Always fix the window, even if it doesn't do it itself
            if (params.secure) {
                // Shorter timeout for secure
                currentPopup.fixTimeout = setTimeout("PopupWindow.Fix('"+frameName+"')", 1000);
            } else {
                currentPopup.fixTimeout = setTimeout("PopupWindow.Fix('"+frameName+"')", 5000);
            }
        }
        return currentPopup;
    },

    ReplaceTopRegistered: function (name) {
            var params = this._registeredTypes[name];
        if (params) {
            var popup = this.ReplaceTop(params);
            popup.registeredName = name;
            this._ResetHash();
            return popup;
        } else {
                return null;
        }
    },

    GetTopmostRegistered: function () {
        for (var i=this._openPopups.length-1; i>=0; --i) {
            if (this._openPopups[i].registeredName) {
                return this._openPopups[i].registeredName;
            }
        }
        return null;
    },

    /*
     * Register(): Register a particular "type" of popup with the system.
     * "name" is the name of the popup type, "params" is the creation params
     * used by Create().
     */
    Register: function (name, params) {
        this._registeredTypes[name] = params;
    },

    Unregister: function (name) {
        this._registeredTypes[name] = undefined;
    },

    /*
     * CreateRegistered(): Create an instance of a registered popup type by
     * name.  "name" is the name of the popup type to create, returns the
     * created popup.  
     * dynamicParams are parameters that were added at time of popup creation 
     *   They are kept as part of the hash so they will be part of the URL and
     *   will be included in the bookmark
     * tempParams are similar to dynamic params but will not be part of the URL
     */
    CreateRegistered: function (name, noResetHash, dynamicParams, tempParams) {
        var params = this._registeredTypes[name];
        var fullParams;

        if (params) {
            fullParams = params;
            if (dynamicParams) { fullParams = ConcatObjects(params,dynamicParams) }
            if (tempParams) {fullParams = ConcatObjects(fullParams, tempParams) }
            var popup = this.Create(fullParams);
            popup.registeredName = name;
            if (!noResetHash) {
                this._ResetHash(dynamicParams);
            }
            return popup;
        } else {
            return null;
        }
    },

    /*
     * HandleEvent(): Handle an event generated by a popup.  "sender" is
     * the iframe name of the popup, "eventName" is the event being
     * triggered.
     */
    HandleEvent: function (sender, eventName) {
        /* 
         * This is called outside of the frame and frame event to handle any
         * frame events.  This allows us to do things like close the popup.
         */
        var popup = this.FindPopup(sender);
        if (popup) {
            if (popup.params[eventName]) {
                var theDocument = null;
                var theWindow = null;
                if ((typeof popup.params.secure == "undefined") || !popup.params.secure) {
                    theDocument = window.frames[popup.iframe.name].document;
                    // This works for Safari, FF, and most other browsers.
                    theWindow = window.frames[popup.iframe.name];
                    // This should fill in the proper window for IE
                    if (window.frames[popup.iframe.name].contentWindow) {
                        theWindow = window.frames[popup.iframe.name].contentWindow;
                    }
                }
                popup.params[eventName]({
                    popup: popup, 
                    frame: window.frames[popup.iframe.name],
                    frameDocument: theDocument,
                    frameWindow: theWindow
                });
            }
        }
    },

    TopInfo: function () {
        var popup = this._openPopups[this._openPopups.length-1];
        var theDocument = null;
        var theWindow = null;

        if ((typeof popup.params.secure == "undefined") || !popup.params.secure) {
            theDocument = window.frames[popup.iframe.name].document;
            // This works for Safari, FF, and most other browsers.
            theWindow = window.frames[popup.iframe.name];
            // This should fill in the proper window for IE
            if (window.frames[popup.iframe.name].contentWindow) {
                theWindow = window.frames[popup.iframe.name].contentWindow;
            }
        }

        return {
            popup: popup,
            frame: window.frames[popup.iframe.name],
            frameDocument: theDocument,
            frameWindow: theWindow
        };
    },

    /*
     * FindPopup(): Given an iframe name, "name", find the popup entry.
     * This does a linear search from top to bottom, since there will likely
     * only be two or three popups open at most, anyway, and the topmost
     * one is the most likely to be doing stuff.
     */
    FindPopup: function (name) {
        for (var i=this._openPopups.length-1; i>=0; --i) {
            var popup = this._openPopups[i];
            if (popup.iframe.name == name) {
                return popup;
            }
        }
        return null;
    },


    /*
     * ReCenterPopups(): Re-Center the popup(s) in the browser when the 
     * it is rezied by the user
     */
    ReCenterPopups: function() {
        for (var i=0; i <PopupWindow._openPopups.length; i ++) {
            PopupWindow.CenterPopup(PopupWindow._openPopups[i]);
        }
    },

    /* 
     * CenterPopup(): centers a given popup on the browser

     */
    CenterPopup: function(popup) {

        // Stolen from Create code...suppose should refactor

        if (!popup.params.callout) {
            var screenSize = PopupWindowUtils.ScreenSize();
            var pageSize = PopupWindowUtils.ViewPortSize();
            var scrollOffset = PopupWindowUtils.ScrollOffset();
            var scrollBarSize = PopupWindowUtils.ScrollBarSize();
            var scrollBarOffset = { x: 0, y: 0 };

            //get the popup size
            var popupDiv = popup.div;
            var measureW = popupDiv.offsetWidth;
            var measureH = popupDiv.offsetHeight;

            if (pageSize.h > screenSize.h) {
                scrollBarOffset.x = scrollBarSize;
            }
            
            // console.log("Screen size in center is " + screenSize.w + "x" + screenSize.h);
            // console.log("Page size in center is " + pageSize.w + "x" + pageSize.h);
            // console.log("Scrollbar size in center is " + scrollBarSize);

            // And center it, place it in the viewport center no matter what for iPad
            var posX = (((isIpad() ? pageSize.w : screenSize.w) - scrollBarOffset.x - measureW)/2) + (isIpad() ? 0 : scrollOffset.x);
            var posY = ((screenSize.h - scrollBarOffset.y - measureH)/2) + scrollOffset.y;
            
            if (posX < this.minLeft) posX = this.minLeft;
            if (posY < this.minTop) posY = this.minTop;

            var isFixed = false;

            if (popup.params.fixedX) {
                posX = popup.params.fixedX; //+ scrollOffset.x;
                isFixed = true;
            }

            if (popup.params.fixedY) {
                // On iPad, don't make position:fixed, place at current viewport offset
                // Otherwise, always position at top
                if (isIpad())
                {
                    posY = popup.params.fixedY + scrollOffset.y;
                }
                else
                {
                    posY = popup.params.fixedY; // + scrollOffset.y;
                    isFixed = true;
                }
            }

            if (popup.params.x) {
                posX = popup.params.x;
            }
            if (popup.params.y) {
                posY = popup.params.y;
            }

            /* IE7 supports position fixed, all others fail */
            if (IsIE() && !IsIE7()) {
                isFixed = false;
            }

            if (isFixed) {
                popupDiv.style.position = "fixed";
            } else {
                popupDiv.style.position = "absolute";
            }

            popupDiv.style.left = (posX + "px");
            popupDiv.style.top = (posY + "px");
        } else {
            this.FixCallOut(popup);
        }
        this.ReadjustBarrier();
    },

    FixCallOut: function(popup) {
        var calloutSource = document.getElementById(popup.params.callout);
        calloutImage = document.createElement("img")
        calloutImage.src ="/static/images/callout.gif";

        if (calloutImage.width == 0 && calloutImage.height == 0) {
        // Cheat here, for now.  FIXME: this should be handled properly, perhaps by preloading the callout GIF
            var calloutWidth = 14;
            var calloutHeight = 30;
        } else {
            var calloutWidth = calloutImage.width;
            var calloutHeight = calloutImage.height;
        }

        position = PopupWindowUtils.GetAbsolutePosition(calloutSource);
        calloutImage.style.position = "absolute";
        calloutImage.style.left = "-" + calloutWidth + "px";
        popup.div.appendChild(calloutImage);
        popup.div.style.left = (position.x + 4 + calloutSource.offsetWidth + Math.floor(calloutWidth/2)) + "px";
        var calloutCenter = position.y + Math.floor(calloutSource.offsetHeight/2);
        var calloutTop = calloutCenter - Math.floor(calloutHeight/2);
        var calloutBottom = calloutTop + calloutHeight;
        var divTop = parseInt(popup.div.style.top);
        var divBottom = divTop + popup.div.offsetHeight;

        if (calloutTop <= divTop + this.kCalloutMargin) {
        // Out of bounds, top
            var delta = divTop - calloutTop + this.kCalloutMargin;
            divTop -= delta;
            popup.div.style.top = divTop + "px";
        }

        if (calloutBottom >= divBottom - this.kCalloutMargin) {
        // Out of bounds, bottom
          var delta = calloutBottom - divBottom + this.kCalloutMargin;
          divTop += delta;
          popup.div.style.top = divTop + "px";
        }
        
        calloutImage.style.top = (calloutTop-divTop) + "px";
    },

    /*
     * ResizePopup(): Resize a popup (including the iframe and div) to a
     * given size.  "popup" is the popup entry, "w" and "h" are the
     * desired (client) size, and "titleHeight" is the height of the title
     * bar.
     */
    ResizePopup: function (popup, w, h, titleHeight) {
        var borderH = parseInt(PopupWindowUtils.GetComputedStyle(popup.div, "borderTopWidth")) +
            parseInt(PopupWindowUtils.GetComputedStyle(popup.div, "borderBottomWidth"));
        var borderW = parseInt(PopupWindowUtils.GetComputedStyle(popup.div, "borderLeftWidth")) +
            parseInt(PopupWindowUtils.GetComputedStyle(popup.div, "borderTopWidth"));
        var totalW = w + borderW;
        var totalH = h + borderH;
        popup.div.style.width = totalW + "px";
        popup.div.style.height = (totalH + titleHeight) + "px";
        popup.iframe.style.width = totalW + "px";
        popup.iframe.style.height = totalH + "px";

        // FIXME: Not sure how to handle this in the secure case for IE?
        if (!popup.params.secure && popup.iframe.contentWindow) {
        /*
         * Fix for the document size in IE6, apparently IE6 does not respect
         * CSS width/height on body initially, so we have to tell it a second
         * time.  We mean it!
         */
            popup.iframe.contentWindow.document.body.style.width = totalW + "px";
            popup.iframe.contentWindow.document.body.style.height = totalH + "px";
        }

        popup.iframe.style.top = titleHeight + "px";
    /*
        var screenSize = PopupWindowUtils.ScreenSize();
        var scrollOffset = PopupWindowUtils.ScrollOffset();
        var viewportSize = PopupWindowUtils.ViewPortSize();
        var scrollBarSize = PopupWindowUtils.ScrollBarSize();
        var scrollBarOffset = { x: 0, y: 0 };

        if (viewportSize.y > screenSize.y) {
            scrollBarOffset.x = scrollBarSize;
        }

        var posX = ((screenSize.w - scrollBarOffset.x - totalW)/2); //+ scrollOffset.x;
        var posY = ((screenSize.h - scrollBarOffset.y - (totalH + titleHeight))/2);// + scrollOffset.y;
        if (posX < this.minLeft) posX = this.minLeft;
        if (posY < this.minTop) posY = this.minTop;

        popup.div.style.left = popup.params.x ? popup.params.x : (posX + "px");
        popup.div.style.top = popup.params.y ? popup.params.y : (posY + "px");
    */
        this.CenterPopup(popup);
    },

    /*
     * Fix(): This routine resets some of the popup characteristics once the 
     * document inside the popup is loaded, and these characteristics are
     * known.  This routine is called even if the load fails (e.g. 404, 500),
     * in which case it does nothing much but make the popup visible.
     */
    Fix: function (sender) {
        var popup = this.FindPopup(sender);

        if (popup) {
            if (popup.fixTimeout) {
                // Clear the fixing timeout
                clearTimeout(popup.fixTimeout);
                popup.fixTimeout = null;

                this.HandleEvent(sender, "onCreate");

                var frame = window.frames[sender];
                var container = document.getElementById("popupContainer");
                var titleHeight = 0;

                if (popup.params.title) {
                    popup.title.innerHTML = popup.params.title;
                    this._CreateCloseButton(popup.title, popup.params.isDialog);
                }
                if (!popup.params.secure) {
                    headers = frame.document.getElementsByTagName("H1");
                    if (headers.length > 0 && headers[0].className == "popupTitle") {
                        popup.title.innerHTML = headers[0].innerHTML;
                        this._CreateCloseButton(popup.title, popup.params.isDialog);
                        headers[0].style.display = "none";
                    }
                }

                titleHeight = popup.title.offsetHeight;

                if (!popup.params.width && !popup.params.height && !popup.params.secure && frame.document.body &&
                    frame.document.body.style.width && 
                    frame.document.body.style.height) 
                {
                    var w = frame.document.body.style.width;
                    var h = frame.document.body.style.height;
                    this.ResizePopup(
                        popup,
                        parseInt(PopupWindowUtils.ConvertToPixels(w, container)),
                        parseInt(PopupWindowUtils.ConvertToPixels(h, container)),
                        titleHeight
                    )
                }
                if (popup.params.callout){
                    PopupWindow.FixCallOut(popup)
                }
            }

            if (!popup.params.noBarrier) {
                var barrier = document.getElementById("popupBarrier");
                barrier.style.cursor = "default";
                popup.iframe.style.visibility = "visible";
                popup.div.style.visibility = "visible";
                popup.div.style.cursor = "default";
            }
            this.ReadjustBarrier();
        }
    },

    /*
     * ReadjustBarrier(): Fix the barrier size after a popup messes
     * with the screen dimensions.
     */
    ReadjustBarrier: function () {
        var barrier = document.getElementById("popupBarrier");
        var screenSize = PopupWindowUtils.ScreenSize();
        var vpSize = PopupWindowUtils.ViewPortSize();
        var sbW = 0;
        var sbH = 0;
        if (vpSize.h > screenSize.h) {
            sbW = PopupWindowUtils.ScrollBarSize();
        }
        if (vpSize.w > screenSize.w) {
            sbH = PopupWindowUtils.ScrollBarSize();
        }
        
        // console.log("Readjusting barrier to " + (vpSize.w - sbW) + "pixels wide");
        // console.log("I think my viewport is " + vpSize.w + " pixels wide");
        // console.log("I think my scrollbar width is " + sbW);

        // FIXME: vpSize includes the scrollbar size, so we
        // need to fix this somehow.
        if (barrier.offsetWidth != 0 && barrier.offsetHeight != 0) {
            barrier.style.width = (vpSize.w - sbW) + "px";
            barrier.style.height = (vpSize.h - sbH) + "px";
        }

        barrier = document.getElementById("dialogBarrier");
        if (barrier.offsetWidth != 0 && barrier.offsetHeight != 0) {
            barrier.style.width = (vpSize.w - sbW) + "px";
            barrier.style.height = (vpSize.h - sbH) + "px";
        }
    },

    /*
     * ReloadPopups(): Reload any available popups from the URL hash.
     */
    ReloadPopups: function() {
        if (this._reloading) {
            return;
        } else {
            this._reloading = true;
            var hash = window.location.hash;
            if (hash.charAt(0) == "#") { hash = hash.slice(1); }
            var params = hash.split("&");
            var unusedParams = "";
            var popups = [];
            for (var i=0; i<params.length; ++i) {
                var m = params[i].match(/popups=(.+)/);
                if (m) {
                    popups.push(m[1]);
                } else {
                    if (unusedParams != "") unusedParams += "&";
                    unusedParams += params[i];
                }
            }
            // Don't change the hash here, otherwise we get problems!
            for (var i=0; i<popups.length; ++i) {
                var popupNames = popups[i].split(",");
                for (var j=0; j<popupNames.length; ++j) {
                    // FIXME: We should wait until the Fix() call of each popup
                    // to register the next one.
                    var dynamicParams = {};
                    if (unusedParams) {
                       dynamicParams = PopupWindow.StringAsDict(unusedParams); 
                    }
                    PopupWindow.CreateRegistered(popupNames[j],
                                                true,
                                                dynamicParams);
                }
            }
            this._reloading = false;
        }
    },
    
    /*
     * StringAsDict(aString)  
     */
    StringAsDict: function(aString) {
        var stringList = aString.split("&");
        var newDict = {};
        for (var index=0; index < stringList.length; index ++) {
            keyValue = stringList[index].split("=");
            newDict[keyValue[0]]=keyValue[1];
        }
        return newDict;
    },

    /* 
     * These are "private" methods, don't use them unless you know what
     * you are doing! 
     */

    /*
     * _CreateCloseButton(): Creates a close button for the "title bar" of
     * the popup.
     */
    _CreateCloseButton: function (titleDiv, isDialog) {
        var link = document.createElement("A");
        link.href = "javascript:void(PopupWindow.Close())";
        link.className = "popupWindowClose";
        var closeButton = document.createElement("IMG");
        if (isDialog) {
            closeButton.src = "/static/images/close-dialogs.gif";
            if (IsIE()) {
                closeButton.width = 13;
                closeButton.height = 13;
            }
        } else {
            closeButton.src = "/static/images/closePop.gif";
            if (IsIE()) {
                closeButton.width = 59;
                closeButton.height = 10;
            }
        }
        closeButton.alt = "Close";
        closeButton.title = "Close";
        link.appendChild(closeButton);
        titleDiv.appendChild(link);
    },

    /* 
     * _LoadPopup(): Loads a document into a popup window, also sets the
     * interior document parameters.  "popup" is the popup, "url" is the
     * url of the content to load.
     */
    _LoadPopup: function (popup, url) {
        popup.iframe.src = url;
        var frame = window.frames[popup.iframe.name];
        /* 
         * This doesn't actually work in Safari, it must get reset 
         * somewhere.
         */
        if (!popup.params.secure) {
            frame.popupFrameName = popup.iframe.name;
            frame.popupInfo = popup;
        }
    },

    _SetPopupContent: function (popup, staticText) {
        window.frames[popup.iframe.name].document.write(staticText);
        window.frames[popup.iframe.name].document.close();
        this.Fix(popup.iframe.name);
    },

    /*
     * _FindMatchingPopupInfo(): Given a document object, this method
     * tries to find the popup info that matches it.  If it finds it,
     * it returns it.  This is mainly for the use of Safari, since
     * our "push" into the IFRAME in _LoadPopup(), above, doesn't 
     * work.
     */
    _FindMatchingPopupInfo: function (doc) {
        for (var i=0; i<this._openPopups.length; ++i) {
            var popup = this._openPopups[i];
            var frameDoc = window.frames[popup.iframe.name].document;
            if (frameDoc == doc) {
                return popup;
            }
        }
        return null;
    },

    /*
     * _GetPopupUrl(): Determine the (partial) url of the "popups=" portion
     * of the hashed URL based on the current popup stack.
     */
    _GetPopupUrl: function () {
        var result = "";
        for (var i=0; i<this._openPopups.length; ++i) {
            var popup = this._openPopups[i];
            if (popup.registeredName) {
                if (result != "") result += ",";
                result += popup.registeredName;
            }
        }
        return (result == "") ? result : "popups="+result
    },

    /* 
     * _CleanPopupUrl(): Return the hashed URL with any popup portions
     * stripped out.
     */
    _CleanPopupUrl: function() {
        var hash = window.location.hash;
        if (hash.charAt(0) == "#") { hash = hash.slice(1); }
        var params = hash.split("&");
        var unusedParams = "";
        for (var i=0; i<params.length; ++i) {
            var m = params[i].match(/popups=(.+)/);;
            if (!m) {
                if (unusedParams != "") unusedParams += "&";
                unusedParams += params[i];
            }
        }
        return unusedParams;
    },

    /*
     * _ResetHash(): Given a hashed URL, reset it to canonical form - that
     * is, with any non-popups in the front, and the popups consolidated
     * at the end in a popups= "parameter".
     */
    _ResetHash: function(args) {
        var cleanedUrl = this._CleanPopupUrl();
        var popupUrl = this._GetPopupUrl();
        var newHash = ""
        if (cleanedUrl == "" && popupUrl == "") {
            newHash = "";
        } else if (cleanedUrl == "") {
            newHash = popupUrl;
        } else if (popupUrl == "") {
            newHash = cleanedUrl;
        } else {
            newHash = cleanedUrl + "&" + popupUrl;
        }


        if (args) {
            var argString= "";
            for (key in args) {
                var val =  args[key]
                argString += "&" + key + "=" + val;
            }
            newHash += argString;
        }

        if (window.location.hash != "" || newHash != "") {
            window.location.hash = "#" + newHash;
        }
    }
};

Events.RegisterEvent(window, "load", PopupWindow.ReloadPopups);
Events.RegisterEvent(window, "resize", PopupWindow.ReCenterPopups);

/*
 * ================================================================
 * Old popupwindows, for compatibility
 * TODO: Convert everything and remove
 * ================================================================
 */

function showPopupWindow(url, method, data, title, left, top, width, height) {

    var popupWindow = getPopupWindow();

    var windowStyle = popupWindow.style;
    var background = document.getElementById("blockUI");

    windowStyle.display="block";
    background.style.display="block";

/*
    if (title) {
        document.getElementById("popupwindowtitle").innerHTML = unescape(title);
    }
*/

    if (left) {
        windowStyle.left=left;   
    }

    if (top) {
        windowStyle.top = top;
    }

    if (width) {
        windowStyle.width=width;
    }
    if (height) {
        windowStyle.height=height;
    }

    loadWindowContents(url, method, data);

    setPageUrl(url, data, title, left, top, width, height);
 
}

function loadWindowContents (url, method, data) {

    var windowContent = getPopupWindowContent()
 
    windowContent.contentWindow.document.body.innerHTML="<html><body><center>Loading...</center></body></html>";       
    if (data) {
        windowContent.src = url + "?" + data;
    } else {
        windowContent.src = url
    }

}


function getPopupWindow() {

    return document.getElementById("popupwindow");
}

function getPopupWindowContent() {

    return document.getElementById("windowcontent");
}

function getPopupWindowDoc () {

    return getPopupWindowContent().contentDocument;
}

function getPopupWindowElement(elementId) {
    return getPopupWindowDoc().getElementById(elementId);
}

function getPopupWindowSrc() {
    return getPopupWindowContent().src
}

function setPageUrl(popupUrl, popupData, pageTitle, top, left, width, height) {   

    var callHash;
    var windowHash= "#window=";
    var newUrl;
    var baseUrl;
    var index;
    var href = document.location.href
    if (popupData) {
        callHash = (popupUrl.substring (0, popupUrl.length)) + "?" + popupData ;
    } else {
        callHash = popupUrl.substring (0, popupUrl.length);
    }

    index = href.indexOf('#');


    if (index > -1) {
        baseUrl = href.substring (0, index);
    } else {
        baseUrl = href;
    }

/*
    if (pageTitle)  {
        windowHash += pageTitle; 
    }
*/
    windowHash += ',';
    if (left) {
        windowHash += left;
    }

    windowHash += ',';
    if (top) {
        windowHash += top;
    }
    windowHash += ',';
    if (width) {
        windowHash += width;
    }
    windowHash += ',';
    if (height) {
        windowHash += height;
    }

    var newHref = baseUrl+ "#popup=" + callHash;
    if (windowHash) {
        newHref += windowHash;
    }
    document.location.href = newHref;

    return false;
}

function resetPageUrl() {

    var href = document.location.href;
    var index = href.indexOf('#');

    if (index > -1) {
        document.location.href= href.substring(0,index+1);
    }

}

function showSearch()  {

    var searchArea=document.searchform.searchArea.value;
    var searchTerms=document.searchform.searchTerms.value;

    var searchString = "searchTerms=" + searchTerms + "&searchArea= " + searchArea;

    return showPopupWindow("/search", "POST", searchString, "Search");
    
}

function showSectionSearch()  {


    var searchTerms=document.getElementById("searchTerms").value;
    var searchArea=document.getElementById("searchArea").value;

    var searchString = "searchTerms=" + searchTerms + "&searchArea= " + searchArea;

    return showPopupWindow("/search", "POST", searchString, "Search");

}

function closePopupWindow(){

    document.getElementById("popupwindow").style.display="none";
    document.getElementById("blockUI").style.display="none";

    resetPageUrl();
    if (window.popupCloseCallback) {
        popupCloseCallback()
    }
}

function bookmarkMe() {
    var url = 'http://localhost:8080/search?searchTerms="test"&searchArea="test"'
    var text = 'Workbook Search'
    if (window.sidebar) {
        window.sidebar.addPanel(text, url, "");
    }
    else if (window.external) {
        window.external.AddFavorite(url, text );
    }
}

function ShowDialog(url, callback) {
    if (callback) {
        // FIXME: This sucks, fix me!
        window.popupCloseCallback = function () { 
            setTimeout(callback, 0);
            window.popupCloseCallback = null;
        }
    }
    showPopupWindow(url, null, null, null, null, null, "30em", "10em");
}
