window.cmu = window.cmu || {};

(function (ns) {

    ns.foldoutPopup = function (spec, my) {
        var that = {};

        spec = spec || {};
        spec.activationScope = spec.activationScope || $('body');
        spec.activationLinks = spec.activationLinks;
        spec.pointRight = spec.pointRight || false; // Whether the popup arrow points left or right

        // ------------------------------------------------------------------
        // Shared properties
        // ------------------------------------------------------------------

        my = my || {};
        my.logger = gj.logging.getLogger('cmu.foldoutPopup');
        my.dataUrl = null;
        my.activeLink = null;

        // Set when response is received
        my.$content = null;
        my.$contentInner = null;

        // ------------------------------------------------------------------
        // Private properties
        // ------------------------------------------------------------------

        my.$viewNode = spec.viewNode;
        my.$resultContainer = my.$viewNode.children('.inner');
        my.$activationLinks = spec.activationScope.find(spec.activationLinks);

        // ------------------------------------------------------------------
        // Private methods
        // ------------------------------------------------------------------

        var init = function () {
            my.logger.debug('init()', my.$viewNode, my.$resultContainer);
            my.logger.debug('Activation links: ', my.$activationLinks);

            if (spec.pointRight) {
                my.$viewNode.addClass('pointRight');
            }
            return that;
        };

        var open = function (href) {
            my.logger.debug('open()');
            var isDifferentUrl = href !== my.dataUrl;

            if (isDifferentUrl) {
                my.$resultContainer.empty();
            }
            my.$viewNode.show();
            position();
            my.$viewNode.bind('clickoutside', close);

            // Avoid loading the same URL multiple times
            if (!isDifferentUrl) {
                my.$content && my.$content.scrollTop(0);
                return;
            }
            my.dataUrl = href;

            my.$viewNode.addClass('loading');
            getData();
        };

        var close = function () {
            my.logger.debug('close()');
            my.$viewNode.hide();
            my.$viewNode.unbind('clickoutside', close);
        };

        // Positions the popup at the correct height relative to the link
        // it was opened from
        var position = function () {
            my.logger.debug('position()');
            var linkTop = my.activeLink.offset().top;
            var linkHeight = my.activeLink.height();
            var popupHeight = my.$viewNode.height();
            var popupTop = linkTop - popupHeight / 2 + linkHeight / 2;
            my.$viewNode.css('top', popupTop);
        };

        var getData = function () {
            my.logger.debug('getData()', my.dataUrl);
            cmu.communicationController.ajax({
                url: my.dataUrl,
                type: 'GET',
                data: null,
                success: function (data, status, xhr) {
                    my.$resultContainer.html(data);
                    my.$viewNode.removeClass('loading');

                    my.$content = my.$resultContainer.find('.content');
                    my.$contentInner = my.$content.children('.inner');

                    my.$content.scrollTop(0);

                    my.$viewNode.find('.navigation.alphabet a').click(function (e) {
                        my.logger.debug(this, e.type);

                        if (cmu.browser.isSupported('scrollToAnchor')) {
                            var href = $(this).attr('href');
                            var anchorName = href.slice(1);
                            scrollToAnchor(anchorName);
                            e.preventDefault();
                        }
                    });

                    // If a callback was provided, we hijack the links and let
                    // the callback handle the link click
                    if (spec.callback) {
                        hijackLinks(my.$resultContainer, spec.callback);
                    }
                }
            });
        };

        var scrollToAnchor = function (anchorName) {
            my.logger.debug('scrollToAnchor(' + anchorName + ')');
            my.$content.animate({scrollTop: getAnchorTop(anchorName)});
        };

        var getAnchorTop = function (anchorName) {
            my.logger.debug('getAnchorTop(' + anchorName + ')');
            var anchor = my.$contentInner.find('a[name=' + anchorName + ']');
            var anchorTop = anchor.offset().top - my.$contentInner.offset().top;
            my.logger.debug({'anchorTop': anchorTop});
            return anchorTop;
        };

        var hijackLinks = function (scope, callback) {
            my.logger.debug('hijackLinks', callback);
            scope.find('ul.facetValues li a').click(function () {

                try {
                    spec.callback.apply(my.activeLink, [this]);
                } catch (e) {
                    my.logger.warning(e);
                }

                close();
                return false;
            });
        };

        // ------------------------------------------------------------------
        // Public methods
        // ------------------------------------------------------------------

        // ------------------------------------------------------------------
        // Event handlers
        // ------------------------------------------------------------------

        my.$activationLinks.click(function () {
            var $this = $(this);
            var href = $this.attr('href');
            my.activeLink = $(this);
            // my.logger.debug('click()', href);
            open(href);
            return false;
        });

        my.$viewNode.find('.closeButton').click(function () {
            close();
        });

        // ------------------------------------------------------------------
        // Constructor
        // ------------------------------------------------------------------

        return init();
    };

})(window.cmu);

