Source: views/player/base.js

define('application/views/player/base', [
    'rofl/widgets/verticallist',
    'rofl/widgets/container',
    'application/widgets/player/controls',
    'rofl/lib/utils',
    'application/widgets/player/channelswitcher',
    'application/widgets/player/warningbox',
    'application/widgets/clock',
    'application/widgets/detail/iconbutton',
    'application/widgets/player/programdetails',
    'application/widgets/player/miniepg',
    'application/constants',
    'antie/runtimecontext',
    'antie/events/keyevent',
    'rofl/devices/input/pointer'
], function (
    VerticalList,
    Container,
    Controls,
    Utils,
    ChannelSwitcher,
    WarningBox,
    Clock,
    IconButton,
    ProgramDetails,
    MiniEPG,
    Constants,
    RuntimeContext,
    KeyEvent,
    PointerManager
) {
    'use strict';

    var CONTROLS = {
            BACK: Constants.PLAYER_CONTROLS_BACK,
            INFO: Constants.PLAYER_CONTROLS_INFO,
            RESTART: Constants.PLAYER_CONTROLS_RESTART,
            REWIND: Constants.PLAYER_CONTROLS_REWIND,
            PLAYPAUSE: Constants.PLAYER_CONTROLS_PLAYPAUSE,
            FORWARD: Constants.PLAYER_CONTROLS_FORWARD,
            RECORD: Constants.PLAYER_CONTROLS_RECORD,
            MINIEPG: Constants.PLAYER_CONTROLS_MINIEPG,
            LIVE: Constants.PLAYER_CONTROLS_LIVE,
            NEXT: Constants.PLAYER_CONTROLS_NEXT,
            CLOCK: Constants.PLAYER_CONTROLS_CLOCK,
            MENU: Constants.PLAYER_CONTROLS_MENU
        },
        BaseView,
        application = RuntimeContext.getCurrentApplication(),
        layout = application.getLayout(),
        configuration = application.getConfiguration(),
        descriptionLayout = layout.player.description,
        ZAPPBANNER_DISSAPPEAR_TIME = configuration.ZAPPBANNER_DISSAPPEAR_TIME,
        device = RuntimeContext.getDevice(),
        pointerManager;

    BaseView = VerticalList.extend({

        init: function init (controls, viewParams) {
            init.base.call(this, 'player-view-container');

            controls = controls || [];

            this._viewContent = new Container();
            this._viewContent.addClass('player-view-content');
            this._view = new VerticalList();
            this._view.addClass('player-view');
            this._onViewKeyDownBound = Utils.bind(this._onViewKeyDown, this);
            this._onMouseOverHandler = viewParams && viewParams.mouseOverHandler;

            this._buildBack();
            this._buildWarningBox();
            this._viewContent.appendChildWidget(this._view);
            this.appendChildWidget(this._viewContent);

            this._buildClock();
            this._buildZapControlsContainer();
            this._buildZappBanner();
            this._buildControlBar();
            this._buildBottomBar();

            this.setControls(controls);
            this._buildInfo();
            this._setListeners();

            if (!pointerManager) {
                pointerManager = PointerManager.getInstance();
            }
        },

        /**
         * On before show event.
         *
         * @param {Object} e - The before show event.
         */
        onBeforeShow: function onBeforeShow (e) {
            onBeforeShow.base.call(this, e);

            this.hideProgress({
                skipAnim: true
            });
        },

        /**
         * On before hide event.
         *
         * @param {Object} e - The before show event.
         */
        onBeforeHide: function onBeforeHide (e) {
            onBeforeHide.base.call(this, e);

            this._removeListeners();
        },

        /**
         * Sets listeners.
         *
         * @private
         */
        _setListeners: function () {
            this._view.addEventListener('keydown', this._onViewKeyDownBound);
        },

        /**
         * Remove listeners.
         *
         * @private
         */
        _removeListeners: function () {
            this._view.removeEventListener('keydown', this._onViewKeyDownBound);
        },

        supportsPointer: function () {
            return pointerManager && pointerManager.pointerIsOn();
        },

        /**
         * Adds the mouse over handler.
         */
        addMouseOverHandler: function () {

            if (this.parentWidget.outputElement) {

                this.parentWidget.outputElement.onmouseover = this._onMouseOverHandler;
            }
        },

        /**
         * Removes the mouse over handler.
         */
        removeMouseOverHandler: function removeMouseOverHandlerFn () {

            if (this.parentWidget.outputElement) {

                this.parentWidget.outputElement.onmouseover = null;
            }
        },

        /**
         * Renders the button.
         *
         * @returns {Object} DOM node.
         */
        render: function render () {
            var element = render.base.call(this, device);

            this.addMouseOverHandler();

            return element;
        },

        /**
         * Disposes of the button.
         */
        dispose: function dispose () {

            this.removeMouseOverHandler();

            dispose.base.call(this);
        },

        /**
         * Sets the player ui controls.
         *
         * @param {Array} controls - Array with the control buttons to be set.
         */
        setControls: function (controls) {
            this._controls.setControls(controls);
        },

        /**
         * Builds the clock.
         *
         * @private
         */
        _buildClock: function () {
            var clock = this._clock = new Clock();

            this.appendChildWidget(clock);
        },

        /**
         * Builds zap controls container.
         *
         * @private
         */
        _buildControlBar: function () {
            this._controls = new Controls();

            this._zapControlsContainer.appendChildWidget(this._controls);
        },

        /**
         * Returns the control bar that contians each control.
         *
         * @returns {Object} - The control bar.
         */
        getControlBar: function () {
            return this._controls;
        },

        /**
         * Builds bottom bar.
         *
         * @private
         */
        _buildBottomBar: function () {
            this._bottomBar = new Container();

            this._bottomBar.addClass('bottombar');

            this._view.appendChildWidget(this._bottomBar);
        },

        /**
         * Builds WarningBox.
         *
         * @private
         */
        _buildWarningBox: function () {
            var warningBox = this._warningBox = new WarningBox();

            this.appendChildWidget(warningBox);
        },

        /**
         * Builds the back button.
         *
         * @private
         */
        _buildBack: function () {
            var btn = this._backButton = new IconButton(CONTROLS.BACK, '', ['icon', 'icon-back-v2']);

            this._backButton.addClass('back-button');

            this._view.appendChildWidget(btn);
        },

        /**
         * Build info bar.
         *
         * @private
         */
        _buildInfo: function () {
            this._programInfo = this._bottomBar.appendChildWidget(new ProgramDetails());
        },

        /**
         * Build zappbaner bar.
         *
         * @param {Object} zappBannerWidget - The zapp banner widget.
         * @private
         */
        _buildZappBanner: function (zappBannerWidget) {
            this._zappBanner = zappBannerWidget;

            this._zapControlsContainer.appendChildWidget(zappBannerWidget);
        },

        /**
         * Builds the main container that will include zappBanner & controls.
         *
         * @private
         */
        _buildZapControlsContainer: function () {
            var zapControlsContainer = this._zapControlsContainer = new Container();

            zapControlsContainer.addClass('zapping-controls-content');

            this._view.appendChildWidget(zapControlsContainer);
        },

        /**
         * Sets the program data to be displayed.
         *
         * @param {Object} programData - The program's data.
         */
        setProgram: function (programData) {
            this._zappBanner.setProgram(programData);
        },

        /**
         * Sets the progress to the progressbar.
         *
         * @param {Object} progressData - The progress data to be set.
         */
        setProgress: function (progressData) {
            this._zappBanner.setProgress(progressData);

            if (!this._zappBanner.getProgress().isVisible()) {
                this.showProgress();
            }
        },

        /**
         * Sets max pointer position.
         */
        setProgressMaxPointerPosition: function () {
            this._zappBanner.getProgress().setMaxPointerPosition();
        },

        /**
         * Updates the seek speed.
         *
         * @param {number} speed - The seek speed.
         */
        updateSeekSpeed: function (speed) {
            this._controls.updateSeekSpeed(speed);
        },

        /**
         * Attempts to reset trickmode buttons.
         */
        resetControls: function () {
            this._controls.resetControls();
        },

        /**
         * On focus event. Sets the focus on play pause button.
         */
        focus: function () {
            this._controls.focus();
            this.showUI();
        },

        /**
         * Show progress bar.
         *
         */
        showProgress: function () {
            this._zappBanner.getProgress().show();
        },

        /**
         * Hide progress bar.
         *
         * @param {Object} [options] - Pass animation options if required.
         *
         */
        hideProgress: function (options) {
            this._zappBanner.getProgress().hide(options);
        },

        /**
         * Show/hide the program detail for the current live program.
         *
         * @param {boolean} show - True to show info detail, false to hide it.
         * @param {Object} programDetails - The program containing the details to show.
         **/
        showProgramInfo: function (show, programDetails) {
            var infoContainerHeight = 0,
                metadataOutputElement,
                descriptionLayoutHeight;

            this._controls.onProgramInfo(!show);

            if (show) {
                if (this._miniEPG) {
                    this.showMiniEPG(true);
                }

                this._programInfo.setDataItem(programDetails);

                // Retrieve metadata widget and apply dynamic height to the info container.
                metadataOutputElement = this._programInfo.getChildWidgetByIndex(1).outputElement;
                descriptionLayoutHeight = descriptionLayout.height;
                infoContainerHeight = metadataOutputElement.getBoundingClientRect().height;
                infoContainerHeight = (infoContainerHeight < descriptionLayoutHeight ? descriptionLayoutHeight : infoContainerHeight) + 'px';
                this._programInfo.setStyleTo('height', infoContainerHeight);
                this._programInfo.addClass('expand');
            } else {
                this._programInfo.setStyleTo('height', infoContainerHeight);
                this._programInfo.removeClass('expand');
            }
        },

        /** --> Update button states **/

        /**
         * Should be called when the video player plays.
         */
        onPlay: function () {
            this._controls.onPlay();
        },

        /**
         * Should be called when the video player pauses.
         *
         * @param {boolean} focusPlayPause - True if should focus on playpause button.
         */
        onPause: function (focusPlayPause) {
            this._controls.onPause(focusPlayPause);
        },

        /**
         * Focuses on rewind.
         */
        onRewind: function () {
            this._controls.onRewind();
        },

        /**
         * Focuses on ff.
         */
        onFastForward: function () {
            this._controls.onFastForward();
        },

        /** --> View Visibility **/
        /**
         * Returns true if the UI is visible.
         *
         * @returns {boolean} - True if the UI is visible.
         */
        isUIVisible: function () {
            return this._viewContent.isVisible();
        },

        /**
         * Shows the ui.
         * Default behaviour hides after ZAPPBANNER_DISSAPPEAR_TIME seconds.
         *
         * @param {boolean} [permanent] - True if UI should show permanently.
         * @param {boolean} [hideClock] - True if clock should be hidden.
         */
        showUI: function (permanent, hideClock) {
            var seekActive = this._controls.isSeekActive();

            clearTimeout(this._hideUITimeout);

            if (!this.isUIVisible()) {
                this._viewContent.show();

                if (!hideClock && this._clock) {
                    this._clock.show();
                }
            }

            if ((!permanent && !seekActive) || !seekActive) {
                this._hideUITimeout = setTimeout(Utils.bind(this.hideUI, this), ZAPPBANNER_DISSAPPEAR_TIME);
            }

            if (this._miniEPG) {
                this._miniEPG.setFocusable(true);
            }
        },

        /**
         * Hides the ui.
         *
         * @param {Object} [opts] - Options.
         */
        hideUI: function (opts) {
            var isPaused = this._controls.isPaused();

            if (this.isContentExpanded() || isPaused) {
                return;
            }

            if (this.isUIVisible()) {
                this.closeExpandedContents();
                this._viewContent.hide(opts);
                this._clock.hide(opts);
            }

            if (this._miniEPG) {
                this._miniEPG.setFocusable(false);
            }
        },

        /**
         * Checks if the bottom bar content is showing miniEPG or programInfo.
         *
         * @returns {boolean} - True if there's expanded content, false if not.
         */
        isContentExpanded: function () {
            return this._programInfo && this._programInfo.isExpanded() ||
                   this._miniEPG && this._miniEPG.isExpanded();
        },

        /**
         * Closes any expanded content (i.e. miniEPG or program's detail).
         */
        closeExpandedContents: function () {
            if (this._programInfo && this._programInfo.isExpanded()) {
                this.showProgramInfo(false);
            }

            if (this._miniEPG) {
                this.showMiniEPG(true);
            }
        },

        /**
         * Behaviour for showing hiding miniEPG with down button.
         *
         * @param {Object} e - Key down event.
         * @private
         */
        _onViewKeyDown: function (e) {
            if (e.keyCode === KeyEvent.VK_DOWN) {
                if (this.isUIVisible() &&
                    this._miniEPG && !this._miniEPG.isExpanded() && this._miniEPG.isFocussed()) {
                    this.showMiniEPG();
                    this._miniEPG.focus();
                } else {
                    if (!this.isUIVisible()) {
                        this.showUI();
                    }
                    e.stopPropagation();
                }
            }

            if (e.keyCode === KeyEvent.VK_UP) {
                if (this.isContentExpanded()) {
                    this.closeExpandedContents();
                    this.showUI();
                }
            }
        },

        /**
         * Returns the program details container.
         *
         * @returns {Object} - The program details container.
         */
        getProgramDetails: function () {
            return this._programInfo;
        },

        /**
         * Returns the mini epg.
         *
         * @returns {Object} - The mini epg.
         */
        getMiniEPG: function () {
            return this._miniEPG;
        },

        /**
         * Shows the warning box.
         *
         * @param {Object} config - The config.
         */
        showWarningBox: function (config) {
            this._warningBox.show(config);
        },

        /**
         * Hides the warning box.
         *
         * @param {boolean} [skipAnim] - True if should skip the animations.
         */
        hideWarningBox: function (skipAnim) {
            this._warningBox.hide({
                skipAnim: skipAnim
            });
        },

        /**
         * Shows/hides next episode button.
         *
         * @param {boolean} show - Boolean flag to show (true) or hide next episode button..
         */
        setNextEpisodeButton: function (show) {
            this._controls.setNextEpisodeButton(show);
        },

        /**
         * Should set or not program info button.
         *
         * @param {boolean} show - True to show button.
         */
        setProgramInfoButton: function (show) {
            this._controls.setProgramInfoButton(show);
        },

        /**
         * Sets the trickplay settings.
         */
        setTrickplaySettings: function () {
            this._zappBanner.setTrickplaySettings();
        }

    });

    BaseView.CONTROLS = CONTROLS;

    return BaseView;
});