﻿/// <reference path="http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.1-vsdoc.js" />
/// <reference path="../jdiacono.js" />
/// <reference path="../jdiacono.web.js" />
/** Overlay which displays external content in a page
*   @author: James Diacono
*   @date: 16th of August, 2010
*   @requires: jQuery, jdiacono, jdiacono.web
*   @optional: jdiacono.web.jquery.lightBox
*   @parameters:  Config object (see below)
*   @usage: See overlay.html
*/

jdiacono.web.overlay = function (customConfig) {
    ///<summary>
    /// Overlay which displays external content in a page
    ///</summary>
    ///<param name="customConfig" type="Object">
    ///<returns type="overlay manager" />

    // The empty overlay instance
    var overlay = {};

    // Define the default behaviour:
    var config = {
        container: '#overlayContainer',
        // (jQueryable) The overlay DOM element

        content: '.content',
        // (jQueryable) The element in the container whose direct children are content or an iframe

        links: 'a.overlay',
        // (jQueryable) The anchor elements which trigger an overlay instead of navigating to their href

        spawnWindowByDefault: false,
        // (Boolean) Whether to use an iframe for the overlayed content (necessary if the
        // content contains scripts).  When false, the content is imported into the 'content'
        // element.  When true, an iframe is created inside the 'content' element which loads
        // the content.
        //
        // Equivalent to using 'rel="import"' if false, 'rel="iframe"' if true.

        importedContentSelector: '.ajax-content',
        // (jQuery selector) In an imported file (i.e. not an iframe), you can select a specific
        // DOM element to use.  See documentation on jQuery.load()

        lightBoxing: false,
        // (Boolean) Whether to implement the lightbox effect

        rememberPreviousState: true
        // (Boolean) If true, the content is not loaded everytime, only when it changes.
    };
    // Overwrite default behaviours with defined ones:
    if (typeof customConfig === 'object') {
        jQuery.extend(config, customConfig);
    }

    /* Private methods */
    var $container, $content, $links, loadedUrl;

    var loadIframe = function (url) {
        ///<summary>
        /// Load the url into an iframe in $content
        ///</summary>
        $container.addClass('loading');

        var $iframe = jQuery('<iframe frameBorder="0" />'); // frameBorder is an IE property
        $iframe.attr('src', url);
        $iframe.appendTo($content);

        // load event handler
        $iframe.load(function () {
            $container.removeClass('loading');
            loadedUrl = url;
        });
    };

    var loadHtml = function (url) {
        ///<summary>
        /// Import the url's HTML into $content
        ///</summary>
        $container.addClass('loading');
        $content.load(url + ' ' + config.importedContentSelector, function () {
            $container.removeClass('loading');
            loadedUrl = url;
        });
    };

    var open = function (url, spawnWindow) {
        ///<summary>
        /// Opens the overlay, loading whats specified by the url either through an iframe
        /// (spawnWindow is truthy) or imports it (spawnWindow is falsy)
        ///</summary>
        ///<param name="url" type="String">
        ///<param name="spawnWindow" type="Boolean">
        ///<returns type="overlay" />

        // Only load if the content is not already loaded
        // Effectively saves the state of the previously overlaid page
        if (!config.rememberPreviousState || url !== loadedUrl) {
            // Clear the content element
            $content.empty();

            var useIframe = config.spawnWindowByDefault;

            // optional override
            if (spawnWindow === true) {
                useIframe = true;
            } else if (spawnWindow === false) {
                useIframe = false;
            }

            if (useIframe) {
                loadIframe(url);
            } else {
                loadHtml(url);
            }
        }

        $container.addClass('active');
        $container.lightBox();

        return overlay;
    };

    var deactivate = function () {
        ///<summary>
        ///		Deactivates the overlay, irrespective of lightboxing
        ///</summary>
        $container.removeClass('active');
    };

    var close = function () {
        ///<summary>
        ///		Closes the lightbox, if lightboxing is used, otherwise
        ///     just deactivates the overlay.
        ///</summary>
        if (config.lightBoxing) {
            $container.unLightBox();
        } else {
            deactivate();
        }

        return overlay;
    };

    var clickHandler = function (e) {
        var $link = jQuery(e.target);

        // Stop the browser following the link
        e.preventDefault();
        var spawnWindow = config.spawnWindowByDefault;

        if ($link.attr('rel') === 'iframe') {
            spawnWindow = true;
        } else if ($link.attr('rel') === 'import') {
            spawnWindow = false;
        }

        open($link.attr('href'), spawnWindow);
    };

    var destroy = function () {
        ///<summary>
        ///		Destroys overlay state
        ///</summary>

        $content.empty();

        $links.each(function () {
            jQuery(this).unbind('click', clickHandler);
        });

        return overlay;
    };

    /* Public methods */
    overlay.close = close;
    overlay.open = open;
    overlay.destroy = destroy;
    overlay.container = jQuery(config.container).first()[0];
    overlay.content = jQuery(overlay.container).find(config.content).first()[0];

    /* Constructor */
    $container = jQuery(overlay.container);
    $content = jQuery(overlay.content);
    $links = jQuery(config.links);

    // If either the container or content elements were not found, die
    if (!$container.length || !$content.length) {
        throw "Overlay container and/or content elements were not found";
    }

    // Ensure that the overlay is deactivated when told to by the lightbox
    if (config.lightBoxing) {
        $container[0].onUnLightBox = function () {
            deactivate();
        };
    }

    // Add click listeners to the links on the page
    $links.click(clickHandler);

    return overlay;
};
