Source: decorators/player/manipulation.js

define('application/decorators/player/manipulation', [
    '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'
], 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(),
        TYPES = {
            LIVE: 'LIVE',
            VOD: 'VOD',
            VOD_MOVIE: 'VOD_MOVIE',
            RESTART: 'RESTART',
            RECORDING: 'RECORDING'
        },
        SEEKING = {
            forward: 'forward',
            rewind: 'rewind'
        };

    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 === TYPES.LIVE) {
                    this._delayedStreamTime = this._pauseTime;
                    this._onRestart();
                } else {
                    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();
                if (this._type === TYPES.LIVE) {
                    this._stopRestartProgressTimeout();
                    this._startLiveProgressTimeOut();
                }
            } else if (this.playerInterface.isPaused()) {
                this._onPlay();
            }
        },

        _onRestart: function () {
            if (this.playerInterface.isPaused() ||
                this.playerInterface.isPlaying() && this._playbackStatus.active) {
                if (this._seeker.isActive()) {
                    this._seeker.cancel();
                    this._view.resetControls();
                }

                this.playerInterface.seek(0);

                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 = SEEKING.rewind;
                this._seeker.rewind();
            }
        },

        /**
         * 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 = SEEKING.forward;
                this._view.setProgressMaxPointerPosition();
                this._seeker.fastForward();
            }
        },

        /**
         * 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()) {
                        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,
                currentTime;

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

            if (!this._program.canSeek()) {
                currentTime = this._seekCurrentTime !== null ? this._seekCurrentTime : this.playerInterface.getCurrentTime();

                return currentTime < maxSeekTime;
            }

            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) {
            this._sendOpenInfoAnalytics();

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

        /**
         * On Next episode button pressed.
         *
         * @param {Object} nextEpisode - The episode to watch.
         */
        _onNextEpisode: function (nextEpisode) {
            this._sendNextEpisodeAnalytics();

            if (this._seeker.isActive()) {
                this._seeker.cancel();
                this._view.resetControls();
            }
            application.showLoader(true);
            this._preparePlayer({
                data: nextEpisode
            });
        },

        /**
         * Returns to live broadcast.
         */
        _onLive: function () {
            this._playChannel(this._program.getChannelId());
            this._view.getControls().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 speed changes.
         *
         * @param {number} speed - The speed.
         * @private
         */
        _onSpeedChanged: function (speed) {
            this._seekSpeed = speed;

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

        /**
         * 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);
        }
    };
});