Source: widgets/asset/asset.js

define('application/widgets/asset/asset', [
    'application/widgets/pointerfocusableasset',
    'application/widgets/asset/progressbar',
    'application/widgets/loader',
    'application/managers/session',
    'application/managers/feature',
    'application/utils',
    'rofl/widgets/container',
    'rofl/widgets/label',
    'rofl/lib/utils',
    'rofl/lib/l10n',
    'antie/runtimecontext',
    'application/managers/bookmark'
], function (
    Button,
    ProgressBar,
    Loader,
    SessionManager,
    FeatureManager,
    AppUtils,
    Container,
    Label,
    Utils,
    L10N,
    RuntimeContext,
    BookmarkManager
) {
    'use strict';

    var device = RuntimeContext.getDevice(),
        app = RuntimeContext.getCurrentApplication(),
        l10n = L10N.getInstance();

    /**
     * Base Widget for every asset in the app.
     */
    return Button.extend({

        /**
         * Initialises the widget.
         *
         * @param {Object} data - The data.
         * @param {Object} data.item - Contains the model item.
         * @param {string} data.title - The title for this assset.
         * @param {string} data.subtitle - The subtitle for this asset.
         * @param {string} data.lockedTitle - The title for this asset when locked.
         * @param {string} [data.logo] - The logo url.
         * @param {string} data.background - The image url.
         * @param {string} [data.lockedBackground] - The locked image url.
         * @param {number} [data.startTime] - The content's start time.
         * @param {number} [data.endTime] - The content's end time.
         * @param {string} [data.topRightIcon] - The top right icon classname.
         * @param {string} [data.bottomRightIcon] - The bottom right icon classname.
         * @param {string} [data.topLeftText] - Top left text to show.
         * @param {boolean} [data.gradient] - True if the gradient should show.
         * @param {boolean} [data.progressbar] - True if the progressbar should show.
         * @param {boolean} [data.setBookmarkProgress] - True if the progressbar should be filled with bookmark time.
         * @param {boolean} [data.playOnSelect] - True if the asset should skip details and play after selected.
         */
        init: function init (data) {
            init.base.call(this);
            this._isLocked = false;

            this.addClass('asset');
            this.setDataItem(data);
            this._setListeners(data.listeners);
        },

        /**
         * Sets listeners for the asset.
         *
         * @param {Array} [listeners] - Array of objects that contains any custom listener.
         * @private
         */
        _setListeners: function (listeners) {
            var boundListener,
                listenerEvName,
                listenerEvHandler;

            this._listeners = [];

            Utils.each(listeners, Utils.bind(function (listener) {
                listenerEvName = listener.evName;
                listenerEvHandler = listener.evHandler;

                boundListener = Utils.bind(listenerEvHandler, this, this);

                this._listeners.push({
                    evName: listenerEvName,
                    evHandler: boundListener
                });

                app.addEventListener(listener.evName, boundListener);
            }, this));
        },


        /**
         * Remove listeners for the asset.
         *
         * @private
         */
        _removeListeners: function () {
            Utils.each(this._listeners, function (listener) {
                app.removeEventListener(listener.evName, listener.evHandler);
            });
        },

        /**
         * Sets the data.
         */
        setData: function () {
            var data = this.getDataItem(),
                showLockedTitles = Utils.getNested(SessionManager.getInstance().getUserPCParams(), 'showLockedTitles'),
                title = data.title,
                lockedTitle = data.lockedTitle || l10n.get('asset.locked'),
                background = data.background;

            if (this.isLocked()) {
                title = showLockedTitles ? title : lockedTitle;
                background = data.lockedBackground;
            }

            this._setBackground(background);
            if (!this._metadata) {
                this._buildMetadataContainer();
            }
            this._setGradient(data.gradient);
            this._setTitle(title);
            this._setSubTitle(data.subTitle);
            this._setSubTitle2(data.subTitle2);
            this._setLogo(data.logo);
            this._setTopRightIcon(data.topRightIcon);
            this._setBottomRightIcon(data.bottomRightIcon);
            this._setTopLeftText(data.topLeftText);
            this._setProgressBar(data.progressbar);
        },

        /**
         * Sets locked background.
         */
        setLockedBackground: function () {
            if (!this._lockedContainer) {
                this._buildLockedContainer();
                this.insertChildWidget(0, this._lockedContainer);
                this._lockedContainer.render(device);
            }

            if (!this._lockedIcon) {
                this._buildLockedIcon();
                this._lockedContainer.appendChildWidget(this._lockedIcon);
                this._lockedIcon.render(device);
            }

            if (this._placeholder) {
                this._placeholder.hide();
            }

            this._lockedContainer.show();
            this._lockedIcon.show();
        },

        /**
         * Sets the title.
         *
         * @param {string} title - The title.
         * @private
         */
        _setTitle: function (title) {
            if (title) {
                if (!this._title) {
                    this._buildTitle();
                }

                this._title.render(device);
                this._title.setText(title);
                this._metadata.appendChildWidget(this._title);
            }
        },

        /**
         * Sets the subtitle.
         *
         * @param {string} subTitle - The subtitle.
         * @private
         */
        _setSubTitle: function (subTitle) {
            if (subTitle) {
                if (!this._subTitle) {
                    this._buildSubTitle();
                }

                this._subTitle.render(device);
                this._subTitle.setText(subTitle);
                this._metadata.appendChildWidget(this._subTitle);
            }
        },

        /**
         * Sets the second subtitle.
         *
         * @param {string} subTitle2 - The second subtitle.
         * @private
         */
        _setSubTitle2: function (subTitle2) {
            if (subTitle2) {
                if (!this._subTitle2) {
                    this._buildSubTitle2();
                }

                this._subTitle2.render(device);
                this._subTitle2.setText(subTitle2);
                this._metadata.appendChildWidget(this._subTitle2);
            }
        },

        /**
         * Sets the top right icon.
         *
         * @param {string} icon - The icon.
         * @private
         */
        _setTopRightIcon: function (icon) {
            if (icon) {
                if (!this._topRightIcon) {
                    this._buildTopRightIcon();
                }

                this._topRightIcon.render(device);
                this._toprightGradient.render(device);

                this._topRightIcon.removeClass(this._previousTopRightIcon);
                this._topRightIcon.addClass(icon);
                this._previousTopRightIcon = icon;

                this.appendChildWidget(this._toprightGradient);
                this.appendChildWidget(this._topRightIcon);
            } else if (this._topRightIcon) {
                this.removeChildWidget(this._toprightGradient);
                this.removeChildWidget(this._topRightIcon);
            }
        },

        /**
         * Sets the bottom right icon.
         *
         * @param {Object} icon - The icon.
         * @param {string} [icon.textIcon] - The icon as text.
         * @param {string} [icon.classIcon] - The icon as classname.
         * @private
         */
        _setBottomRightIcon: function (icon) {
            var hasIcon = icon && (icon.textIcon || icon.classIcon);

            if (hasIcon) {
                if (!this._bottomRightIcon) {
                    this._buildBottomRightIcon();
                }

                this._bottomRightIcon.render(device);

                if (icon.textIcon) {
                    this._bottomRightIcon.setText(icon.textIcon);
                } else {
                    this._bottomRightIcon.addClass(icon.classIcon);
                }

                this.appendChildWidget(this._bottomRightIcon);
            }
        },

        /**
         * Sets the top left text.
         *
         * @param {string} text - The top left text.
         * @private
         */
        _setTopLeftText: function (text) {
            if (text) {
                if (!this._topLefttText) {
                    this._buildTopLeftText();
                }

                this._topLefttText.render(device);
                this._topLefttText.setText(text);
                this.appendChildWidget(this._topLefttText);
            }
        },

        /**
         * Sets the background image.
         *
         * @param {string} url - The image url.
         * @private
         */
        _setBackground: function (url) {
            var self = this,
                image;

            if (!this._background) {
                this._buildBackground();
                this.appendChildWidget(this._background);
            }

            if (this.isLocked() && !url) {
                this.setLockedBackground();
            } else if (url) {
                this._buildPlaceholder();

                image = new Image();
                image.onload = function () {
                    self._setImage();
                    image.onload = null;
                    delete image.onload;
                };

                image.onerror = function () {
                    self._loader.hide();
                    image.onerror = null;
                    delete image.onerror;
                };

                image.src = url;
            }
        },

        /**
         * Sets the logo.
         *
         * @param {string} url - The logo url.
         * @private
         */
        _setLogo: function (url) {
            if (url) {
                if (!this._logo) {
                    this._buildLogo();
                    this.appendChildWidget(this._logo);
                }

                this._logo.render(device);
                this._logo.setStyleTo('backgroundImage', 'url(' + url + ')');
            }
        },

        /**
         * Sets the gradient.
         *
         * @param {boolean} gradient - True if the gradient should show.
         * @private
         */
        _setGradient: function (gradient) {
            if (gradient) {
                if (!this._gradient) {
                    this._buildGradient();
                }

                this._gradient.render(device);
                this.appendChildWidget(this._gradient);
            }
        },

        /**
         * Sets the content's progressbar.
         *
         * @param {boolean} progressbar - True if progressbar is to be set.
         * @private
         */
        _setProgressBar: function (progressbar) {
            if (progressbar) {
                if (!this._progressBar) {
                    this._buildProgressBar();
                    this.appendChildWidget(this._progressBar);
                    this._progressBar.render(device);
                }

                this._progressBar.setIsLive(true);
                this.updateProgressBar();
            } else if (this._progressBar) {
                this.removeChildWidget(this._progressBar);
                delete this._progressBar;
            }
        },

        /**
         * Updates the content's progressbar.
         *
         * @returns {boolean} - Progress complete.
         */
        updateProgressBar: function () {
            var percentage,
                dataItem,
                bookmarkTime,
                contentItem;

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

            dataItem = this.getDataItem();
            contentItem = dataItem.item;

            // Set bookmark progress or current time progress.
            if (dataItem.setBookmarkProgress) {
                bookmarkTime = BookmarkManager.getBookmark(contentItem.getId(), contentItem.getContentType());
                percentage = this._getBookmarkPercentage(contentItem.getDuration(), bookmarkTime);
            } else {
                percentage = this._getPercentage(dataItem.startTime, dataItem.endTime);
            }

            if (this._progressBar) {
                this._progressBar.setProgress(percentage);
            }

            return true;
        },

        /**
         * Returns the progressBar percentage.
         *
         * @param {Date} startTime - The startTime.
         * @param {Date} endTime - The end time.
         * @returns {number} - The percentage.
         * @private
         */
        _getPercentage: function (startTime, endTime) {
            var now = app.getDate(),
                percentage,
                allTime,
                passedTime;

            allTime = endTime - startTime;
            passedTime = now - startTime;
            percentage = Math.round((passedTime * 100) / allTime);

            return percentage;
        },

        /**
         * Returns the progressBar percentage.
         *
         * @param {number} duration - The content's duration.
         * @param {number} bookmark - The bookmark time.
         * @returns {number} - The percentage.
         * @private
         */
        _getBookmarkPercentage: function (duration, bookmark) {
            return Math.round((bookmark * 100) / duration);
        },

        /**
         * Builds the placeholder.
         *
         * @private
         */
        _buildPlaceholder: function () {
            var placeholder = this._placeholder,
                loader = this._loader;

            if (!placeholder) {
                placeholder = this._placeholder = new Container();
                loader = this._loader = new Loader();

                loader.addClass('small-loader');
                placeholder.addClass('asset-placeholder');
                placeholder.appendChildWidget(loader);
                this.appendChildWidget(placeholder);
            }

            placeholder.render(device);
            loader.show();
            placeholder.show();
        },

        /**
         * Sets the background image after loading.
         *
         * @private
         */
        _setImage: function () {
            var data = this.getDataItem(),
                isLocked = this.isLocked(),
                background = data.background;

            if (!this._background.rendered) {
                this._background.render(device);
                this._background.rendered = true;
            }

            if (isLocked) {
                background = data.lockedBackground;

                if (!this._lockedIcon) {
                    this._buildLockedIcon();
                    this._background.appendChildWidget(this._lockedIcon);
                } else if (!this._lockedIcon.parentWidget) {
                    this._background.appendChildWidget(this._lockedIcon);
                }
            } else if (this._lockedIcon) {

                // Remove locked icon.
                this._background.removeChildWidgets();

                // Remove locked container.
                if (this._lockedContainer) {
                    this._lockedContainer.hide();
                }
            }

            this._background.setStyleTo('backgroundImage', 'url(' + background + ')');

            this._loader.hide({ skipAnim: true });
            this._placeholder.hide({ skipAnim: true });
        },

        /**
         * Renders the widget.
         *
         * @param {Object} d - The device.
         * @returns {Object} - The output element.
         */
        render: function render (d) {
            var outputElement = render.base.call(this, d);

            if (!this.rendered) {
                this.rendered = true;
                this.setData();
            }

            return outputElement;
        },

        /**
         * Builds the widget.
         *
         * @private
         */
        _build: function () {
            this._buildBackground();
            this._buildTitle();
            this._buildLogo();
            this._buildSubTitle();
            this._buildSubTitle2();
            this._buildBottomRightIcon();
            this._buildTopRightIcon();
            this._buildTopLeftText();
            this._buildGradient();
            this._buildProgressBar();
        },

        /**
         * Builds the metadata container (for title, subtitle, subtitle 2, etc..).
         *
         * @private
         */
        _buildMetadataContainer: function () {
            var metadata = this._metadata = new Container();

            metadata.addClass('metadata-container');

            this.appendChildWidget(metadata);
        },

        /**
         * Builds the locked icon.
         *
         * @private
         */
        _buildLockedIcon: function () {
            var lockedIcon = this._lockedIcon = new Container();

            lockedIcon.addClass(['locked-icon', 'icon-lock']);
        },

        /**
         * Builds the locked icon.
         *
         * @private
         */
        _buildLockedContainer: function () {
            var lockedContainer = this._lockedContainer = new Container();

            lockedContainer.addClass('locked-container');
        },

        /**
         * Builds the background.
         *
         * @private
         */
        _buildBackground: function () {
            var background = this._background = new Container();

            background.addClass('background');
        },

        /**
         * Builds the logo.
         *
         * @private
         */
        _buildLogo: function () {
            var logo = this._logo = new Container();

            logo.addClass('logo');
        },

        /**
         * Builds the title.
         *
         * @private
         */
        _buildTitle: function () {
            this._title = new Label({ text: '', classNames: ['title'] });
        },

        /**
         * Builds the subtitle.
         *
         * @private
         */
        _buildSubTitle: function () {
            var subTitleClassNames = this.getDataItem().classNames.subTitle,
                classNames = ['subtitle'];

            if (subTitleClassNames) {
                classNames = classNames.concat(subTitleClassNames);
            }

            this._subTitle = new Label({ text: '', classNames: classNames });
        },

        /**
         * Builds the second subtitle.
         *
         * @private
         */
        _buildSubTitle2: function () {
            var subTitle2ClassNames = this.getDataItem().classNames.subTitle2,
                classNames = [];

            if (subTitle2ClassNames) {
                classNames = classNames.concat(subTitle2ClassNames);
            }

            this._subTitle2 = new Label({ text: '', classNames: classNames });
        },

        /**
         * Builds the bottom right icon.
         *
         * @private
         */
        _buildBottomRightIcon: function () {
            var bottomRightIconClassNames = this.getDataItem().classNames.bottomRightIcon,
                classNames = ['icon', 'bottomright'];

            if (bottomRightIconClassNames) {
                classNames = classNames.concat(bottomRightIconClassNames);
            }

            this._bottomRightIcon = new Label({ text: '', classNames: classNames });
        },

        /**
         * Builds the top right icon.
         *
         * @private
         */
        _buildTopRightIcon: function () {
            this._topRightIcon = new Label({ text: '', classNames: ['icon', 'topright'] });
            this._toprightGradient = new Container();

            this._toprightGradient.addClass('topright-gradient');
        },

        /**
         * Builds the top left text.
         *
         * @private
         */
        _buildTopLeftText: function () {
            var topLeftTextClassNames = this.getDataItem().classNames.topLeftText,
                classNames = ['topleft'];

            if (topLeftTextClassNames) {
                classNames = classNames.concat(topLeftTextClassNames);
            }

            this._topLefttText = new Label({ text: '', classNames: classNames });
        },

        /**
         * Builds the gradient.
         *
         * @private
         */
        _buildGradient: function () {
           this._gradient = new Label({ text: '', classNames: ['gradient'] });
        },

        /**
         * Builds the progressBar.
         *
         * @private
         */
        _buildProgressBar: function () {
            this._progressBar = new ProgressBar();
        },

        /**
         * Disposes the widget.
         */
        dispose: function dispose () {
            var self = this,
                dataItem = this.getDataItem(),
                listeners = dataItem.listeners;

            if (listeners) {
                this._removeListeners(listeners);
            }

            Utils.each(self, function (item, key) {

                if (item) {
                    if (typeof item.dispose === 'function') {
                        item.dispose();
                    }
                }

                self[key] = null;
                delete self[key];
            });

            dispose.base.call(this);
        },

        /**
         * Checks whether asset is child protected.
         *
         * @returns {boolean} - True if is child protected.
         */
        isLocked: function () {
            var assetItem = Utils.getNested(this.getDataItem(), 'item');

            this._isLocked = AppUtils.isBroadcastLocked(assetItem);

            return this._isLocked;
        },

        /**
         * For the rendered assets remove the locked container and set background and title.
         */
        unlock: function () {
            var data = this.getDataItem(),
                background = data.background;

            if (background) {

                // Remove blurred query param from the background url.
                data.background = background.replace('?blurred=true', '');
            }

            if (!this.rendered || !this._isLocked) {
                return;
            }

            this._setBackground(data.background);
            this._setTitle(data.title);
        },

        lock: function () {
            var data = this.getDataItem(),
                showLockedTitles = Utils.getNested(SessionManager.getInstance().getUserPCParams(), 'showLockedTitles'),
                lockedTitle = data.lockedTitle || l10n.get('asset.locked'),
                title = showLockedTitles ? data.title : lockedTitle;

            if (!this.rendered || !this.isLocked()) {
                return;
            }

            this._locked = true;
            this._setBackground(data.lockedBackground);
            this._setTitle(title);
        },

        /**
         * Checks if asset should play after select.
         *
         * @returns {boolean} - Returns true if asset should play after selecting.
         */
        playOnSelect: function () {
            return this.getDataItem().playOnSelect;
        }
    });
});