var generic = generic || {};

/**
 * @class brx.overlay This singleton class offers pop-over display functionality.
 * It supports one visible window at a time.
 */
generic.overlay = function() {
    var isVisible = false;
    var backgroundNode = null;
    var foregroundNode = null;
    var containerNode = null;

    var scaleElementToPage = function(ele) {
        if (!Object.isElement(ele)) {
            return;
        }
        var docsize = $(document.body).getDimensions();
        ele.setStyle({
            height: docsize.height+'px',
            width: docsize.width+'px'
        });        
    };

    var centerElement = function(ele) {
        if (!Object.isElement(ele)) {
            return;
        }        
        var contentDimensions = ele.getDimensions();
        var windowScrollOffsets = document.viewport.getScrollOffsets();
        var windowDimensions = document.viewport.getDimensions();
        var yPosition;
        if (windowDimensions.height < contentDimensions.height) {
            yPosition = 0;
        } else {
            yPosition = (windowDimensions.height/2) - (contentDimensions.height/2) + (windowScrollOffsets.top);
        }
        ele.style.top = yPosition + "px";
        var xPosition = (windowDimensions.width/2) - (contentDimensions.width/2) + (windowScrollOffsets.left);
        ele.style.left = xPosition + "px";
    };

    var scrollHandler = function(evt) {
        centerElement(foregroundNode);
    };
    var insertCloseLink = function(containerEle) {
        var closeLink = new Element("a", {"class": "close-link"});
        closeLink.insert(generic.rb.language.rb_close);
        var closeDiv = new Element("div", {"class": "close-container"});
        closeDiv.insert(closeLink);
        containerEle.insert({"top": closeDiv});
        closeLink.observe("click", function (closeClickEvt) {
            closeClickEvt.preventDefault();
            generic.overlay.hide();
        });
        return closeLink;
    };
    var hideSelects = function () {
        var selectNodes = $$("select");
        selectNodes.each( function(node) {
            node.addClassName("overlay-hidden");
        });
    };
    var restoreSelects = function() {
        var selectNodes = $$("select.overlay-hidden");
        selectNodes.each( function(node) {
            node.removeClassName("overlay-hidden");
        });
    };

    return {
        /**
         * This function displays a pop-over window. If a pop-over is already showing, the launch()
         * function will replace it with the new one.
         * @example 
         * // generic.overlay.launch({
         * //     content: htmlNode,
         * //     cssStyle: {
         * //         border: #000000 1px solid,
         * //         backgroundColor: #ffffff,
         * //         left: "100px",
         * //         top: "350px",
         * //         width: "250px",
         * //         height: "350px"
         * //     },
         * //     lockPosition: true,
         * //     includeBackground: false
         * // });
         * @param {Object} args.cssStyle Hash of CSS style definitions for the window. Uses JS notation (i.e., "marginLeft").
         * @param {string|Node} args.content HTML, node, or text that will display in the window.
         * @param {boolean} lockPosition if true, the overlay layer will remain anchored at the same x,y coords
         * when the user scrolls or resizes.
         * @param {boolean} includeBackground if true, a background Node will cover the page directly behind the
         * overlay contents.
         */
        launch : function(args) {
            if (isVisible) { // check internal flag
                this.hide();
                // return null;
            }
            if (!containerNode) { // can't retrieve body variable in function declaration b/c it hasn't finished loading
                containerNode = $(document.body);
            }
            if (args.includeBackground) {
                if (!backgroundNode) { // create background node, if necessary
                    backgroundNode = new Element('div', {"class":"overlay-background", style:"display:none"});
                    containerNode.insert(backgroundNode);
                }
                backgroundNode.style.display = "block";
                scaleElementToPage(backgroundNode);
            }
            if (!foregroundNode) { // create foreground node, if necessary
                foregroundNode = new Element('div', {"class":"overlay-container", style:"display:none"});
                containerNode.insert(foregroundNode);
            }
            hideSelects();
            // insert elements into DOM and adjust layout
            foregroundNode.insert(args.content);
            foregroundNode.style.display = "block";
            if (args.cssStyle) {
                foregroundNode.setStyle(args.cssStyle);
            }
            var closeLinks = foregroundNode.select(".close-link"); // look for a close link
            if (closeLinks.length < 1) {
                var newCloseLink = insertCloseLink(foregroundNode); // Insert link if one is not found
                closeLinks.push(newCloseLink);
            }
            var self = this;
            closeLinks.each( function(link) { // attach event handler to close links
                link.observe("click", function(clickEvt) {
                    self.hide();
                });
            });
            isVisible = true; // set internal flag
             // attach events for scroll & resize
            if (!args.lockPosition) {
                Event.observe( window, 'resize', scrollHandler );
                Event.observe( window, 'scroll', scrollHandler );
            }
	    	centerElement(foregroundNode);
        },
        /**
         * This function "closes" the pop-over window. It completely removes
         * the foreground node and its children from the DOM. The background
         * element is set to display: none.
         */
        hide: function() {
            isVisible = false; // set internal flag
             // remove events for scroll & resize
            Event.stopObserving( window, 'resize', scrollHandler );
            Event.stopObserving( window, 'scroll', scrollHandler );
            restoreSelects();
            // clean up DOM and layout
            if (Object.isElement(foregroundNode)) {
                foregroundNode.remove();
                foregroundNode = null;
            }
            if (Object.isElement(backgroundNode)) {
                backgroundNode.style.display="none";
            }
        },
        /**
         * This function scans the DOM for <a class="overlay-links"> elements. It takes the href attribute
         * from those links and preloads that URL via AJAX into a hidden DIV. This div is used
         * as the content for an overlay window when the link is clicked.
         */
        initLinks: function() {
            var linksToModify = $$("a.overlay-link");
            linksToModify.each( function(link) {
                if (link.hasClassName("overlay-ready")) {
                    return;
                }
                var styleObj = {};
                var widthRegexResults = link.className.match(/overlay-width-(\d+)/);
                if (widthRegexResults) {
                    styleObj.width = widthRegexResults[1] + "px";
                }
                var heightRegexResults = link.className.match(/overlay-height-(\d+)/);
                if (heightRegexResults) {
                    styleObj.height = heightRegexResults[1] + "px";
                }
                var containerDiv = new Element("div");
                containerDiv.style.display = "none";
                document.body.appendChild(containerDiv);
                var req = new Ajax.Request(link.href, {
                    method:'get',
                    onSuccess: function(transport) {
                        var response = transport.responseText || "no response text";
                        containerDiv.update(response);
                    },
                    onFailure: function(){
                        var errMsg = "Error loading " + link.href
                        containerDiv.update(errMsg);
                    }
                });
                link.observe("click", function(clickEvt) {
                    clickEvt.preventDefault();
                    containerDiv.style.display = "block";
                    generic.overlay.launch({
                        content: containerDiv,
                        includeBackground: true,
                        cssStyle: styleObj
                    });
                });
                link.addClassName("overlay-ready");
            }); // end linksToModify.each()
            
        },
        /**
         * This function is used to fetch specific rb keys needed for the
         * overlay. It is called on dom::loaded so each key is only 
         * fetched once.  
         * The specific language bundle is needed to be included in each page 
         * template header.  If not, the key name called will be returned.
        */
        getRBKeys: function() {
    	    generic.rb.language = generic.rb("language");
            generic.rb.language.rb_close = generic.rb.language.get('close');
        }
    };
}();


document.observe('dom:loaded', function (evt) {
    generic.overlay.getRBKeys();
    generic.overlay.initLinks();
});

