Source: components/series.js

define('application/components/series', [
    'application/components/uibuilder',
    'application/managers/api',
    'antie/runtimecontext',
    'rofl/widgets/label',
    'rofl/lib/l10n',
    'rofl/widgets/container',
    'antie/widgets/verticallist',
    'rofl/lib/utils',
    'application/managers/genre',
    'application/models/uibuilder/filteredResult',
    'application/widgets/movies/grid',
    'rofl/analytics/web/google',
    'rofl/lib/promise',
    'application/widgets/infoblock',
    'rofl/events/keyevent',
    'antie/storageprovider',
    'application/widgets/uibuilder/filter'
], function (
    UIBuilder,
    ApiManager,
    RuntimeContext,
    Label,
    L10N,
    Container,
    VerticalList,
    Utils,
    GenreManager,
    FilteredResult,
    Grid,
    GoogleAnalytics,
    Promise,
    InfoBlock,
    KeyEvent,
    StorageProvider,
    Filter
) {
    'use strict';

    var api = ApiManager.getKPNAPI(),
        application = RuntimeContext.getCurrentApplication(),
        device = application.getDevice(),
        storage = device.getStorage(StorageProvider.STORAGE_TYPE_SESSION, 'storage'),
        layout = application.getLayout(),
        l10n = L10N.getInstance(),
        GA = GoogleAnalytics.getInstance(),
        EVENT = {
            Series_HeroClickAction: 'Series_HeroClickAction',
            UserClickedonFilter: 'Series_UserClickedonFilter',
            UserClickedonGenreFilter: 'Series_UserClickedonGenreFilter',
            UserClickedonSortingOptions: 'Series_UserClickedonSortingOptions',
            PlayVideo: 'PlayVideo',
            StartVideo: 'StartVideo',
            StopVideo: 'StopVideo',
            PauseButton: 'PauseButton',
            Trickplay: 'Trickplay'
        },
        GALabels = {
            MoreInfo: 'MoreInfo',
            WatchNow: 'WatchNow'
        },
        filterTypes = {
            GENRE: 'genre',
            SORT: 'sort',
            FILTER: 'filter'
        },
        sortOptions = {
            'Nieuwste eerst': {
                name: 'Nieuwste eerst',
                value: {
                    orderBy: 'activationDate',
                    sortOrder: 'desc'
                }
            },
            'Best beoordeeld': {
                name: 'Best beoordeeld',
                value: {
                    orderBy: 'extendedMetadata.imdbRating',
                    sortOrder: 'desc'
                }
            },
            'Naam: A - Z': {
                name: 'Naam: A - Z',
                value: {
                    orderBy: 'title',
                    sortOrder: 'asc'
                }
            },
            'Naam: Z - A': {
                name: 'Naam: Z - A',
                value: {
                    orderBy: 'title',
                    sortOrder: 'desc'
                }
            }
        },

        filterOptions = {
            'Geen kinderseries': {
                name: 'Geen kinderseries',
                value: 'Kinderen'
            }
        },
        infoblockConfig = {
            id: 'back-on-top-block',
            text: l10n.get('infoblock'),
            classname: ['icon', 'icon-back-v2'],
            position: 'right'
        },
        STORAGE_ITEMS = {
            parental: 'parental'
        },
        topPosition = layout.movies.top;

    return UIBuilder.extend({

        /**
         * Initialises the component.
         */
        init: function init () {
            this.pageId = 'series';
            init.base.call(this);
        },

        /**
         * Builds the component.
         *
         * @private
         */
        _build: function _build () {
            _build.base.call(this);

            this._buildPageContainer();
            this._buildHeader();
            this._buildTitle({
                label: {text: l10n.get('series.title'), classNames: ['top-title']}
            });
            this._buildInfoBlock();
        },

        /**
         * Builds the header.
         *
         * @private
         */
        _buildPageContainer: function () {
            var pageContainer = this._pageContainer = new VerticalList();

            this.appendChildWidget(pageContainer);
        },

        /**
         * Builds the header.
         *
         * @private
         */
        _buildHeader: function () {
            var header = this._header = new Container();

            header.addClass('header');
            this._pageContainer.appendChildWidget(header);
        },

        /**
         * Builds the no results message.
         *
         * @private
         */
        _showNoResultsMessage: function () {
            var noResultsLabel = this._noResultsLabel = new Label({
                text: l10n.get('movies.noresults'),
                classNames: ['noresults']
            });

            this.addClass('empty-result');
            this._widgetList.removeChildWidgets();
            this._widgetList.appendChildWidget(noResultsLabel);
        },

        /**
         * Builds the infoblock.
         *
         * @private
         */
        _buildInfoBlock: function () {
            var infoblock = this._infoblock = new InfoBlock(infoblockConfig);

            infoblock.addClass('info-block');

            this.appendChildWidget(infoblock);
        },

        /**
         * BeforeShow event.
         *
         * @param {Object} e - The event data.
         */
        onBeforeShow: function (e) {
            var activeRowIndex,
                isParentalActive,
                eventArgs = e.args;

            application.showLoader();
            if (!e.fromBack) {
                this._resetPage();
                this._infoblock.hide({skipAnim: true});

                if (eventArgs && Utils.isFunction(eventArgs.callback)) {
                    eventArgs.callback();
                }
            } else {
                application.hideLoader();
                this.alignCarouselsToLastIndex();
                activeRowIndex = this._widgetList && this._widgetList.getActiveChildWidgetIndex();
                this._widgetList.focus();
                isParentalActive = storage.getItem(STORAGE_ITEMS.parental);

                if (activeRowIndex > 0) {
                    this._infoblock.show();
                } else {
                    this._infoblock.hide({skipAnim: true});
                }

                if (!this._assetsUnlocked && !isParentalActive) {
                    this._unlockAssets();
                }
            }
        },

        /**
         * Loads the data.
         *
         * @param {Object} params - The parameters.
         * @private
         */
        _loadData: function loadMoviesData (params) {
            var defaultParams = {
                    page: application.getConfiguration().PAGES.SERIES
                },
                customParams = params || {},
                allParams = Utils.extend(defaultParams, customParams);

            api.read('uibuilder/page', {
                params: allParams
            }).then(Utils.bind(function (sectionsPage) {
                var promises = [];

                promises.push(sectionsPage.prepareHero());
                promises.push(sectionsPage.prepareCarousels());

                Promise.all(promises)
                    .then(Utils.bind(this._onDataReady, this));

            }, this));
        },

        /**
         * Loads the filtered data.
         *
         * @private
         */
        _loadFilteredData: function loadFilteredData () {
            var firstLoadTo = application.getConfiguration().series.firstLoadTo;

            if (Object.keys(this._getActiveFilters()).length < 1) {
                this._resetPage();
                return;
            }

            this._previousActiveRowNumber = null;
            this._buildGrid();
            this._getFilteredData(firstLoadTo)
                .then(Utils.bind(this._onFilteredDataReady, this));
        },

        /**
         * Returns the filtered data.
         *
         * @param {number} [firstLoadTo] - The first number to load if not paginating.
         *
         * @returns {Promise} - Returns the filtered data promise.
         * @private
         */
        _getFilteredData: function (firstLoadTo) {
            var selectedFilter = this._getActiveFilters()[filterTypes.FILTER] ? this._getActiveFilters()[filterTypes.FILTER].value : null,
                selectedSort = this._getActiveFilters()[filterTypes.SORT] ? this._getActiveFilters()[filterTypes.SORT].value : null,
                newPaginationIndex = this._lastPaginationIndex + application.getConfiguration().series.followingLoads,
                filter,
                order,
                sort,
                options,
                pagination;

            sort = selectedSort ? '&sortOrder=' + selectedSort.sortOrder : '';
            order = selectedSort ? '&orderBy=' + selectedSort.orderBy : '';

            if (firstLoadTo) {
                pagination = '&from=0&to=' + firstLoadTo;
                newPaginationIndex = firstLoadTo;
            } else {
                pagination = '&from=' + this._lastPaginationIndex + '&to=' + newPaginationIndex;
            }


            this._lastPaginationIndex = newPaginationIndex + 1;

            filter = selectedFilter ? '&filter_excludedGenres=' + this._getActiveFilters()[filterTypes.FILTER].value : '';
            options = {
                uri: '/TRAY/SEARCH/VOD/' +
                    '?filter_contentType=GROUP_OF_BUNDLES' +
                    '&filter_contentSubtype=SERIES' +
                    '&filter_quality=hd' +
                    '&dfilter_packages=matchSubscription' +
                    '&filter_technicalPackages=10078,10081,10129,10132,10159,10162,10228,10231,10252,10255,10258,10261'
                    + order + sort + filter + pagination
            };

            return new FilteredResult(options).prepare();
        },

        /**
         * Lazy loading data fetch.
         *
         * @private
         */
        _loadMoreFilteredData: function _loadMoreFilteredData () {
            var gridList,
                nextRowIndex,
                rowsCount,
                listWidgetStrip,
                nextWidget;

            if (!this._loadInProgress) {
                this._loadInProgress = true;
                this._getFilteredData()
                    .then(Utils.bind(function (data) {
                        gridList = this._grid.getList();
                        nextRowIndex = gridList.getActiveChildWidgetIndex() + 1;
                        rowsCount = gridList.getChildWidgetCount();
                        listWidgetStrip = this._grid.getList().getMask().getWidgetStrip();

                        if (data._items) {
                            this._grid.appendData(data._items, false, false);
                        }

                        // This conditional block will render & append the last two rows if they're not rendered & visible.
                        if (nextRowIndex >= rowsCount - 1) {
                            nextWidget = listWidgetStrip.getChildWidgetByIndex(nextRowIndex);
                            if (nextWidget && !nextWidget.isRendered()) {
                                device.appendChildElement(listWidgetStrip.outputElement, nextWidget.render(device));

                                nextWidget = gridList.getChildWidgetByIndex(nextRowIndex + 1);

                                if (nextWidget) {
                                    device.appendChildElement(listWidgetStrip.outputElement, nextWidget.render(device));
                                }
                            } else {
                                nextWidget = listWidgetStrip.getChildWidgetByIndex(nextRowIndex + 1);

                                if (nextWidget && !nextWidget.isRendered()) {
                                    device.appendChildElement(listWidgetStrip.outputElement, nextWidget.render(device));
                                }
                            }
                        }

                        this._loadInProgress = false;
                    }, this));
            }
        },

        /**
         * Gets executed when the filtered page data has loaded.
         *
         * @param {Array} pageSections - The grid data to build.
         * @private
         */
        _onFilteredDataReady: function (pageSections) {
            this._settingDataItems = true;

            if (pageSections._items.length <= 0) {
                this._showNoResultsMessage();
                return;
            }

            this.removeClass('empty-result');
            this._widgetList.removeChildWidgets();

            // Unset hero found and reset top to the default top position.
            this.heroFound = false;
            this._widgetList.setStyleTo('top', layout.movies.top + 'px');
            this._widgetList.appendChildWidget(this._grid);

            this._grid.setDataItem({
                items: pageSections._items
            }, false, true);

            if (!this._grid.isVisible()) {
                this._grid.show();
            }

            this._settingDataItems = false;
            this._totalCount = pageSections._totalCount;

            application.hideLoader();
        },

        /**
         * Gets executed when the page data has loaded.
         *
         * @param {Array} pageSections - The sections to build.
         * @private
         */
        _onDataReady: function (pageSections) {
            var sections = this._parseSections(pageSections),
                seriesLayout = layout.series,
                firstContentCarousel;

            topPosition = seriesLayout.top;

            this.buildWidgets(sections);
            this.alignCarousels();

            firstContentCarousel = this._widgetList.getChildWidgetByIndex(0);

            this._addFilterWidget();
            this._buildClock();
            this._widgetList.focus();

            if (!this.heroFound) {
                topPosition = seriesLayout.topNoHero;
                firstContentCarousel.focus();
            }

            this._widgetList.setStyleTo('top', topPosition + 'px');
            application.hideLoader();
        },

        /**
         * Transforms the sections.
         *
         * @param {Array} pageSections - The sections to transform.
         * @returns {Object} - Returns an object with a collection of hero slider items and carousels.
         */
        _parseSections: function (pageSections) {
            var hero = pageSections[0],
                carousels = pageSections[1];

            return {
                hero: hero,
                carousels: carousels
            };
        },

        /**
         * Builds the widgets and appends them to the component.
         *
         * @param {Object} pageSections - The sections that contains collections of widgets.
         * @param {Object} [sectionParams] - Specific params to use for the widgets. i.e. layouts.
         */
        buildWidgets: function (pageSections, sectionParams) {
            var hero = pageSections.hero,
                carousels = pageSections.carousels,
                sections = [],
                carouselWidget;

            if (hero && hero.getItems().length) {
                sections = sections.concat(hero);
            }

            if (carousels.length) {
                sections = sections.concat(carousels);
            }

            this.heroFound = false;

            Utils.each(sections, function (section) {

                this.buildWidget(section, sectionParams);
            }, this);

            if (!this.heroFound) {
                this.addClass('no-hero-item');
                this._list.getChildWidgetByIndex(0).focus();
            } else {
                this._branding.show({
                    duration: 300
                });
                if (this.hasClass('no-hero-item')) {
                    this.removeClass('no-hero-item');
                }

                // Check if it there's only a hero and a carousel to reduce top.
                if (this._widgetList.getChildWidgetCount() === 2) {
                    carouselWidget = this._widgetList.getChildWidgetByIndex(1);
                    carouselWidget.addClass('single-ui-carousel');
                }
            }
        },

        /**
         * Builds the grid.
         *
         * @private
         */
        _buildGrid: function () {
            var opts = {
                loadmoreCallback: Utils.bind(this._loadMoreFilteredData, this)
            };

            this._grid = new Grid(opts);
        },

        /**
         * Unlock the assets.
         *
         * @private
         */
        _unlockAssets: function () {
            var rows = this._widgetList.getChildWidgets(),
                assets;

            this._assetsUnlocked = true;
            Utils.each(rows, function (row) {
                if (row.getCarousel) {
                    assets = row.getCarousel().getChildWidgets();

                    Utils.each(assets, function (asset) {
                        if (asset.hasClass('asset')) {
                            asset.unlock();
                        }
                    });
                }
            });

            if (this._grid) {
                Utils.each(this._grid.getList().getChildWidgets(), function (row) {

                    Utils.each(row.getChildWidgets(), function (asset) {
                        if (asset.hasClass('asset')) {
                            asset.unlock();
                        }
                    });
                });
            }
        },

        /**
         * Unlock the assets.
         *
         * @private
         */
        _lockAssets: function () {
            var rows = this._widgetList.getChildWidgets(),
                assets;

            this._assetsUnlocked = true;
            Utils.each(rows, function (row) {
                if (row.getCarousel) {
                    assets = row.getCarousel().getChildWidgets();

                    Utils.each(assets, function (asset) {
                        if (asset.hasClass('asset')) {
                            asset.lock();
                        }
                    });
                }
            });

            if (this._grid) {
                Utils.each(this._grid.getList().getChildWidgets(), function (row) {

                    Utils.each(row.getChildWidgets(), function (asset) {
                        if (asset.hasClass('asset')) {
                            asset.lock();
                        }
                    });
                });
            }
        },

        /**
         * Select event.
         *
         * @param {Object} e - The event data.
         * @private
         */
        _onSelect: function (e) {
            var eventTarget = e.target,
                contentItem,
                selectAction = Utils.bind(function () {
                    contentItem = eventTarget.getDataItem().item;

                    if (eventTarget.playOnSelect()) {
                        if (contentItem.canPlay()) {
                            this._routeToPlayer({
                                data: contentItem,
                                type: 'VOD_MOVIE',
                                callingPage: this.pageId
                            });
                        }
                    } else if (eventTarget.hasClass('asset')) {
                        this._routeToDetails({
                            data: contentItem
                        });
                    }
                }, this),
                sliderItem;

            switch (eventTarget.id) {
                case 'back-on-top-block':
                    this._onBack();
                    return;
                case 'filter-genre-btn':
                    this._genreFilterSelected();
                    return;
                case 'filter-filter-btn':
                    this._commonFilterSelected();
                    return;
                case 'filter-sort-btn':
                    this._sortFilterSelected();
                    return;

                // no default
            }

            if (e.target.hasClass('watchall')) {
                this.goToWatchAll(e.target.getDataItem());
                return;
            }

            if (eventTarget.hasClass('slider-item') || (eventTarget.hasClass('epg') || eventTarget.hasClass('vod'))) {
                sliderItem = e.target.getDataItem();
                contentItem = sliderItem.item || sliderItem.getItem();

                selectAction = Utils.bind(this._routeToDetails, this, {
                    data: contentItem
                });

                if (contentItem.isLocked()) {
                    application.route('parentalpin', {
                        successCallback: Utils.bind(function () {
                            selectAction();
                            this._unlockAssets();

                            GA.onEvent('Action', EVENT.Series_HeroClickAction, {eventLabel: GALabels.MoreInfo});
                        }, this)
                    });
                } else {
                    selectAction();

                    GA.onEvent('Action', EVENT.Series_HeroClickAction, {eventLabel: GALabels.MoreInfo});
                }
            } else if (e.target.hasClass('pointer-button-big')) {

                if (e.target.hasClass('left-pointer')) {
                    e.target.parentWidget.getCarousel().alignPrevious();
                } else if (e.target.hasClass('right-pointer')) {
                    e.target.parentWidget.getCarousel().alignNext();
                }
            } else if (!e.target.isLocked()) {
                selectAction();
            } else {
                application.route('parentalpin', {
                    successCallback: Utils.bind(function () {
                        selectAction();
                        this._unlockAssets();
                    }, this)
                });
            }
        },

        /**
         * Builds genre filters.
         *
         * @private
         */
        _buildGenreFilters: function () {
            var commonFiltersButton = this._commonfilter = new Filter({
                    text: l10n.get('filter.filter'),
                    id: 'filter-filter-btn',
                    isDropDown: true,
                    classList: 'icon-button',
                    type: 'filter'
                }),

                sortingFiltersButton = this._sortfilter = new Filter({
                    text: l10n.get('sort.all'),
                    id: 'filter-sort-btn',
                    isDropDown: true,
                    classList: 'icon-button',
                    type: 'sort'
                });

            this._filterscontainer.appendChildWidget(commonFiltersButton);
            this._filterscontainer.appendChildWidget(sortingFiltersButton);
        },

        /**
         * Attempts to play the video.
         *
         * @param {Object} dataItem - The data item.
         * @private
         */
        _onPlay: function (dataItem) {
            var data = dataItem || this._data[0];

            if (data.canPlay()) {
                this.showPlayer();
                application.route('vodplayer', {
                    data: data,
                    type: 'VOD_MOVIE',
                    callingPage: 'series'
                });
            }
        },

        /**
         * Popup a modal to filter a genre.
         *
         * @private
         */
        _genreFilterSelected: function () {
            var genreArray = [],
                genreValues = [],
                genres = GenreManager.MOVIE_GENRES,
                all = l10n.get('genre.overview'),
                highlighted = l10n.get('genre.highlighted');

            genreArray.push(all);
            genreValues.push({
                name: all,
                values: null
            });

            genreArray.push(highlighted);
            genreValues.push({
                name: highlighted,
                values: 11393
            });

            Utils.each(genres, function (genre) {
                genreArray.push(genre.name);
                genreValues.push(genre);
            });

            clearTimeout(this._timer);

            application.route('dropdown', {
                dataOptions: genreArray,
                dataValues: genreValues,
                prevValue: this._genrefilter.getGenreButton().getText(),
                filter: 'genre',
                callback: Utils.bind(this._onDropdownCallback, this),
                showGoBackButton: true
            });
        },

        /**
         * Popup a modal to filter by filtering.
         *
         * @private
         */
        _commonFilterSelected: function () {
            var genreArray = [],
                genreValues = [],
                genres = filterOptions,
                all = l10n.get('filter.all_series');

            genreArray.push(all);
            genreValues.push({
                name: all,
                values: null
            });

            Utils.each(genres, function (value, key) {
                genreArray.push(key);
                genreValues.push(value);
            });

            clearTimeout(this._timer);

            application.route('dropdown', {
                dataOptions: genreArray,
                dataValues: genreValues,
                prevValue: this._commonfilter.getFilterButton().getText(),
                filter: 'filter',
                callback: Utils.bind(this._onDropdownCallback, this),
                showGoBackButton: true
            });
        },

        /**
         * Popup a modal to filter by sorting.
         *
         * @private
         */
        _sortFilterSelected: function () {
            var genreArray = [],
                genreValues = [],
                genres = sortOptions,
                all = l10n.get('sort.all');

            genreArray.push(all);
            genreValues.push({
                name: all,
                values: null
            });

            Utils.each(genres, function (value, key) {
                genreArray.push(key);
                genreValues.push(value);
            });

            clearTimeout(this._timer);

            application.route('dropdown', {
                dataOptions: genreArray,
                dataValues: genreValues,
                prevValue: this._sortfilter.getSortButton().getText(),
                filter: 'sort',
                callback: Utils.bind(this._onDropdownCallback, this),
                showGoBackButton: true
            });
        },


        /**
         * Function fires after dropdown item is selected.
         *
         * @param {Object} event - Selected item.
         * @private
         */
        _onDropdownCallback: function (event) {
            var target,
                filterName,
                valueObject;

            if (!event) {
                return;
            }

            application.showLoader();
            target = event.target;
            filterName = target._filterName;
            valueObject = target._itemValueObject;

            this._setFilter(filterName, valueObject);

            this._markSelectedFilters();
            this._sendFiltersAnalyticsEvents(filterName, valueObject.name);
            this._loadFilteredData();
        },

        /**
         * Upload text filter value.
         *
         * @param {string} filter - Filter name.
         * @param {string} value - Value which should be set.
         * @private
         */
        _setFilter: function (filter, value) {
            var buttonName = value.name;

            switch (filter) {
                case 'genre':
                    if (buttonName === l10n.get('genre.overview')) {
                        buttonName = l10n.get('genre.all');
                    }
                    this._genrefilter.getGenreButton().setText(buttonName);
                    break;
                case 'filter':
                    if (buttonName === l10n.get('filter.all')) {
                        buttonName = l10n.get('filter.filter');
                    }
                    this._commonfilter.getFilterButton().setText(buttonName);
                    break;
                case 'sort':
                    this._sortfilter.getSortButton().setText(buttonName);
                    break;
            }

            if (value.values || value.value) {
                this._setActiveFilters(filter, value);
            } else {
                this._removeActiveFilter(filter);
            }
        },

        /**
         * Send the appropriate events to google analytics.
         *
         * @param {string} type - Type of the filter.
         * @param {string} value - Value which should be sent to GA.
         * @private
         */
        _sendFiltersAnalyticsEvents: function (type, value) {
            switch (type) {
                case 'genre':
                    GA.onEvent('Action', EVENT.UserClickedonGenreFilter, {eventLabel: value});
                    break;
                case 'filter':
                    GA.onEvent('Action', EVENT.UserClickedonFilter, {eventLabel: value});
                    break;
                case 'sort':
                    GA.onEvent('Action', EVENT.UserClickedonSortingOptions, {eventLabel: value});
                    break;
            }
        },

        /**
         * Upload text filter value.
         *
         * @param {string} filter - Filter name.
         * @param {string} value - Value which should be set.
         * @private
         */
        _setActiveFilters: function (filter, value) {
            this._activeFilters = this._activeFilters || {};
            this._activeFilters[filter] = value;
        },

        /**
         * Upload text filter value.
         *
         * @param {string} filter - Filter name.
         * @private
         */
        _removeActiveFilter: function (filter) {
            delete this._activeFilters[filter];
        },

        /**
         * Return the active filter if any.
         *
         * @returns {Array} List of active filters.
         * @private
         */
        _getActiveFilters: function () {
            return this._activeFilters;
        },

        /**
         * Clear the filters set.
         *
         * @private
         */
        _clearAllFilters: function () {
            this._activeFilters = {};
        },

        /**
         * Mark active filtes as selected, if any.
         *
         * @private
         */
        _markSelectedFilters: function () {
            var activeFilters = this._getActiveFilters();

            if (activeFilters['filter']) {
                if (!this._commonfilter.hasClass('selected')) {
                    this._commonfilter.addClass('selected');
                }
            } else {
                if (this._commonfilter.hasClass('selected')) {
                    this._commonfilter.removeClass('selected');
                }
            }

            if (activeFilters['sort']) {
                if (!this._sortfilter.hasClass('selected')) {
                    this._sortfilter.addClass('selected');
                }
            } else {
                if (this._sortfilter.hasClass('selected')) {
                    this._sortfilter.removeClass('selected');
                }
            }
        },

        /**
         * Selected item change event.
         *
         * @param {Object} e - The event data.
         * @private
         */
        _onSelectedItemChange: function (e) {
            var activeRowNumber,
                itemsLength,
                target = e.target;

            if (target === this._widgetList && !this._grid) {

                this._scroll(e);
                activeRowNumber = e.index + 1;

                if (activeRowNumber > 1) {
                    this._infoblock.show();
                } else {
                    this._infoblock.hide();
                }

            } else if (this._grid) {
                activeRowNumber = this._grid.getActiveChildIndex() + 1;

                if (activeRowNumber > 1) {
                    this._infoblock.show();
                } else {
                    this._infoblock.hide();
                }

                if (this._grid.getDataItem()) {
                    itemsLength = this._grid.getDataItem().items.length;

                    if (!this._loadInProgress && (!this._previousActiveRowNumber || activeRowNumber > this._previousActiveRowNumber && itemsLength < this._totalCount)) {
                        this._grid.checkLoadMore();
                        this._previousActiveRowNumber = activeRowNumber;
                    }
                }
            }
        },

        /**
         * Back event.
         *
         * @private
         */
        _onBack: function () {
            var activeRowNumber,
                topCarousel;

            if (this._grid) {
                activeRowNumber = this._grid.getActiveChildIndex() + 1;
            } else {
                activeRowNumber = this._widgetList._selectedIndex + 1;
            }

            if (activeRowNumber !== 1) {
                if (this._grid) {
                    this._grid.alignToFirstItem();
                } else {

                    // Focus on first carousel/hero.
                    this._widgetList.setActiveChildIndex(0);

                    topCarousel = this._widgetList.getChildWidgetByIndex(0).getCarousel();
                    topCarousel.alignToIndex(0);
                    topCarousel.setActiveChildIndex(0);
                }

            } else {
                application.focusMenu('main');
            }
        },

        /**
         * Reset the page to initial view.
         *
         * @private
         */
        _resetPage: function () {
            this.removeAll();
            this.removeClass('empty-result');
            this._loadData();
            this._clearAllFilters();
            this._markSelectedFilters();
            this._commonfilter.getFilterButton().setText(l10n.get('filter.filter'));
            this._sortfilter.getSortButton().setText(l10n.get('sort.all'));
            this._grid = null;
        },

        /**
         * Scrolls the page.
         *
         * @param {Object} e - The selected item change event data.
         * @param {boolean} donotAnim - Do not animate.
         * @param {boolean} [reset] - True if the alignment should reset.
         * @private
         */
        _scroll: function (e, donotAnim, reset) {
            if (!e.item.outputElement) {
                return;
            }

            // Skip align at last carousel, this way we don't leave a gap at the end of the screen.
            if (this._widgetList.getIndexOfChildWidget(e.item) >= 0) {
                this._align(e.item, donotAnim, reset, e.index);
            }
        },

        /**
         * Aligns the widgetlist to the item.
         *
         * @param {Object} item - The item.
         * @param {boolean} doNotAnim - Prevent animation.
         * @param {boolean} [reset] - True if the alignment should reset.
         * @private
         */
        _align: function (item, doNotAnim, reset, index) {
            var listElement = this._widgetList.outputElement,
                listTop = listElement.getBoundingClientRect().top,
                left = 0,
                dimensions,
                difference,
                newTop,
                moviesLayout = layout.movies,
                marginTop = moviesLayout.marginTopCarousels;

            dimensions = item.outputElement.getBoundingClientRect();

            if (index > 1 || (index && !this.heroFound)) {
                dimensions = this._widgetList.getChildWidgetByIndex(index - 1).outputElement.getBoundingClientRect();
            }

            difference = dimensions.top - marginTop;

            if (difference > 0) {
                newTop = listTop - difference;
            } else {
                newTop = listTop + -difference;
            }

            if (newTop > 0 || reset) {
                newTop = topPosition;
            }

            device.moveElementTo({
                el: listElement,
                duration: 300,
                fps: 60,
                easing: 'easeInOut',
                skipAnim: !!doNotAnim,
                to: {
                    top: newTop,
                    left: left
                }
            });
        }
    });
});