Source: models/epg/item.js

define('application/models/epg/item', [
    'product-layer/models/epg/item',
    'application/managers/channel',
    'antie/runtimecontext',
    'application/managers/api',
    'rofl/lib/utils',
    'application/managers/session',
    'antie/storageprovider',
    'application/managers/feature',
    'rofl/lib/l10n'
], function (
    EPGItem,
    ChannelManager,
    RuntimeContext,
    ApiManager,
    Utils,
    SessionManager,
    StorageProvider,
    FeatureManager,
    L10n
) {
    'use strict';

    var application = RuntimeContext.getCurrentApplication(),
        imageFormat = application && application.getLayout().imageFormat,
        imageEndpoint = ApiManager.getImageAPI('epg/') + '{{imageId}}/{{size}}.jpg',
        getDetailsAction = function (actions) {
            var i,
                j,
                detailsAction;

            for (i = 0, j = actions.length; i < j; i++) {

                if (actions[i].targetType === 'DETAILS_PAGE') {
                    detailsAction = actions[i].uri;
                    break;
                }
            }

            return detailsAction;
        },
        CONTENT_OPTIONS = {
            TRICKPLAY: 'TRICKPLAY',
            STARTOVER: 'STARTOVER',
            CATCHUP: 'CATCHUP',
            RECORDABLE: 'RECORDABLE'
        },
        l10n = L10n.getInstance();

    return EPGItem.extend({

        /**
         * Initialises the EPG Item.
         *
         * @param {Object} data - The data.
         * @param {Object} channel - The channel the epg item belongs to.
         */
        init: function (data, channel) {
            var metadata;

            data = Utils.isEmpty(data) ? this._createInfoNotAvailable(channel, data) : data;
            metadata = data.metadata;

            this._id = parseInt(metadata.contentId);
            this._title = metadata.title;
            this._titleBrief = metadata.titleBrief;
            this._startTime = metadata.airingStartTime / 1000;
            this._endTime = metadata.airingEndTime / 1000;
            this._channelName = metadata.channelName;
            this._channelId = channel.getId();
            this._assetId = channel.getAssetId();
            this._contentOptions = metadata.contentOptions;
            this._duration = metadata.duration;
            this._imageUrl = metadata.pictureUrl;
            this._videoRatings = metadata.pcExtendedRatings;
            this._channel = channel;
            this._detailsAction = getDetailsAction(data.actions || []);
            this._seriesId = parseInt(metadata.seriesId);
            this._pcLevel = parseInt(metadata.pcLevel);
            this._parentalGenres = metadata.pcExtendedRatings.length ? metadata.pcExtendedRatings : [];
            this._parentalWhitelisted = false;
            this._noEpgData = data.noEpgData;
            this._contentType = metadata.contentType || 'PROGRAM';
            this._contentType = metadata.contentType;
            this._contentSubtype = metadata.contentType;

            if (!imageFormat) {
                imageFormat = RuntimeContext.getCurrentApplication().getLayout().imageFormat;
            }

            if (this._pcLevel === 99) {
                this._pcLevel = 0;
            }

            this._streamOffset = 5 * 60; // Hardcode the stream offset.
        },

        /**
         * Creates epgData when missing.
         *
         * @param {Object} channel - The channel the epg item belongs to.
         * @param {Object} data - The data.
         * @returns {Object} - Epg item metadata.
         */
        _createInfoNotAvailable: function (channel, data) {
            var metadata = {},
                dataChannel = [],
                now = application.getDate(),
                duration = 3600000; // 1hr

            if (!Utils.isEmpty(data)) {
                metadata = data.metadata || {};
                dataChannel = data.channel || [];
            }

          return {
              id: data.id || '0',
              layout: data.layout || 'CONTENT_ITEM',
              actions: data.actions || [],
              metadata: {
                  contentId: metadata.contentId,
                  contentType: metadata.contentType || 'PROGRAM',
                  contentSubtype: metadata.contentSubtype || 'VOD',
                  title: l10n.get('asset.noinfoavailable'),
                  titleBrief: l10n.get('asset.noinfoavailable'),
                  pcExtendedRatings: metadata.pcExtendedRatings || [],
                  pcLevel: metadata.pcLevel || 99,
                  duration: metadata.duration || duration / 1000,
                  pictureUrl: metadata.pictureUrl || '',
                  season: metadata.season || 0,
                  externalId: metadata.externalId || '',
                  airingStartTime: metadata.airingStartTime || now,
                  airingEndTime: metadata.airingEndTime || now + duration,
                  contentOptions: metadata.contentOptions || []
              },
              technicalPackageIds: data.technicalPackageIds || [],
              channel: {
                  channelId: dataChannel.channelId || channel.getId && channel.getId(),
                  externalChannelId: dataChannel.externalChannelId || channel.getExternalId && channel.getExternalId(),
                  channelName: dataChannel.channelName || channel.getName && channel.getName(),
                  type: dataChannel.type || 'LIVE'
              },
              assets: data.assets || [],
              noEpgData: true
          };
        },

        /**
         * Returns the id.
         *
         * @returns {number} - The id.
         */
        getId: function () {
            return this._id;
        },

        /**
         * Returns the asset id.
         *
         * @returns {number} - The asset id.
         */
        getAssetId: function () {
            return this._assetId;
        },

        /**
         * Returns the title.
         *
         * @returns {string} - The title.
         */
        getTitle: function () {
            return this._title;
        },

        /**
         * Returns the title brief (short title).
         *
         * @returns {string} - The title brief.
         */
        getTitleBrief: function () {
            return this._titleBrief;
        },

        /**
         * Returns if EPG data is available.
         *
         * @returns {boolean} - True if noEpgData is set.
         */
        hasEpgData: function () {
            return !this._noEpgData;
        },

        /**
         * Returns the start time.
         *
         * @returns {number} - The start time.
         */
        getStartTime: function () {
            return this._startTime;
        },

        /**
         * Returns the end time.
         *
         * @returns {number} - The end time.
         */
        getEndTime: function () {
            return this._endTime;
        },

        /**
         * Returns the duration.
         *
         * @returns {number} - The duration.
         */
        getDuration: function () {
            return this._duration;
        },

        /**
         * Returns the channel name.
         *
         * @returns {string} - The channel name.
         */
        getChannelName: function () {
            return this._channelName;
        },

        /**
         * Returns the channel id.
         *
         * @returns {string} - The channel id.
         */
        getChannelId: function () {
            return this._channelId;
        },

        /**
         * Returns the content options.
         *
         * @returns {Object} - The content options.
         */
        getContentOptions: function () {
            return this._contentOptions;
        },

        /**
         * Returns the channel.
         *
         * @returns {Object} - The channel.
         */
        getChannel: function () {
            return this._channel;
        },

        /**
         * Returns the background.
         *
         * @param {string} orientation - Orientation.
         * @param {Object} [dimensions] - The dimensions. Should contain width and height.
         * @returns {string|null} - The background url or null if not available.
         * @private
         */
        getImage: function (orientation, dimensions) {
            var format,
                size;

            if (!this._imageUrl) {
                return null;
            }

            orientation = orientation || 'landscape'; // Default to landscape image.

            if (orientation === 'manual') {
                size = dimensions.width + 'x' + dimensions.height;
            } else {
                format = imageFormat[orientation];
                size = Math.round(format.width) + 'x' + Math.round(format.height);
            }

            return Utils.formatTemplate(imageEndpoint, {
                imageId: this._imageUrl,
                size: size
            });
        },

        /**
         * Returns URL of preview image.
         *
         * @param {string} size - Size of the image.
         * @returns {string} - URL of preview image.
         */
        getImageUrl: function (size) {
            size = size || imageFormat.landscape.width + 'x' + imageFormat.landscape.height;

            // Prevents unnecessary calls to image api when there's no imageUrl.
            if (!this._imageUrl) {
                return this._imageUrl;
            }

            return Utils.formatTemplate(imageEndpoint, {
                imageId: this._imageUrl,
                size: size
            });
        },

        /**
         * Returns the video ratings.
         *
         * @returns {Array} - The video ratings.
         */
        getVideoRatings: function () {
            return this._videoRatings;
        },

        /**
         * Returns the details action.
         *
         * @returns {string} - The details action url.
         */
        getDetailsAction: function () {
            return this._detailsAction;
        },

        /**
         * Returns the channel logo.
         *
         * @returns {string} - The channel logo.
         */
        getChannelLogo: function () {
            return this.getChannel().getImage(128);
        },

        /**
         * Returns true if the video can be played.
         *
         * @returns {boolean} - True if the video can be played.
         */
        canPlay: function () {

            if (this.isLive()) {

                // Program is currently playing and can be restarted.
                return true;
            } else if (this.isReplayItem()) {

                // Program is finished and can be caught up.
                return this.canCatchup();
            }

            // Program is in the future and can't be watched.
            return false;
        },

        /**
         * Returns true if the video is currently playing.
         *
         * @returns {boolean} - True if the video is currently playing.
         */
        isLive: function () {
            var now = application.getDate() / 1000;

            return this.getStartTime() < now && this.getEndTime() > now;
        },

        /**
         * Returns true if the item is a replay item.
         *
         * @returns {boolean} - True if the item is a replay item.
         */
        isReplayItem: function () {
            var now = application.getDate() / 1000;

            return this.getEndTime() < now;
        },

        /**
         * Returns true if the video can be caught up.
         *
         * @returns {boolean} - True if can be caught up.
         */
        canCatchup: function () {
            return this._contentOptions.indexOf(CONTENT_OPTIONS.CATCHUP) >= 0;
        },

        /**
         * Returns true if seeking is allowed.
         *
         * @returns {boolean} - True if seeking is allowed.
         */
        canSeek: function () {
            return this._contentOptions.indexOf(CONTENT_OPTIONS.TRICKPLAY) >= 0;
        },

        /**
         * Returns true if recording is allowed.
         *
         * @returns {boolean} - True if recording is allowed.
         */
        canRecord: function () {
            return this._contentOptions.indexOf(CONTENT_OPTIONS.RECORDABLE) >= 0;
        },

        /**
         * Returns the series id.
         *
         * @returns {number} - The series id.
         */
        getSeriesId: function () {
            return this._seriesId;
        },

        /**
         * Returns parental control level.
         *
         * @returns {number} - Parental control level.
         */
        getPCLevel: function () {

            return this._pcLevel;
        },

        /**
         * Returns parental genres.
         *
         * @returns {Array} - Parental genres.
         */
        getParentalGenres: function () {
            return this._parentalGenres;
        },

        /**
         * Sets program to be parental whitelisted.
         */
        setParentalWhitelisted: function () {
            this._parentalWhitelisted = true;
        },

        /**
         * Gets if program is whitelisted.
         *
         * @returns {boolean} - If is whitelisted.
         */
        getParentalWhitelisted: function () {
            return this._parentalWhitelisted;
        },

        /**
         * Returns the recording starttime.
         *
         * @returns {number|null} - The stream offset.
         */
        getStreamOffset: function () {
            return this._streamOffset;
        },

        /**
         * Returns true if the broadcast is locked.
         *
         * @returns {boolean} - True if the broadcast is locked.
         */
        isLocked: function () {
            var parentalControlParams = SessionManager.getInstance().getUserPCParams(),
                parentalControlOn = SessionManager.getInstance().isParentalOn(),
                parentalControlLevel = parseInt(Utils.getNested(parentalControlParams, 'parentalControlLevel')),
                parentalControlGenres = Utils.getNested(parentalControlParams, 'parentalGenres'),
                i,
                self = this,
                isGenreProtected = function () {
                    if (parentalControlGenres.length) {
                        for (i = 0; i < parentalControlGenres.length; i++) {
                            if (self.getParentalGenres().indexOf(parentalControlGenres[i]) > -1) {
                                return true;
                            }
                        }
                    }
                    return false;
                },
                isLocked = false,
                VODContentTypes = ['VOD', 'GROUP_OF_BUNDLES', 'BUNDLE'];

            if (VODContentTypes.indexOf(this.getContentType()) >= 0) {
                parentalControlLevel = parseInt(Utils.getNested(parentalControlParams, 'parentalVODControlLevel'));
            }

            if (!FeatureManager.getInstance().isParentalEnabled() || !parentalControlOn) {
                isLocked = false;
            } else {
                isLocked = !(parentalControlLevel >= this.getPCLevel()) || isGenreProtected();
            }

            return isLocked;
        },

        /**
         * Returns true if the stream requires to be requested with pin.
         *
         * @returns {boolean} - True if stream requires pin.
         */
        streamRequiresPin: function () {
            var parentalControlParams = SessionManager.getInstance().getUserPCParams(),
                parentalControlLevel = parseInt(Utils.getNested(parentalControlParams, 'parentalControlLevel')),
                parentalControlGenres = Utils.getNested(parentalControlParams, 'parentalGenres'),
                genres = this.getParentalGenres(),
                isGenreProtected,
                VODContentTypes = ['VOD', 'GROUP_OF_BUNDLES', 'BUNDLE'];

            if (VODContentTypes.indexOf(this.getContentType()) >= 0) {
                parentalControlLevel = parseInt(Utils.getNested(parentalControlParams, 'parentalVODControlLevel'));
            }

            isGenreProtected = function () {
                var i;

                if (parentalControlGenres.length) {
                    for (i = 0; i < parentalControlGenres.length; i++) {
                        if (genres.indexOf(parentalControlGenres[i]) > -1) {
                            return true;
                        }
                    }
                }
                return false;
            };

            return !(parentalControlLevel >= this.getPCLevel()) || isGenreProtected();
        },

        /**
         * Returns true if the item is playable.
         *
         * @returns {boolean} - True if the item is playable.
         */
        isPlayable: function () {
            var now = application.getDate().getTime(),
                endTime = this.getEndTime() * 1000,
                replayBuffer = 15 * 60 * 1000;

            return (now - endTime > replayBuffer);
        },

        /**
         * Returns the content type.
         *
         * @returns {string} - The content type.
         */
        getContentType: function () {
            return this._contentType;
        },

        /**
         * Returns the content type.
         *
         * @returns {string} - The content type.
         */
        getContentSubtype: function () {
            return this._contentSubtype;
        }
    });
});