/**
 * Glossary Popups for sodbrennen.de
 * 
 * This jQuery Plugin can be used from several bayer product pages to display glossary entries of
 * sodbrennen.de. To do that, you have to create links, wich includes the term anchor in its href.
 * After that, you apply the sodbrennenGlossary() function to all these Links.
 * 
 * Example:
 * <a href="http://www.sodbrennen.de/scripts/pges/de/fachbegriffe.html#Antazida" rel="glossary">Antra</a>
 * 
 * <script type="text/javascript" src="http://www.sodbrennen.de/html/js/jquery.sodbrennen-glossar.js"></script>
 * <script type="text/javascript"> 
 *     $("a[rel='glossary']").sodbrennenGlossary();
 * </script>
 * 
 * @copyright 2010 Brainbits GmbH
 * @author Michael van Engelshoven <mvengelshoven@brainbits.net>
 * @package glossary
 * @version 1.0
 * @date $Id$
 */
(function () {
    
    /**
     * jQuery Plugin sodbrennenGlossary()
     * 
     * Iterates through all the given elements and connects them with a new instance of the
     * sodbrennenGlossary prototype.
     * 
     * @param {object} Hash with options to overload
     * @return {object} jQuery object with all given elements
     */
    jQuery.fn.sodbrennenGlossary = function(options) {
        var glossary = new jQuery.sodbrennenGlossary(options);
        return this.each(function(){
            jQuery(this).click(function (event) {
                return !glossary.openPopup.call(glossary, this, event);
            });
        });
    };
    
    /**
     * Constructs a new glossary object
     *
     * @constructor
     * @param {object} Hash with options to overload
     * @return {object} New Instance of sodbrennenGlossary
     */
    jQuery.sodbrennenGlossary = function (options) {
        // Set options
        this.options = jQuery.extend(this.options, options);
        // Create popup
        this.popup = jQuery('<div><div></div></div>')
            .addClass(this.options.containerClass)
            .css({
                position: 'absolute',
                top: 0,
                left: 0
            })
            .find('div')
              .addClass(this.options.contentClass)
            .end();
        // Add powered by notice, if specified
        if (this.options.poweredBy) {
            jQuery("<div></div>")
              .addClass(this.options.poweredByClass)
              .html(this.options.poweredBy)
              .appendTo(this.popup);
        }
        // Create close link
        var closeOnClick = function(parent) {
            return function(event) {
                return parent.closePopup.call(parent);
            };
        }(this);
        this.closeLink = jQuery('<a href="#"></a>')
            .addClass(this.options.closeLinkClass)
            .text(this.options.closeLinkText)
            .click(closeOnClick)
            .appendTo(this.popup);
        // Add a keypress event for the escape key
        var closeOnEsc = function(parent) {
            return function(event) {
                if (event.keyCode == 27 && parent.popup.is(':visible')) {
                    return parent.closePopup.call(parent);
                }
            };
        }(this);
        jQuery('body').keydown(closeOnEsc);
        // Hide popup and insert it into the document
        this.popup.hide().appendTo('body');
    };
    
    /**
     * The sodbrennenGlossary prototype
     * 
     * @prototype
     */
    jQuery.sodbrennenGlossary.prototype = {
            
        /**
         * Options
         * 
         * @var {object} Hash with options
         */
        options: {
            containerClass:  'glossaryPopup',
            contentClass:    'content',
            closeLinkClass:  'close',
            closeLinkText:   'schließen',
            poweredByClass:  'poweredBy',
            poweredBy:       '<a href="http://www.sodbrennen.de">powered by <img src="http://www.sodbrennen.de/html/images/upload/glossaryPopupLogo.gif" alt="sodbrennen.de"/></a>',
            sourceDocument:  'http://www.sodbrennen.de/scripts/pages/de/fachbegriffe/',
            animationSpeed:  350,
            loadingContent:  '<div class="loading">Lade Daten von sodbrennen.de</div>',
            termClass:       'glossaryTerm'
        },
        
        /**
         * The currently shown Link
         * 
         * @var {object} DOM-Element of the current link
         */
        currentLink: undefined,

        /**
         * The close link of the popup
         * 
         * @var {object} jQuery-Object with the close link
         */
        closeLink: undefined,
        
        /**
         * Open the popup
         * 
         * @return
         */
        openPopup: function (link, event) {
            if (this.currentLink != link) {
                this.currentLink = link;
                // Ensure the popup is hidden
                this.popup.hide();
                // If hash is not available, force default behavior
                if (link.hash == '') return false;
                // Get Hash and load data
                var key = link.hash.substr(1);
                this.applyData(key);
                if (this.loading) {
                    this.popup.find('.'+this.options.contentClass)
                      .html(this.options.loadingContent);
                }
                this.positionPopup();
                this.closeLink.focus();
            }
            return true;
        },
        
        /**
         * Close Popup
         * @return
         */
        closePopup: function() {
            this.popup
                .animate({
                    top:  '+=50px',
                    opacity: 0
                }, this.options.animationSpeed, function() {
                    jQuery(this).hide();
                });
            this.currentLink.focus();
            this.currentLink = undefined;
            // Prevent default behavior
            return false;
        },
        
        /**
         * Position the Popup
         * 
         * Places the popup in the middle top of the current link
         */
        positionPopup: function() {
            var linkElem = jQuery(this.currentLink);
            var offset = linkElem.offset();
            // Calculate optimal position
            var top = offset.top - this.popup.height() - 10;
            var left = offset.left + (linkElem.width() / 2) - (this.popup.width() / 2);
            // Ensure element is in documents space
            if (left >= document.width - this.popup.width() - 10) {
                left = document.width - this.popup.width() - 30;
            }
            if (left <= 10) {
                left = 30;
            }
            if (top >= document.height - this.popup.height() - 10) {
                top = document.height - this.popup.height() - 30;
            }
            if (top <= 10) {
                top = 30;
            }
            if (this.popup.is(':visible')) {
                this.popup
                    .stop()
                        .animate({
                            top:  '-=50px',
                            opacity: 1
                        }, this.options.animationSpeed);
            } else {
                // Apply position
                this.popup
                    .stop()
                    .css({
                        left: (left),
                        top:  (top + 50),
                        opacity: 0
                    })
                    .show()
                    .animate({
                        top:  '-=50px',
                        opacity: 1
                    }, this.options.animationSpeed);
            }
        },
        
        /**
         * Data
         * 
         * @var {object} Hash with loaded data
         */
        data: undefined,
        
        /**
         * Ajax is loading
         * 
         * This property is used to prevent multiple loads.
         * 
         * @param {boolean} True if Ajax is loading data
         */
        loading: false,
        
        /**
         * Load glossary data
         * 
         * Loads data from source document, defined in <options.sourceDocument>, and stores the
         * content to a local object property. After that, <applyData> is called, wich applies the
         * content to the popup.
         * 
         * @param {string} Key to look for
         */
        loadData: function(key) {
            this.loading = true;
            var callback = function (parent, key) {
                return function(data) {
                    parent.data = data;
                    for (i in parent.data) {
                        // Select glossary links in content and apply click event
                        parent.data[i].content = jQuery(parent.data[i].content)
                            .find("a[href^='http://www.sodbrennen.de/scripts/pages/de/fachbegriffe.html#']")
                                .addClass(parent.options.termClass)
                                .click(function(event) {
                                    // If hash is not available, force default behavior
                                    if (this.hash == '') return true;
                                    // Apply Data for clicked link hash
                                    parent.applyData.call(parent, this.hash.substr(1));
                                    return false;
                                })
                            .end();
                    }
                    parent.loading = false;
                    parent.applyData(key);
                };
            }(this, key);
            jQuery.ajax({
              dataType: 'jsonp',
              url: this.options.sourceDocument,
              success: callback
            });
        },
        
        /**
         * Apply Data
         * 
         * Applies content to the popup. The content is identified by the given key. Is no data
         * available, <loadData> is called, wich recalls this mehtod after the ajax request.
         * 
         * @param {string} Key to identifiy the content
         */
        applyData: function(key) {
            if (!this.loading && typeof this.data == 'undefined') {
                this.loadData(key);
            } else {
                var popupInner = this.popup.find('.'+this.options.contentClass);
                if (typeof this.data[key] != 'undefined') {
                    popupInner.html(this.data[key].content.clone(true));
                    jQuery("<h2></h2>")
                        .text(this.data[key].title)
                        .prependTo(popupInner);
                } else {
                    popupInner.html("<p>Es existiert keine Beschreibung für #"+key+".</p>");
                }
                if(this.popup.is(':visible')) {
                    this.positionPopup();
                }
            }
        }
    };
    
})();
