Source: widgets/guide/horizontalcarousel.js

define('application/widgets/guide/horizontalcarousel', [
    'rofl/lib/utils',
    'rofl/widgets/carousel',
    'antie/widgets/carousel/keyhandlers/activatefirsthandler',
    'application/widgets/carousel/strips/culling',
    'antie/runtimecontext',
    'application/formatters/guide',
    'application/utils',
    'application/widgets/guide/nextdayasset',
    'application/widgets/guide/prevdayasset',
    'application/widgets/guide/horizontalcarouselaligner'
], function (
    Utils,
    Carousel,
    KeyHandler,
    CullingStrip,
    RuntimeContext,
    Formatter,
    AppUtils,
    NextDayAsset,
    PrevDayAsset,
    HorizontalCarouselAligner
) {
    'use strict';

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

    return Carousel.extend({

        /**
         * Initialises the button.
         *
         * @param {Object} items - Items.
         * @param {number} day - Selected day filter index.
         * @param {Date} filterData - Filter date object.
         * @param {Array} daysArray - Days array..
        */
        init: function init (items, day, filterData, daysArray) {
            init.base.call(this, '', Carousel.orientations.HORIZONTAL);
            this.addClass('carousel-row');

            this._startTimes = [];
            this._endTimes = [];
            this._hasPreviousDay = null;
            this._hasNextDay = null;
            this.setContinuousListener(true);
            this._buildCarousel(items, day, filterData, daysArray);
        },

        /**
          * Builds the carousel.
          *
          * @private
          * @param {Object} items - Items.
          * @param {number} day - Selected day filter index.
          * @param {Date} filterData - Filter date object.
          * @param {Array} daysArray - Days array.
          */
        _buildCarousel: function (items, day, filterData, daysArray) {
            var keyHandler = new KeyHandler(),
                formatter = new Formatter(),
                nextDayButton = new NextDayAsset(),
                prevDayButton = new PrevDayAsset(),
                self = this,
                filterTime = filterData.getTime() / 1000,
                aligner = new HorizontalCarouselAligner(this.getMask()),
                highestDayIndex = daysArray.length,
                itemStartTime;

            this.setWidgetStrip(CullingStrip);
            keyHandler.setAnimationOptions({
                duration: 300,
                easing: 'easeInOut',
                fps: 60,
                skipAnim: false
            });

            keyHandler.attach(this);
            this.setMaskLength(carousels.maskLength);
            aligner.setNumberOfItemsVisibleOnScreen(4);
            this.setWidgetLengths(carousels.carousels.widgetLength);
            this.setAligner(aligner);

            if (day > 0) {

                this._hasPreviousDay = true;
                if (daysArray.length && day > 0) {
                    prevDayButton.setDate(daysArray[day - 1]);
                }
                self.append(prevDayButton, carousels.carousels.widgetLength);
            }

            Utils.each(items, function (item) {
                itemStartTime = item.getStartTime();

                if ((itemStartTime >= filterTime && itemStartTime !== this._lastStartTime) || items.length === 1) {
                    this._lastStartTime = itemStartTime;
                    this._setItem(item);
                    this.append(formatter.format(item), carousels.carousels.widgetLength);
                }
            }, this);

            if (day < (highestDayIndex - 1)) {

                this._hasNextDay = true;
                if (daysArray.length && day < daysArray.length) {
                    nextDayButton.setDate(daysArray[day + 1]);
                }
                self.append(nextDayButton, carousels.carousels.widgetLength);
            }
        },

        /**
          * Sets carousel item.
          *
          * @private
          * @param {Object} item - Items.
          */
        _setItem: function (item) {
            var start = item.getStartTime() * 1000,
                end = item.getEndTime() * 1000,
                now = application.getDate().getTime(),
                index = this._index || 1,
                channelId = this._channelId || null;

            if (channelId === null) {
                this._channelId = item.getChannelId();
            }

            if (start <= now && now <= end) {
                this._nowIndex = index;
            }

            this._startTimes.push(start);
            this._endTimes.push(end);

            this._lastIndex = index;
            this._index = index + 1;
        },

        /**
         * Executes a manual align to index.
         *
         * @param {number} index - The index.
         * @param {Object} opts - Options.
         */
        manualAlignToIndex: function (index, opts) {
            var widgetCount = this.getChildWidgetCount(),
                threshold = 3, // 4 items fit on screen, so stop scrolling when the max is already on screen.
                maxManualIndex = widgetCount - threshold - 1; // Remove one because of index zero based.

            if (index > maxManualIndex) {
                index = maxManualIndex;
            }

            if (index < 0) {
                index = 0;
            }

            this.alignToIndex(index, opts);
        },

        /**
         * Aligns the carousel to a specific index.
         *
         * @param {number} index - The index.
         * @param {Object} [options] - The alignment options.
         */
        alignToIndex: function alignToIndex (index, options) {
            this.activated = true;

            if (this._delayedIndex) {
                index = this._delayedIndex;
            } else if (this._delayedTime) {
                index = this._getIndex(this._delayedTime);

                if (this._delayedPosition) {
                    index = index - this._delayedPosition;
                }
            }

            this._delayedTime = null;
            this._delayedIndex = null;
            this._delayedPosition = null;

            if (index < 0) {
                index = 0;
            }

            if (this.outputElement &&
                (!this.outputElement.parentElement || !this.outputElement.parentElement.parentElement)) {
                options = options || {};
                options.skipAnim = true;
            }

            alignToIndex.base.call(this, index, options);
        },

        /**
         * Aligns the carousel to a specific time of day.
         *
         * @param {string|number} time - The time.
         * @param {Object} [options] - The alignment options.
         * @param {number} [position] - The carousel position.
         */
        alignToTimeOfDay: function (time, options, position) {
            var index;

            position = position || 0;

            if (this.outputElement) {
                index = this._getIndex(time);

                this._delayedTime = null;
                this._delayedIndex = null;
                this.alignToIndex(index - position, options);
            } else {
                this._delayedIndex = null;
                this._delayedTime = time;
                this._delayedPosition = position;
            }
        },

        /**
         * Aligns the carousel to a position.
         *
         * @param {number} position - Position 0 for the start, 1 for the end.
         * @param {Object} [options] - The alignment options.
         */
        alignToPosition: function (position, options) {
            var index;

            if (position === 0) {
                index = 0;
            } else {
                index = this.getChildWidgetCount() - 1;
            }

            this._delayedTime = null;
            this._delayedIndex = index;

            if (this.outputElement) {
                this._delayedIndex = null;
                this.alignToIndex(index, options);
            }
        },

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

        /**
         * Returns the item index for the given time.
         *
         * @param {string|number} time - The time.
         * @returns {number} - The index.
         * @private
         */
        _getIndex: function (time) {
            var index;

            if (time === '_nowIndex') {
                index = this._nowIndex;
            } else {

                index = this._getEndIndex(time);

                if (index <= 0) {
                    index = 1;
                }
            }

            return index || 0;
        },

        /**
         * Returns the start index.
         *
         * @param {number} time - The time.
         * @returns {number} - The current time index.
         * @private
         */
        _getStartIndex: function (time) {
            var startTimes = this._startTimes,
                filtered,
                index;

            filtered = Utils.filter(startTimes, function (current) {

                return current >= time;
            });

            if (filtered.length) {
                index = startTimes.indexOf(filtered[0]);

                if (this._hasPreviousDay) {
                    index = index + 1;
                }
            } else {
                index = this.getChildWidgetCount() - 1;

                if (this._hasNextDay) {
                    index = index - 1;
                }
            }

            return index;
        },

        /**
         * Returns the end index.
         *
         * @param {number} time - The time.
         * @returns {number} - The current time index.
         * @private
         */
        _getEndIndex: function (time) {
            var endTimes = this._endTimes,
                filtered,
                index;

            filtered = Utils.filter(endTimes, function (current) {

                return current > time;
            });

            if (filtered.length) {
                index = endTimes.indexOf(filtered[0]);

                if (this._hasPreviousDay) {
                    index = index + 1;
                }
            } else {
                index = this.getChildWidgetCount() - 1;

                if (this._hasNextDay) {
                    index = index - 1;
                }
            }

            return index;
        },

        /**
         * Activates the last item in the row.
         *
         * @param {Object} animOptions - The animation options.
         */
        activateLast: function (animOptions) {
            var last = this.getChildWidgetCount() - 1;

            if (this._hasNextDay) {
                last = last - 1;
            }

            if (this.outputElement) {
                this.alignToIndex(last, animOptions);
                this.setActiveIndex(last);
            } else {
                this._delayedIndex = last;
            }
        },

        /**
         * Returns the index from left.
         *
         * @returns {number} - The left index.
         */
        getFromLeftIndex: function () {
            var widgetStrip = this.getMask().getWidgetStrip(),
                activeIndex = this.getActiveIndex(),
                positionFromLeft = widgetStrip.getLengthToIndex(activeIndex),
                widgetSize = widgetStrip.lengthOfWidgetAtIndex(activeIndex),
                index;

            index = positionFromLeft / widgetSize;

            return index;
        }
    });
});