Source: decorators/player/livemanipulation.js

define('application/decorators/player/livemanipulation', [
    'antie/runtimecontext',
    'rofl/lib/l10n',
    'application/managers/player',
    'application/managers/recording',
    'rofl/lib/utils',
    'application/managers/feature',
    'rofl/analytics/web/google',
    'application/constants',
    'application/utils',
    'application/managers/progress'
], function (
    RuntimeContext,
    L10N,
    PlayerManager,
    RecordingManager,
    Utils,
    FeatureManager,
    GoogleAnalytics,
    Constants,
    AppUtils
) {
    'use strict';

    var application = RuntimeContext.getCurrentApplication(),
        recordingManager = RecordingManager.getInstance(),
        featureManager = FeatureManager.getInstance(),
        GA = GoogleAnalytics.getInstance(),
        l10n = L10N.getInstance();

    return {

        /**
         * Pauses the player.
         *
         * @private
         */
        _onPause: function () {

            if (!this.playerInterface.isPlaying()) {
                return;
            }

            // Focus on play/pause button.
            this._view.focus();
            this._view.onPause();
            this.playerInterface.pause();
            this._sendPauseAnalytics();
        },

        /**
         * Plays the player.
         *
         * @private
         */
        _onPlay: function () {

            if (!this.playerInterface.isPaused()) {
                return;
            }

            this._view.onPlay();

            if (this._seeker.isActive()) {
                this._seeker.confirm();
                this._sendTrickplayAnalytics();
            } else {

                if (this._type === Constants.LIVE_VIDEO_TYPE) {
                    this._delayedStreamTime = this._pauseTime;

                    // LIVE video was paused, request startover with media player's current time.
                    this._onRestart(this.playerInterface.getCurrentTime());
                } else {

                    // RESTART video was paused, resume playback.
                    this.playerInterface.resume();
                }
            }

            GA.onEvent(
                Constants.ANALYTICS_EVENT_CATEGORY_ACTION,
                Constants.ANALYTICS_EVENT_ACTION_PLAY_VIDEO,
                {
                    eventLabel: AppUtils.getAnalyticsEventLabel(this._type)
                }
            );
        },

        /**
         * Plays or Pauses the video, depending on the current state.
         *
         * @private
         */
        _onPlayPause: function () {
            if (this.playerInterface.isPlaying()) {
                this._onPause();
            } else if (this.playerInterface.isPaused()) {
                this._onPlay();
            }
        },

        /**
         * Prepares playback of live broadcast.
         */
        _onLive: function () {
            this._stopProgressTimeouts();
            this._view.resetControls();
            application.showLoader();
            this._preparePlayer({
                data: this._program,
                type: Constants.LIVE_VIDEO_TYPE
            });
            this._view.focus();
        },

        /**
         * Function solves selecting restart button.
         *
         * @param {number} [startTime] - The restart start time.
         * @private
         */
        _onRestart: function (startTime) {
            var isRestart = this._type === Constants.RESTART_VIDEO_TYPE;

            if (this.playerInterface.isPaused() ||
                this.playerInterface.isPlaying() && this._playbackStatus.active) {

                if (isRestart) {
                    this.playerInterface.seek(0);
                } else {

                    // Stop the live and Restart progress.
                    this._stopProgressTimeouts();
                    this._view.resetControls();
                    application.showLoader();
                    this._preparePlayer({
                        data: this._program,
                        startTime: startTime,
                        type: Constants.RESTART_VIDEO_TYPE
                    });
                }

                GA.onEvent(
                    Constants.ANALYTICS_EVENT_CATEGORY_ACTION,
                    Constants.ANALYTICS_EVENT_ACTION_STARTOVER
                );
            }
        },

        /**
         * Attempts to rewind the video.
         *
         * @private
         */
        _onRewind: function () {
            if (this.playerInterface.isPaused() ||
                this.playerInterface.isPlaying() && this._playbackStatus.active) {
                if (!PlayerManager.isTrickplayEnabled()) {
                    this._showSeekingNotSupportedMessage();
                    return;
                }

                if (!this._canRewind()) {
                    this._showSeekingProhibitedMessage();
                    return;
                }

                this._seeking = Constants.PLAYER_SEEK_DIRECTION_BACKWARD;

                // Stop progress timeouts before starting fast forward.
                this._stopProgressTimeouts();
                this._seeker.rewind();
            }
        },

        /**
         * Gets executed when the speed changes.
         *
         * @param {number} speed - The speed.
         * @private
         */
        _onSpeedChanged: function (speed) {
            this._seekSpeed = speed;

            if (speed) {
                this._view.updateSeekSpeed(speed);
            }
        },

        /**
         * Attempts to fast forward the video.
         *
         * @private
         */
        _onFastForward: function () {
            if (this.playerInterface.isPaused() ||
                this.playerInterface.isPlaying() && this._playbackStatus.active) {

                if (!PlayerManager.isTrickplayEnabled()) {
                    this._showSeekingNotSupportedMessage();
                    return;
                }

                if (!this._canFastForward()) {
                    this._showSeekingProhibitedMessage();
                    return;
                }

                this._seeking = Constants.PLAYER_SEEK_DIRECTION_FORWARD;
                this._view.setProgressMaxPointerPosition();

                // Stop progress timeouts before starting fast forward.
                this._stopProgressTimeouts();
                this._seeker.fastForward();
            }
        },

        /**
         * Stops restart and live progress timeouts.
         *
         * @private
         */
        _stopProgressTimeouts: function () {
            this._stopRestartProgressTimeout();
            this._stopLiveProgressTimeout();
        },

        /**
         * Stops the live progress timeout.
         *
         * @private
         */
        _stopLiveProgressTimeout: function () {
            clearInterval(this._liveProgressInterval);
        },

        /**
         * Stops the replay progress timeout.
         *
         * @private
         */
        _stopRestartProgressTimeout: function () {
            clearInterval(this._liveProgressInterval);
        },

        /**
         * Function solves selecting record button.
         *
         * @private
         */
        _onRecord: function () {
            var program = this._program,
                view = this._view,
                config = {
                    text: l10n.get('player.warningbox.recording'),
                    icon: 'icon-alert-v2'
                },
                hasRecording = recordingManager.hasRecording(program.getId(), program.getSeriesId()),
                flow = hasRecording.episode || hasRecording.series ? 'delete' : 'default';

            if (featureManager.isRecordingEnabled()) {

                if (hasRecording.episode || hasRecording.series) {

                    // Deleting of recordings only allowed from recording section.
                    view.showWarningBox({
                        happy: true,
                        icon: 'icon-check-v2',
                        text: l10n.get('player.warningbox.alreadyrecording')
                    });
                } else {
                    if (program && program.canRecord()) {
                        this._view.hideUI({
                            skipAnim: true
                        });
                        application.route('record', {
                            item: program,
                            callingComponent: 'player',
                            callback: Utils.bind(this._onRecordCallback, this),
                            flow: flow
                        });
                    }
                }
            } else {
                view.showWarningBox(config);
            }
        },

        /**
         * Returns true if the stream can be fast forwarded.
         *
         * @returns {boolean} - True if the stream can be fast forwarded.
         * @private
         */
        _canFastForward: function () {
            var trickplaySettings = PlayerManager.getTrickplaySettings(),
                maxSeekTime = trickplaySettings.maxSeekValue,
                startTime = trickplaySettings.startTime * 1000,
                livePosition = trickplaySettings.currentLivePosition - startTime;

            if (!PlayerManager.isTrickplayEnabled()) {
                return false;
            }

            if (!this._program.canSeek()) {

                if (!this._pauseTime) {
                    return false;
                }

                return livePosition < maxSeekTime * 1000;
            }

            return true;
        },

        /**
         * Shows menu.
         *
         * @private
         */
        _onShownMenu: function () {
            this._view.closeExpandedContents();
            this._view.hideUI({
                skipAnim: true
            });
            application.focusMenu('player');
        },

        /**
         * Shows or hides current program's info.
         *
         * @param {boolean} show - Flag to show or hide program info.
         * @param {Object} programDetails - Program info details.
         * @private
         */
        _onInfo: function (show, programDetails) {
            GA.onEvent(
                Constants.ANALYTICS_EVENT_CATEGORY_ACTION,
                Constants.ANALYTICS_EVENT_ACTION_OPEN_DETAILS,
                {
                    eventLabel: AppUtils.getAnalyticsEventLabel(this._type)
                }
            );

            this._view.showUI(true);
            this._view.showProgramInfo(show, programDetails);
        },

        /**
         * Shows or hides the miniEPG.
         */
        _onMiniEPG: function () {
            this._view.showUI(true);
            this._view.showMiniEPG(false);
            this._view.getMiniEPG().focus();
        },

        /**
         * On mini epg program selected.
         *
         * @param {Object} channel - The selected program's channel to switch.
         * @private
         */
        _onMiniEPGProgram: function (channel) {
            this._view.focus();
            this._view.closeExpandedContents();
            this._zapToChannel(channel);

            GA.onEvent(
                Constants.ANALYTICS_EVENT_CATEGORY_ACTION,
                Constants.ANALYTICS_EVENT_ACTION_MINIEPG_PROGRAM,
                {
                    eventLabel: Constants.ANALYTICS_EVENT_LABEL_TYPE_LIVETV
                });
        },

        /**
         * Cancel mini epg selection after childlock esceped or cancelled.
         *
         * @private
         */
        _onMiniEPGCancelled: function () {
            this._view.focus();
            this._view.getMiniEPG().focus();
        },

        /**
         * Returns true if the stream can be rewound.
         *
         * @returns {boolean} - True if the stream can be rewound.
         * @private
         */
        _canRewind: function () {
            return PlayerManager.isTrickplayEnabled();
        },

        /**
         * Shows the seeking prohibited message.
         *
         * @private
         */
        _showSeekingProhibitedMessage: function () {
            var config = {
                text: l10n.get('player.warningbox.seek'),
                icon: 'icon-alert-v2'
            };

            this._view.showWarningBox(config);
        },

        /**
         * Shows the seeking not supported message.
         *
         * @private
         */
        _showSeekingNotSupportedMessage: function () {
            var config = {
                text: l10n.get('player.warningbox.liveonseek'),
                icon: 'icon-alert-v2'
            };

            this._view.showWarningBox(config);
        },

        /**
         * The record callback.
         *
         * @param {Object} e - The record callback.
         * @private
         */
        _onRecordCallback: function (e) {
            var config = {
                    happy: true,
                    icon: 'icon-check-v2'
                },
                hasRecording = recordingManager.hasRecording(e.item.getId(), e.item.getSeriesId());

            if (e.removed) {
                if (e.item.getEndTime() * 1000 > application.getDate()) {

                    // Future item gets canceled.
                    config.text = l10n.get('recordings.notification.cancelled', {item: e.item.getTitle()});
                } else {

                    // Old items get removed.
                    config.text = l10n.get('recordings.notification.removed', {item: e.item.getTitle()});
                }

                if (hasRecording.episode || hasRecording.series) {
                    this._view.onRecording();
                } else {
                    this._view.onRecord();
                }
            } else {

                config.text = l10n.get('recordings.notification.successful.' + e.type, {series: e.item.getTitle()});
                this._view.onRecording();
            }

            this._view.showWarningBox(config);
        },

        /**
         * Shows the program is already recorded message.
         *
         * @param {Object} item - The item.
         * @private
         */
        _showProgramAlreadyRecorded: function (item) {
            var config = {
                icon: 'icon-alert-v2',
                text: l10n.get('recordings.notification.recording', {
                    series: item.getTitle()
                })
            };

            this._view.showWarningBox(config);
        },

        /**
         * Shows the program can not be recorded message.
         *
         * @param {Object} item - The item.
         * @private
         */
        _showProgramNotRecordable: function (item) {
            var config = {
                icon: 'icon-alert-v2',
                text: l10n.get('recordings.notification.not_recordable', {
                    series: item.getTitle()
                })
            };

            this._view.showWarningBox(config);
        },

        /**
         * Gets executed when the current time changes.
         *
         * @param {number|Object} data - The seek data.
         * @private
         */
        _onCurrentTimeChanged: function (data) {

            if (!this._seeker.isActive()) {
                return;
            }

            this._onSeekCurrentTime(data);
        }
    };
});