Source: widgets/guide/verticalcarousel.js

define('application/widgets/guide/verticalcarousel', [
    'rofl/widgets/carousel',
    'antie/widgets/carousel/keyhandlers/activatefirsthandler',
    'antie/widgets/carousel/strips/cullingstrip',
    'application/widgets/guide/verticalcarouselaligner',
    'antie/runtimecontext',
    'rofl/lib/utils'
], function (
    Carousel,
    KeyHandler,
    CullingStrip,
    Aligner,
    RuntimeContext,
    Utils
) {
    'use strict';

    var application = RuntimeContext.getCurrentApplication(),
        carouselsDimensions = application.getLayout().guide,
        VerticalCarousel;

    VerticalCarousel = Carousel.extend({

        /**
         * Initialises the vertical carousel.
         */
        init: function init () {
            init.base.call(this, '', Carousel.orientations.VERTICAL);
            this._setSettings();

            this._onFocusBound = Utils.bind(this._onFocus, this);
            this._onSelectedItemChangeBound = Utils.bind(this._onSelectedItemChange, this);
            this._onBlurBound = Utils.bind(this._onBlur, this);

            this._lastAbsoluteIndex = 0;

            this._setEventListeners();
        },

        /**
         * Sets the carousel settings.
         *
         * @private
         */
        _setSettings: function () {
            var keyHandler = new KeyHandler(),
                aligner = new Aligner(this.getMask());

            this.setContinuousListener(true);
            this.setWidgetStrip(CullingStrip);
            this.setMaskLength(carouselsDimensions.maskHeight);
            this.addClass('big-carousel');

            keyHandler.setAnimationOptions({
                duration: 200,
                fps: 30,
                easing: 'easeInOut',
                skipAnim: true
            });
            keyHandler.attach(this);

            aligner.setNumberOfItemsVisibleOnScreen(1.5);
            this.setWidgetLengths(carouselsDimensions.carousels.widgetLength);
            this.setAligner(aligner);
        },

        /**
         * Get the aligner used by the Carousel.
         *
         * @returns {Aligner} Aligner - The aligner to use.
         */
        getAligner: function () {
          return this._aligner;
        },

        /**
         * Sets the event listeners.
         *
         * @private
         */
        _setEventListeners: function () {
            this.addEventListener('focus', this._onFocusBound);
            this.addEventListener('selecteditemchange', this._onSelectedItemChangeBound);
            this.addEventListener('blur', this._onBlurBound);
        },

        /**
         * Blur event.
         *
         * @param {Object} e - The event data.
         * @private
         */
        _onBlur: function (e) {

            // Target is a carousel inside the vertical carousel.
            if (e.target.parentWidget.parentWidget.parentWidget === this) {
                this._saveLastTarget(e.target);
            }
        },

        /**
         * Focus event.
         *
         * @param {Object} e - The event data.
         * @private
         */
        _onFocus: function (e) {

            // Target is a carousel inside the vertical carousel.
            if (e.target.parentWidget.parentWidget.parentWidget === this) {
                this._setAbsoluteTarget(e.target);
            }
        },

        /**
         * Selected Item Change event.
         *
         * @param {Object} e - The event data.
         * @private
         */
        _onSelectedItemChange: function (e) {

            // Target is the vertical carousel.
            if (e.target.parentWidget.parentWidget === this) {
                this._activateWidget(e.index);
                this._activateWidget(e.index - 1);
                this._activateWidget(e.index - 2);
                this._activateWidget(e.index + 1);
                this._activateWidget(e.index + 2);
                this._activateWidget(e.index + 3);
            }
        },

        /**
         * Activates the widget.
         *
         * @param {number} index - The index.
         * @private
         */
        _activateWidget: function (index) {
            var carousel = this.getChildWidgetByIndex(index);

            if (carousel && !carousel.activated && carousel.outputElement) {
                carousel.alignToIndex(carousel.getActiveIndex() || 0);
                carousel.activated = true;
            }
        },

        /**
         * Saves the last absolute target.
         *
         * @param {Object} carousel - The carousel to retrieve the last target from.
         * @private
         */
        _saveLastTarget: function (carousel) {
            var widgetStrip = carousel.getMask().getWidgetStrip(),
                attachedIndexes = widgetStrip.getAttachedIndexes(),
                visibleIndexes,
                lastActiveIndex,
                lastAbsoluteIndex;

            if (attachedIndexes) {
                visibleIndexes = attachedIndexes.slice(0, 4);
                lastActiveIndex = carousel.getActiveIndex();
                lastAbsoluteIndex = visibleIndexes.indexOf(lastActiveIndex);
            } else {
                lastAbsoluteIndex = 0;
            }

            this._lastAbsoluteIndex = lastAbsoluteIndex;
        },

        /**
         * Sets the absolute target for the given carousel.
         *
         * @param {Object} carousel - The carousel to set the target for.
         * @private
         */
        _setAbsoluteTarget: function (carousel) {
            var widgetStrip = carousel.getMask().getWidgetStrip(),
                attachedIndexes = widgetStrip.getAttachedIndexes(),
                itemToActivate;

            if (attachedIndexes) {

                if (carousel.getCarousel().getChildWidgetCount() <= this._lastAbsoluteIndex) {
                    this._lastAbsoluteIndex = carousel.getCarousel().getChildWidgetCount() - 1;
                }

                itemToActivate = attachedIndexes[this._lastAbsoluteIndex];

                carousel.getCarousel().setActiveChildIndex(itemToActivate);
            }
        },

        /**
         * Resets the vertical carousel.
         */
        reset: function () {
            this.removeChildWidgets();
            this._lastAbsoluteIndex = 0;
            this._mask._lastAlignIndex = null;
            this._aligner._lastAlignIndex = null;
        },

        /**
         * Returns active asset in carousel.
         *
         * @returns {Object} Active widget.
         */
        getCarouselActiveAsset: function () {
            return this.getMask().getWidgetStrip().getActiveChildWidget();
        },

        /**
         * Removes the child widgets.
         */
        removeChildWidgets: function removeChildWidgets () {
            Utils.each(this.getChildWidgets(), function (widget) {

                if (typeof widget.dispose === 'function') {
                    widget.dispose();
                } else {
                    widget.removeChildWidgets();
                }

                widget = null;
            });

            removeChildWidgets.base.call(this);
        },

        /**
         *
         *
         * @returns {Object} - The channels carousels.
         */
        getContentCarousels: function () {
            var strip = this.getMask().getWidgetStrip(),
                carousels = Utils.filter(strip.getChildWidgets(), function (carousel) {

                    // Only rendered carousels.
                    return carousel.isRendered();
                });

            return carousels;
        },

        /**
         * Gets the Grid carousel's items.
         *
         * @returns {Array} - The Grid Carousel's items.
         */
        getCarouselItems: function () {
            var carousels = this.getContentCarousels(),
                items = [],
                carouselsAssets = [],
                carouselsEpgIndex = 3,
                carouselsEpgMask,
                carouselsEpgStrip;

            // Retrieve the actual carousels and the assets.
            Utils.each(carousels, function (carousel) {
                carouselsEpgMask = carousel.getChildWidgetByIndex(carouselsEpgIndex).getMask();
                carouselsEpgStrip = carouselsEpgMask.getWidgetStrip();

                carouselsAssets = carouselsAssets.concat(carouselsEpgStrip.getChildWidgets());
            });

            items = Utils.filter(carouselsAssets, function (item) {

                // Exclude next/previous days buttons.
                return item.hasClass('asset');
            });

            return items;
        }
    });

    VerticalCarousel.orientations = Carousel.orientations;

    return VerticalCarousel;
});