function PopupOverlay()
{
    // Shortcut to current instance of object
    var instance = this;

    // Get the window width (viewport)
    function getWinWidth()
    {
        return window.innerWidth || (document.compatMode == "CSS1Compat" && document.documentElement.clientWidth || document.body.clientWidth);
    }

    // Get the window height (viewport)
    function getWinHeight()
    {
        return window.innerHeight || (document.compatMode == "CSS1Compat" && document.documentElement.clientHeight || document.body.clientHeight);
    }

    // Get the minimum document height
    function getMinDocHeight()
    {
        return Math.min(
            Math.min(document.body["scrollHeight"], document.documentElement["scrollHeight"]),
            Math.min(document.body["offsetHeight"], document.documentElement["offsetHeight"]),
            Math.min(document.body["clientHeight"], document.documentElement["clientHeight"]));
    }

    // Get the maximum document height
    function getMaxDocHeight()
    {
        return Math.max(
            Math.max(document.body["scrollHeight"], document.documentElement["scrollHeight"]),
            Math.max(document.body["offsetHeight"], document.documentElement["offsetHeight"]),
            Math.max(document.body["clientHeight"], document.documentElement["clientHeight"]));
    }

    // Get the vertical scroll offset
    function getScrollOffset()
    {
        var ieBody = (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body;
        var offsetTop = document.all ? ieBody.scrollTop : pageYOffset;
        return offsetTop;
    }

    // Returns the IE Browser Version
    function getIeVersion()
    {
        return parseFloat(navigator.appVersion.split("MSIE")[1]);
    }
    
    // CSS helper function
    function applyStyles(el, o)
    {
        for (var i in o) { el.style[i] = o[i]; }
        return el;
    }

    // Creates and styles new iframe element
    // This is a workaround for IE6/7 select-over-div problem.
    this.frameElement = (function()
    {
        return applyStyles(document.createElement('iframe'), {
            display: 'none',
            position: 'absolute',
            width: '100%',
            height: getMaxDocHeight() + 'px',
            left: '0px',
            top: '0px',
            zIndex: 970,
            opacity: 0,
            MozOpacity: 0,
            filter: 'alpha(opacity=0)'
        });
    })();

    // Creates and styles new div element
    this.backgroundElement = (function()
    {
        return applyStyles(document.createElement('div'), {
            display: 'none',
            position: 'absolute',
            width: '100%',
            height: getMaxDocHeight() + 'px',
            left: '0px',
            top: '0px',
            zIndex: 980,
            background: 'black',
            opacity: 0.7,
            MozOpacity: 0.7,
            filter: 'alpha(opacity=70)'
        });
    })();

    // Creates and styles new div element
    this.contentElement = (function()
    {
        return applyStyles(document.createElement('div'), {
            display: 'none',
            position: 'absolute',
            zIndex: 990
        });
    })();

    // Initialize
    this.init = function(targetElement)
    {
        // Inject iframe element into DOM (IE6 fix for bug with select-elements)
        if (getIeVersion() < 8)
        {
            document.getElementsByTagName('body')[0].appendChild(instance.frameElement);
            instance.frameElement.frameBorder = 0;
        }

        // Inject background element into DOM
        document.getElementsByTagName('body')[0].appendChild(instance.backgroundElement);

        // Inject content element into DOM
        document.getElementsByTagName('body')[0].appendChild(instance.contentElement);

        // Insert the content document element
        instance.contentElement.appendChild(targetElement);

        // Center the content element
        applyStyles(instance.contentElement, {
            width: targetElement.style.width,
            height: targetElement.style.height,
            left: String((getWinWidth() - parseInt(targetElement.style.width)) / 2) + "px",
            top: String(((getWinHeight() - parseInt(targetElement.style.height)) / 2) + getScrollOffset()) + "px"
        });

        // Add remove on click event handler
        instance.backgroundElement.onclick = function() { instance.close(); };
        instance.contentElement.onclick = function() { instance.close(); };

        // Return instance, for reference
        return instance;
    };

    // Show the overlay
    this.show = function()
    {
        // Set position
        this.contentElement.style.top = String(((getWinHeight() - parseInt(this.contentElement.style.height)) / 2) + getScrollOffset()) + "px";

        // Show popup
        if (getIeVersion() < 8)
        {
            this.frameElement.style.display = 'block';
        }
        
        this.backgroundElement.style.display = 'block';
        this.contentElement.style.display = 'block';
    };

    // Hide the overlay
    this.close = function()
    {
        // Hide popup
        if (getIeVersion() < 8)
        {
            this.frameElement.style.display = 'none';
        }
            
        this.backgroundElement.style.display = 'none';
        this.contentElement.style.display = 'none';
    };
    
    // Browser resize event handler
    window.onresize = function()
    {
        // No need to do anything if body is taller than viewport
        if (getMinDocHeight() > getWinHeight()) { return; }

        // We need to hide the background before showing it again, due to scrollbar issue.
        if (getIeVersion() < 8)
        {
            applyStyles(instance.frameElement, { display: 'none' });
            setTimeout(function() { applyStyles(instance.frameElement, { height: getMaxDocHeight() + 'px', display: 'block' }); }, 10);
        }

        applyStyles(instance.backgroundElement, { display: 'none' });
        setTimeout(function() { applyStyles(instance.backgroundElement, { height: getMaxDocHeight() + 'px', display: 'block' }); }, 10);

        // Re-center the content element
        applyStyles(instance.contentElement, {
            left: String((getWinWidth() - parseInt(instance.contentElement.style.width)) / 2) + "px",
            top: String((getWinHeight() - parseInt(instance.contentElement.style.height)) / 2) + "px"
        });
    };

    // Browser key event handler
    document.onkeyup = function(event)
    {
        var keyCode = window.event ? window.event.keyCode : event.which;
        
        if (keyCode == 27)
        {
            instance.close();
        }
    };
}