text: /**
   * @license
   * Copyright 2016 Google Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  goog.provide('shaka.ui.Overlay');
  
  goog.require('goog.asserts');
  goog.require('shaka.polyfill.installAll');
  goog.require('shaka.ui.Controls');
  goog.require('shaka.ui.TextDisplayer');
  
  
  /**
   * @param {!shaka.Player} player
   * @param {!HTMLElement} videoContainer
   * @param {!HTMLMediaElement} video
   * @param {!Object=} config This should follow the form of
   *   {@link shaka.extern.UIConfiguration}, but you may omit
   *   any field you do not wish to change.
   * @constructor
   * @export
   */
  shaka.ui.Overlay = function(player, videoContainer, video, config) {
    /** @private {!shaka.Player} */
    this.player_ = player;
  
    /** @private {!shaka.extern.UIConfiguration} */
    this.config_ = this.defaultConfig_();
  
    if (config) {
      shaka.util.ConfigUtils.mergeConfigObjects(
          this.config_, config, this.defaultConfig_(),
          /* overrides (only used for player config)*/ {}, /* path */ '');
    }
  
    // If a cast receiver app id has been given, add a cast button to the UI
    if (this.config_.castReceiverAppId &&
        !this.config_.overflowMenuButtons.includes('cast')) {
      this.config_.overflowMenuButtons.push('cast');
    }
  
    /** @private {!shaka.ui.Controls} */
    this.controls_ = new shaka.ui.Controls(
        player, videoContainer, video, this.config_);
  };
  
  
  /**
   * @return {!shaka.Player}
   * @export
   */
  shaka.ui.Overlay.prototype.getPlayer = function() {
    return this.player_;
  };
  
  
  /**
   * @return {!shaka.ui.Controls}
   * @export
   */
  shaka.ui.Overlay.prototype.getControls = function() {
    return this.controls_;
  };
  
  
  /**
   * Enable or disable the custom controls.
   *
   * @param {boolean} enabled
   * @export
   */
  shaka.ui.Overlay.prototype.setEnabled = function(enabled) {
    this.controls_.setEnabledShakaControls(enabled);
  };
  
  
  /**
   * @return {!shaka.extern.UIConfiguration}
   * @private
   */
  shaka.ui.Overlay.prototype.defaultConfig_ = function() {
    return {
      controlPanelElements: [
        'time_and_duration',
        'spacer',
        'mute',
        'volume',
        'fullscreen',
        'overflow_menu',
      ],
      overflowMenuButtons: [
        'captions',
        'quality',
        'language',
        'picture_in_picture',
        'cast',
      ],
      addSeekBar: true,
      castReceiverAppId: '',
    };
  };
  
  
  /**
   * @private
   */
  shaka.ui.Overlay.scanPageForShakaElements_ = function() {
    // Install built-in polyfills to patch browser incompatibilities.
    shaka.polyfill.installAll();
    // Check to see if the browser supports the basic APIs Shaka needs.
    if (!shaka.Player.isBrowserSupported()) {
      shaka.log.error('Shaka Player does not support this browser. ' +
        'Please see https://tinyurl.com/y7s4j9tr for the list of ' +
        'supported browsers.');
  
      return;
    }
  
    // Look for elements marked 'data-shaka-player-container'
    // on the page. These will be used to create our default
    // UI.
    const containers = document.querySelectorAll(
        '[data-shaka-player-container]');
    // Look for elements marked 'data-shaka-player'. They will
    // either be used in our default UI or with native browser
    // controls.
    const videos = document.querySelectorAll(
        '[data-shaka-player]');
  
    if (!videos.length && !containers.length) {
      // No elements have been tagged with shaka attributes.
    } else if (videos.length && !containers.length) {
      // Just the video elements were provided.
      for (let i = 0; i < videos.length; i++) {
        const video = videos[i];
        video.classList.add('video');
        goog.asserts.assert(video.tagName.toLowerCase() == 'video',
          'Should be a video element!');
  
        const container = document.createElement('div');
        const videoParent = video.parentElement;
        videoParent.replaceChild(container, video);
        container.appendChild(video);
  
        let castAppId = '';
  
        // If cast receiver application id was provided, pass it to the
        // UI constructor.
        if (video['dataset'] && video['dataset']['shakaPlayerCastReceiverId']) {
          castAppId = video['dataset']['shakaPlayerCastReceiverId'];
        }
  
        const videoAsMediaElement = /** @type {!HTMLMediaElement} */ (video);
        const ui = shaka.ui.Overlay.createUI_(
            /** @type {!HTMLElement} */ (container),
            videoAsMediaElement,
            {castReceiverAppId: castAppId});
  
        if (videoAsMediaElement.controls) {
          ui.getControls().setEnabledNativeControls(true);
        }
      }
    } else {
        for (let i = 0; i < containers.length; i++) {
        const container = containers[i];
        goog.asserts.assert(container.tagName.toLowerCase() == 'div',
          'Container should be a div!');
  
        let castAppId = '';
  
        // Cast receiver id can be specified on either container or video.
        // It should not be provided on both. If it was, we will use the last
        // one we saw.
        if (container['dataset'] &&
            container['dataset']['shakaPlayerCastReceiverId']) {
          castAppId = container['dataset']['shakaPlayerCastReceiverId'];
        }
  
        let video = null;
        for (let j = 0; j < videos.length; j++) {
          goog.asserts.assert(videos[j].tagName.toLowerCase() == 'video',
            'Should be a video element!');
          if (videos[j].parentElement == container) {
            video = videos[j];
            break;
          }
        }
  
        if (!video) {
          video = document.createElement('video');
          container.appendChild(video);
        }
  
        if (video['dataset'] && video['dataset']['shakaPlayerCastReceiverId']) {
          castAppId = video['dataset']['shakaPlayerCastReceiverId'];
        }
        shaka.ui.Overlay.createUI_(/** @type {!HTMLElement} */ (container),
                                   /** @type {!HTMLMediaElement} */ (video),
                                   {castReceiverAppId: castAppId});
      }
    }
  
    // After scanning the page for elements, fire the "loaded" event.  This will
    // let apps know they can use the UI library programmatically now, even if
    // they didn't have any Shaka-related elements declared in their HTML.
  
    // "Event" is not constructable on IE, so we use this CustomEvent pattern.
    const uiLoadedEvent = /** @type {!CustomEvent} */(
        document.createEvent('CustomEvent'));
    uiLoadedEvent.initCustomEvent('shaka-ui-loaded', false, false, null);
  
    document.dispatchEvent(uiLoadedEvent);
  };
  
  
  /**
   * @param {!HTMLElement} container
   * @param {!HTMLMediaElement} video
   * @param {!Object} config (Possibly partial) config in the form of
   *   {@link shaka.extern.UIConfiguration}
   * @return {!shaka.ui.Overlay}
   * @private
   */
  shaka.ui.Overlay.createUI_ = function(container, video, config) {
    const player = new shaka.Player(video);
    const ui = new shaka.ui.Overlay(player, container, video, config);
  
    // If the browser's native controls are disabled, use UI TextDisplayer. Right
    // now because the factory must be a constructor and () => {} can't be a
    // constructor.
    if (!video.controls) {
      player.configure(
          'textDisplayFactory',
          function() { return new shaka.ui.TextDisplayer(video, container); });
    }
  
    container['ui'] = ui;
    video['ui'] = ui;
    return ui;
  };
  
  
  if (document.readyState == 'complete') {
    // Don't fire this event synchronously.  In a compiled bundle, the "shaka"
    // namespace might not be exported to the window until after this point.
    Promise.resolve().then(shaka.ui.Overlay.scanPageForShakaElements_);
  } else {
    window.addEventListener('load', shaka.ui.Overlay.scanPageForShakaElements_);
  }
  