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

(function (ns) {

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

        spec = spec || {};
        spec.backgroundNeverEmpty = true;
        spec.raiseErrors = spec.raiseErrors || true;
        spec.animateBackgroundToggle = spec.animateBackgroundToggle !== undefined ? spec.animateBackgroundToggle : false;
        spec.foregroundSelector = spec.foregroundSelector || '#content, #footer';

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

        my = my || {};
        my.logger = gj.logging.getLogger('cmu.treasury');
        my.activeDetailUrl = null;
        my.objectGrid = cmu.objectGrid({dataCallback: function () {
            hijackDetailLinks(this.find('ul.images li a.objectDetail'));
            cmu.hijack.click('addToSet', 'a.addToSet', this);
            hijackPagers(this.find('.pager'), {addDimensions: true, callback: function () {
                var scrollTop = $(document).height();
                if (cmu.isIpad()) {
                    scrollTop = scrollTop - $(window).height() - 50;
                }
                $('html, body').animate({scrollTop: scrollTop}, {duration: 2000});
            }});
            cmu.gridInit({viewNode: this.find('ul.images')});
        }});
        my.backgroundOnly = false;
        my.initialized = false;
        my.contextualExhibitionUrl = null;
        my.listViewTitle = null;

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

        var $viewNode = spec.viewNode;

        // TODO (yvdm): consider refactoring detail view into separate class
        var views = {
            results: $viewNode.find('.resultsView'),
            detail: $viewNode.find('.detailView > .inner'),
            detailWrapper: $viewNode.find('.detailView')
        };

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

        var init = function () {
            my.logger.debug('init()', $viewNode);

            // Before we do anything else, backup the current document title
            my.listViewTitle = document.title;

            var hashApplied = applyHash(true);

            if (!hashApplied) {
                drawBackgroundState();
            }
            my.initialized = true;

            // If this is not the "non-Ajax" object detail view, hide the detail wrapper
            if (!$('body').hasClass('detailPage')) {
                views.detailWrapper.hide();
            }
            return that;
        };

        var applyHash = function (isInitial) {
            var hash = document.location.hash.slice(1);
            if (!hash && isInitial) {
                return;
            }
            var match = hash.match(/(o|e|s):(\d+)/);

            if (match) {
                var type = {
                    o: 'object',
                    e: 'exhibition',
                    s: 'set'
                }[match[1]];
                var newUrl = cmu.urls[type + 'Detail'].replace(0, match[2]);
                if (my.activeDetailUrl !== newUrl) {
                    my.activeDetailUrl = newUrl;
                    gotoDetailView();
                } else {
                    my.logger.info('Skipping, active detail URL did not change');
                }
                return true;
            } else {
                gotoListView();
            }
        };

        var gotoDetailView = function () {
            my.logger.debug('gotoDetailView(), activeObjectUrl: ', my.activeDetailUrl);

            if (!my.activeDetailUrl) {
                my.logger.warning('No URL for detail view');
                return;
            }
            var re = /\/(object|exhibition|set)\/(\d+)/;
            var match = my.activeDetailUrl.match(re);

            if (match) {
                var objectType = match[1];
                var objectId = match[2];
                document.location.hash = objectType.charAt(0) + ':' + objectId;

                if (objectType == 'exhibition' || objectType == 'set') {
                    my.contextualExhibitionUrl = my.activeDetailUrl;
                    my.logger.info('Contextual exhibition set to ', my.contextualExhibitionUrl);
                }
            }

            // Enable the foreground if necessary
            if (my.backgroundOnly) {
                my.backgroundOnly = false;
                drawBackgroundState();
            }

            views.detailWrapper.hide();
            views.results.show().addClass('loading');
            views.detail.empty();
            $('#lightbox').remove();
            loadObjectData(my.activeDetailUrl, initializeDetailView);
        };

        var gotoListView = function (setHash) {
            if (my.activeDetailUrl == null) {
                // console.warn('Already at list view');
                return;
            }
            my.logger.debug('gotoListView()');
            my.activeDetailUrl = null;
            if (setHash) {
                document.location.hash = '';
            }
            // Restore the original document title
            document.title = my.listViewTitle;

            views.detailWrapper.fadeOut();
            views.results.fadeIn();
            my.objectGrid.setContext({
                type: 'searchResults',
                url: getFirstResultUrl()
            });
        };

        var initializeDetailView = function () {
            my.logger.debug('initializeDetailView()');

            views.results.removeClass('loading');
            views.results.hide();

            views.detailWrapper[my.initialized ? 'fadeIn' : 'show']();
            my.initialized = true;

            var objectTitle = views.detail.find('.objectDetail h2').text();
            if (objectTitle) {
                document.title = objectTitle + ' | Centraal Museum Utrecht'; // TODO (yvdm): more DRY?
            }

            // Create the Twitter buttons
            $.ajax({
                url: 'http://platform.twitter.com/widgets.js',
                dataType: 'script',
                cache: true
            });

            // Create the Facebook buttons
            window.FB && window.FB.XFBML.parse(views.detail.get(0));

            $('body, html').animate({ scrollTop: 0}, 'slow');

            hijackDetailLinks(views.detail.find('.related ul.images li a'));
            hijackDetailLinks(views.detail.find('.objectExhibitions ul.itemList li a'));
            hijackDetailLinks(views.detail.find('.objectSets ul.itemList li a'));
            hijackDetailLinks(views.detail.find('.objectRelated .images a'));
            cmu.hijack.click('addToSet', 'a.addToSet', views.detail);

            views.detail.find('.objectDetail').each(function () {
                cmu.objectDetail({
                    viewNode: $(this),
                    // useBackgroundImage: true,
                    main: '.main .image'
                });
            });

            views.detail.find('.inlineLabel').each(function () {
                cmu.inlineLabel({
                    viewNode: $(this)
                });
            });

            views.detail.find('.tabBox.interactive').each(function () {
                cmu.tabBox({
                    viewNode: $(this)
                });
            });

            views.detail.find('.imageViewer').not('.disabled').each(function () {
                cmu.imageViewer({
                    viewNode: $(this),
                    main: '.main img'
                });
            });

            views.detail.find('.filmStrip').each(function () {
                cmu.filmStrip({
                    viewNode: $(this)
                });
            });

            views.detail.find('.closeButton').click(function () {
                var isExhibition = $(this).closest('.objectDetail').hasClass('exhibition');

                if (my.contextualExhibitionUrl && !isExhibition) {
                    my.activeDetailUrl = my.contextualExhibitionUrl;
                    gotoDetailView();
                } else {
                    gotoListView(true);
                }
                return false;
            });

            cmu.initPrintLinks(views.detail);

            drawObjectNavigation();

            views.detail.find('.toggleableContent p').expander({
                slicePoint: 250,
                expandText: 'lees meer',
                userCollapseText: 'lees minder'
            });

            $('#lightbox').each(function (i, elm) {
                var mainSelector = '.main .image';
                if (cmu.browser.isIE()) {
                    var imageUrl = $(elm).find('.filmStrip li a').attr('href');
                    $(elm).find(mainSelector).append($('<img/>').attr('src', imageUrl));
                    mainSelector += ' img';
                }
                window.cmu.lightbox = cmu.imageViewer({
                    viewNode: $(elm),
                    main: mainSelector
                });
            });

            my.objectGrid.setContext({
                type: 'objectDetail',
                url: my.activeDetailUrl
            });

            /*
            window.setTimeout(function () {
                gotoNextObject();
            }, 500);
            */
        };

        /**
         * Draws the (state of) the previous/next object navigation buttons
         *
         * Both the condition whether or not to show the button, as well as
         * the actual action to perform, are defined in the
         * my.objectNavigationButtons configuration.
         */
        var drawObjectNavigation = function () {
            my.logger.debug('drawObjectNavigation()');
            var scope, name, config, button;
            scope = views.detail;

            for (name in my.objectNavigationButtons) {
                config = my.objectNavigationButtons[name];
                button = scope.find('.objectNavigation .' + name);

                if (config.condition()) {
                    // Use a closure for the action to be executed on click
                    button.click((function (config) {
                        return function () {
                            config.action();
                            return false;
                        };
                    })(config));
                } else {
                    button.addClass('disabled');
                }
            }

            // Hide the entire object navigation if both previous and next buttons are disabled
            // (this means the object is not part of the search results)
            scope.find('.objectNavigation').each(function () {
                var $this = $(this);
                if ($this.find('.disabled').length === 2) {
                    $this.hide();
                }
            });
        };

        var loadObjectData = function (url, callback) {
            cmu.communicationController.ajax({
                url: url,
                type: 'GET',
                data: null,
                success: function (data, status, xhr) {
                    var dataMain = $(data).children('.main').children();
                    views.detail.html(dataMain);

                    // Remove existing lightbox (if any)
                    $('#lightbox').remove();

                    var dataLightbox = $(data).children('#lightbox');
                    if (dataLightbox) {
                        $('body').append(dataLightbox);
                    }
                    callback();
                }
            });
        };

        var hijackDetailLinks = function (elements) {
            // my.logger.debug('hijackDetailLinks()', elements);
            elements.click(function (e) {
                // my.logger.debug('click()');
                my.activeDetailUrl = $(this).attr('href');
                gotoDetailView();
                e.preventDefault();
            });
        };

        // Replaces the standard prev/next navigation with a "load more" button
        var hijackPagers = function (elements, options) {
            my.logger.debug('hijackPagers()', elements);
            options = options || {};

            if (elements.length) {
                $('#drawer').addClass('showFakePager');
            } else {
                $('#drawer').removeClass('showFakePager');
            }

            elements.each(function (i, elm) {
                var $pager = $(elm);
                $pager.addClass('loadMore');

                // Remove the previous button, since we will only keep appending new results
                $pager.find('.previous').remove();

                var $nextButton = $pager.find('.next a');
                $nextButton.text(cmu.messages.moreResults);

                $nextButton.click(function (e) {
                    loadNewPage($pager, options);
                    e.preventDefault();
                });
            });
        };

        var loadNewPage = function (pager, options) {
            my.logger.debug('loadNewPage()');
            options = options || {};

            var $pager = pager || views.results.find('.pager');
            var url = $pager.find('.next a').attr('href');

            if (!url) {
                my.logger.info('No more pages to load');
                return false;
            }
            $pager.addClass('loading');

            if (options.addDimensions) {
                url = my.objectGrid.addClientDimensions(url);
            }
            cmu.communicationController.ajax({
                url: url,
                type: 'GET',
                success: function (data, status, xhr) {
                    var $newData = $(data).children();
                    $pager.replaceWith($newData);

                    hijackPagers($newData.filter('.pager'), options);
                    hijackDetailLinks($newData.filter('.itemList').find('a'));
                    hijackDetailLinks($newData.filter('ul.images').find('li a'));
                    cmu.gridInit({viewNode: $newData.filter('ul.images')});

                    if (options.callback) {
                        options.callback.apply($newData);
                    }
                }
            });
        };

        var getGridContext = function () {
            var context;
            var backgroundUrlElm = $('.setCollection .backgroundUrl');

            if (backgroundUrlElm.length) {
                var url = backgroundUrlElm.find('a').attr('href');
                if (url) {
                    context = {
                        type: 'page',
                        url: url
                    };
                }
            } else {
                context = {
                    type: 'searchResults',
                    url: getFirstResultUrl()
                };
            }
            return context;
        };

        var getFirstResultUrl = function () {
            var firstResult = views.results.find('.itemList:not(.subhome) li').first();
            return firstResult.find('a').attr('href');
        };

        var toggleBackground = function () {
            my.logger.debug('toggleBackground()');
            my.backgroundOnly = !my.backgroundOnly;
            drawBackgroundState();
        };

        var drawBackgroundState = function () {
            my.logger.debug('drawBackgroundState()', {'backgroundOnly': my.backgroundOnly});
            $('body')[my.backgroundOnly ? 'addClass' : 'removeClass']('fullscreenMode');

            // TODO (yvdm): check if this line can be removed
            $('body')[my.backgroundOnly ? 'addClass' : 'removeClass']('backgroundOnly');

            if (!my.activeDetailUrl) {
                if (spec.backgroundNeverEmpty || my.backgroundOnly) {
                    var gridContext = getGridContext();
                    my.objectGrid.setContext(gridContext);
                } else {
                    my.objectGrid.setContext({});
                }
            }

            // Show or hide the background
            if (spec.animateBackgroundToggle) {
                $(spec.foregroundSelector)[my.backgroundOnly ? 'fadeOut' : 'fadeIn'](500);
            } else {
                $(spec.foregroundSelector)[my.backgroundOnly ? 'hide' : 'show']();
            }
        };

        var gotoPreviousObject = function () {
            my.logger.debug('gotoPreviousObject()');
            var navigated = navigateObject('prev');

            if (!navigated) {
                my.logger.info('First item reached');
            }
        };

        var gotoNextObject = function () {
            my.logger.debug('gotoNextObject()');
            var navigated = navigateObject('next');

            if (!navigated) {
                my.logger.info('Last item reached');
            }
        };

        var navigateObject = function (direction) {
            var navigatingForward = (direction == 'next');
            var newItem = getObjectInDirection(direction);

            if (!newItem.length && navigatingForward) {
                my.logger.debug('Still no new items; attempting to load new page');
                loadNewPage(null, {callback: function (data) {
                    navigateObject(direction);
                }});
            } else {
                var newUrl = newItem.find('a').attr('href');

                if (newUrl) {
                    my.activeDetailUrl = newUrl;
                    gotoDetailView();
                }
                return newUrl;
            }
        };

        var hasPreviousObject = function () {
            var objectAvailable = Boolean(getObjectInDirection('prev').length);
            return objectAvailable;
        };

        var hasNextObject = function () {
            var objectAvailable = Boolean(getObjectInDirection('next').length);
            if (!objectAvailable) {
                var isInResultSet = Boolean(getActiveListItem().length);
                var pagerAvailable = Boolean(views.results.find('.pager .next a').length);
                return isInResultSet && pagerAvailable;
            }
            return objectAvailable;
        };

        var getObjectInDirection = function (direction) {
            var navigatingForward = (direction == 'next');
            var activeItem = getActiveListItem();
            var newItem = activeItem[direction]();

            if (!newItem.length) {
                my.logger.debug('Trying the ' + direction + ' page');
                newItem = activeItem.parent('ul')[direction]('ul').children()[
                    navigatingForward ? 'first' : 'last'
                ]();
            }
            return newItem;
        };

        var getActiveListItem = function () {
            var listItems = views.results.find('.itemList li');
            return listItems.has('a[href="' + my.activeDetailUrl + '"]').first();
        };

        my.objectNavigationButtons = {
            prev: {
                condition: hasPreviousObject,
                action: gotoPreviousObject
            },
            next: {
                condition: hasNextObject,
                action: gotoNextObject
            }
        };

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

        that.toggleBackground = toggleBackground;

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

        hijackDetailLinks($viewNode.find('.facets ul.exhibitions li:not(.more) a'));
        hijackDetailLinks(views.results.find('.itemList a'));
        hijackPagers(views.results.find('.pager'));

        $(window).hashchange(function () {
            my.logger.debug('{hashchange}');
            applyHash();
        });

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

        return init();
    };

})(window.cmu);

