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 animate = true;			// toggles resizing animations
    var resizeSpeed = 10;		// controls the speed of the image resizing animations (1=slowest and 10=fastest)
    var resizeDuration = 0;

    if(animate == true){
        if(resizeSpeed > 10){ resizeSpeed = 10;}
        if(resizeSpeed < 1){ resizeSpeed = 1;}
        resizeDuration = (11 - resizeSpeed) * 0.15;
    } else { 
        resizeDuration = 0;
    }

    var scaleElementToPage = function(ele) {
        if (!Object.isElement(ele)) {
            return;
        }
        var docsize = $(document.body).getDimensions();
        var main_container_size = $('main_container').getDimensions();

        ele.setStyle({
            height: main_container_size.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"});
        var topDiv = new Element("div", {"class": "top full-width"});
        closeDiv.insert(closeLink);
        topDiv.insert(closeDiv);
        containerEle.insert({"top": topDiv});
        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");
        });
    };
    
    var setupCloseLinks = function() {
        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);
        }
        
        closeLinks.each( function(link) { // attach event handler to close links
            link.observe("click", function(clickEvt) {

                // references the flash behind overlay if it exists and call custom js on flash file
                if ( $('Main') ) {
                    $('Main').onActive();         
                };

                generic.overlay.hide();
            });
        });      
    };
    
    var loader = function() {
        var fgLoadingNode  = new Element('div', {"id":"overlay-loader"});
        var fgLoadingImg   = new Element('img', {"id":"ajax-loader-jm", "src":"/images/jomalone_loading_logo.gif"})
        var fgSpinnerDiv   = new Element('div', {"id":"spinner-div"});
        var fgSpinnerImg   = new Element('img', {"id":"spinner-img", "src":"/images/jm-loader.gif"})

        fgSpinnerDiv.insert(fgSpinnerImg);
        fgLoadingNode.insert(fgLoadingImg);
        fgLoadingNode.insert(fgSpinnerDiv);
        foregroundNode.insert(fgLoadingNode);
    };

    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.observe("click", function (closeBgClickEvt) {
                        closeBgClickEvt.preventDefault();
                        generic.overlay.hide();
                    });
                }
                backgroundNode.style.display = "block";
                scaleElementToPage(backgroundNode);
            }
            if (!foregroundNode) { // create foreground node, if necessary
                foregroundNode = new Element('div', {"class":"overlay-container","id":"overlay-container"});
                
                // If we have not been provided with content set a loader.
                if(!args.content) {
                    loader();
                }
                containerNode.insert(foregroundNode);
            }

            if(args.content) {
                hideSelects();
                // insert elements into DOM and adjust layout
                foregroundNode.insert(args.content);
     
                if (args.cssStyle) {
                    foregroundNode.setStyle(args.cssStyle);
                }
                setupCloseLinks();
            }
            isVisible = true; // set internal flag
             // attach events for scroll & resize
            if (!args.lockPosition) {
                Event.observe( window, 'resize', scrollHandler );
                Event.observe( window, 'scroll', scrollHandler );
            }
	    	    
            jm.page.replaceSelects();

	    	    centerElement(foregroundNode);
        },
        /**
        * This function updates the pop-over window with content provided.
        **/
        update: function(args) {
            if($('overlay-content')) {
                $('overlay-content').remove();
            }

            var content = new Element('div', {"id":"overlay-content"});  
            content.insert(args.content);
               
            $('overlay-container').insert(content);
            setupCloseLinks();   
            $('overlay-content').hide();   

            jm.page.replaceSelects();
            
        }, 
        /**
        * This functions switches from the loader image to the actual loaded content.
        **/
        showContainer: function(args) {
            $('overlay-loader').hide();
            $('overlay-content').show();

            if (args && args.cssStyle) {
                foregroundNode.setStyle(args.cssStyle);
            }

            jm.page.replaceSelects();

            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(containerDiv, transport) {
                        var response = transport.responseText || "no response text";
                        containerDiv.update(response);
                    }.curry(containerDiv),
                    onFailure: function(containerDiv){
                        var errMsg = "Error loading " + link.href
                        containerDiv.update(errMsg);
                    }.curry(containerDiv)
                });
                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();
});


