"use strict";
/* eslint-disable */
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Media = exports.handledMediaEventsMap = exports.getKeyFromSource = exports["default"] = void 0;

var _dispatcher = require("@enact/core/dispatcher");

var _handle = require("@enact/core/handle");

var _propTypes = _interopRequireDefault(require("@enact/core/internal/prop-types"));

var _propTypes2 = _interopRequireDefault(require("prop-types"));

var _react = _interopRequireDefault(require("react"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }

function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }

function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

/**
 * Generates a key representing the source node or nodes provided
 *
 * Example:
 * ```
 * getKeyFromSource('path/file.mp4'); // 'path/file.mp4'
 * getKeyFromSource(
 * 	<source src="path/file.mp4" type="video/mp4" />
 * ); // 'path/file.mp4'
 * getKeyFromSource([
 * 	<source src="path/file.mp4" type="video/mp4" />,
 * 	<source src="path/file.ogg" type="video/ogg" />,
 * ]); // 'path/file.mp4+path/file.ogg'
 * ```
 *
 * @function
 * @param   {String|Element|Element[]} source URI for a source, `<source>` node, or array of
 *                                     `<source>` nodes
 * @returns {String}                   Key representing sources
 * @memberof ui/Media
 * @public
 */
var getKeyFromSource = function getKeyFromSource() {
  var source = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';

  if ( /*#__PURE__*/_react["default"].isValidElement(source)) {
    return _react["default"].Children.toArray(source).filter(function (s) {
      return !!s;
    }).map(function (s) {
      return s.props.src;
    }).join('+');
  }

  return String(source);
};
/**
 * Maps standard media event `type` values to React-style callback prop names
 *
 * See https://reactjs.org/docs/events.html#media-events
 *
 * ```
 * {
 *   abort           : 'onAbort',
 *   canplay         : 'onCanPlay',
 *   canplaythrough  : 'onCanPlayThrough',
 *   durationchange  : 'onDurationChange',
 *   emptied         : 'onEmptied',
 *   encrypted       : 'onEncrypted',
 *   ended           : 'onEnded',
 *   error           : 'onError',
 *   loadeddata      : 'onLoadedData',
 *   loadedmetadata  : 'onLoadedMetadata',
 *   loadstart       : 'onLoadStart',
 *   pause           : 'onPause',
 *   play            : 'onPlay',
 *   playing         : 'onPlaying',
 *   progress        : 'onProgress',
 *   ratechange      : 'onRateChange',
 *   seeked          : 'onSeeked',
 *   seeking         : 'onSeeking',
 *   stalled         : 'onStalled',
 *   suspend         : 'onSuspend',
 *   timeupdate      : 'onTimeUpdate',
 *   volumechange    : 'onVolumeChange',
 *   waiting         : 'onWaiting'
 * }
 * ```
 *
 * @typedef {Object} handledMediaEventsMap
 * @memberof ui/Media
 * @public
 */


exports.getKeyFromSource = getKeyFromSource;
var handledMediaEventsMap = {
  abort: 'onAbort',
  canplay: 'onCanPlay',
  canplaythrough: 'onCanPlayThrough',
  durationchange: 'onDurationChange',
  emptied: 'onEmptied',
  encrypted: 'onEncrypted',
  ended: 'onEnded',
  error: 'onError',
  loadeddata: 'onLoadedData',
  loadedmetadata: 'onLoadedMetadata',
  loadstart: 'onLoadStart',
  pause: 'onPause',
  play: 'onPlay',
  playing: 'onPlaying',
  progress: 'onProgress',
  ratechange: 'onRateChange',
  seeked: 'onSeeked',
  seeking: 'onSeeking',
  stalled: 'onStalled',
  suspend: 'onSuspend',
  timeupdate: 'onTimeUpdate',
  volumechange: 'onVolumeChange',
  waiting: 'onWaiting'
};
/**
 * A component representation of HTMLMediaElement.
 *
 * @class Media
 * @memberof ui/Media
 * @ui
 * @public
 */

exports.handledMediaEventsMap = handledMediaEventsMap;

var Media = /*#__PURE__*/function (_React$Component) {
  _inherits(Media, _React$Component);

  var _super = _createSuper(Media);

  function Media(props) {
    var _this;

    _classCallCheck(this, Media);

    _this = _super.call(this, props);

    _this.attachCustomMediaEvents = function () {
      for (var eventName in _this.handledCustomMediaForwards) {
        (0, _dispatcher.on)(eventName, _this.handledCustomMediaForwards[eventName], _this.media);
      }
    };

    _this.detachCustomMediaEvents = function () {
      for (var eventName in _this.handledCustomMediaForwards) {
        (0, _dispatcher.off)(eventName, _this.handledCustomMediaForwards[eventName], _this.media);
      }
    };

    _this.handleEvent = function (ev) {
      (0, _handle.forward)('onUpdate', {
        type: 'onUpdate'
      }, _this.props); // fetch the forward() we generated earlier, using the event type as a key to find the real event name.

      var fwd = _this.handledMediaForwards[handledMediaEventsMap[ev.type]];

      if (fwd) {
        fwd(ev, _this.props);
      }
    };

    _this.mediaRef = function (node) {
      _this.media = node;
    };

    _this.media = null;
    _this.handledMediaForwards = {};
    _this.handledMediaEvents = {};
    _this.handledCustomMediaForwards = {}; // Generate event handling forwarders and a smooth block to pass to <Video>

    for (var key in props.mediaEventsMap) {
      var eventName = props.mediaEventsMap[key];
      _this.handledMediaForwards[eventName] = (0, _handle.forward)(eventName);
      _this.handledMediaEvents[eventName] = _this.handleEvent;
    } // Generate event handling forwarders for the custom events too


    var _loop = function _loop(_eventName) {
      var propName = props.customMediaEventsMap[_eventName];
      var forwardEvent = (0, _handle.forward)(propName);

      _this.handledCustomMediaForwards[_eventName] = function (ev) {
        return forwardEvent(ev, _this.props);
      };
    };

    for (var _eventName in props.customMediaEventsMap) {
      _loop(_eventName);
    }

    return _this;
  }

  _createClass(Media, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      this.attachCustomMediaEvents();
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(_ref) {
      var prevSource = _ref.source;
      var source = this.props.source;

      if (getKeyFromSource(source) !== getKeyFromSource(prevSource)) {
        this.load();
      }
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      this.detachCustomMediaEvents();
    }
  }, {
    key: "play",
    value: function play() {
      return this.media.play();
    }
  }, {
    key: "pause",
    value: function pause() {
      this.media.pause();
    }
  }, {
    key: "load",
    value: function load() {
      this.media.load();
    }
  }, {
    key: "render",
    value: function render() {
      var _this$props = this.props,
          customMediaEventsMap = _this$props.customMediaEventsMap,
          Component = _this$props.mediaComponent,
          source = _this$props.source,
          track = _this$props.track,
          rest = _objectWithoutProperties(_this$props, ["customMediaEventsMap", "mediaComponent", "source", "track"]);

      delete rest.mediaEventsMap;
      delete rest.onUpdate; // Remove the events we manually added so they aren't added twice or fail.

      for (var eventName in customMediaEventsMap) {
        delete rest[customMediaEventsMap[eventName]];
      }

      return /*#__PURE__*/_react["default"].createElement(Component, Object.assign({}, rest, this.handledMediaEvents, {
        ref: this.mediaRef
      }), source, track);
    }
  }, {
    key: "currentTime",
    get: function get() {
      return this.media.currentTime;
    },
    set: function set(currentTime) {
      this.media.currentTime = currentTime;
    }
  }, {
    key: "duration",
    get: function get() {
      return this.media.duration;
    }
  }, {
    key: "error",
    get: function get() {
      return this.media.networkState === this.media.NETWORK_NO_SOURCE;
    }
  }, {
    key: "loading",
    get: function get() {
      return this.media.readyState < this.media.HAVE_ENOUGH_DATA;
    }
  }, {
    key: "paused",
    get: function get() {
      return this.media.paused;
    }
  }, {
    key: "playbackRate",
    get: function get() {
      return this.media.playbackRate;
    },
    set: function set(playbackRate) {
      this.media.playbackRate = playbackRate;
    }
  }, {
    key: "proportionLoaded",
    get: function get() {
      return this.media.buffered.length && this.media.buffered.end(this.media.buffered.length - 1) / this.media.duration;
    }
  }, {
    key: "proportionPlayed",
    get: function get() {
      return this.media.currentTime / this.media.duration;
    }
  }]);

  return Media;
}(_react["default"].Component);

exports.Media = Media;
Media.propTypes =
/** @lends ui/Media.Media.prototype */
{
  /**
   * A type of media component.
   *
   * @type {String|Component}
   * @required
   * @public
   */
  mediaComponent: _propTypes["default"].renderable.isRequired,

  /**
   * An event map object for custom media events.
   *
   * List custom events that aren't standard to React. These will be directly added to the media
   * element and props matching their name will be executed as callback functions when the event fires.
   *
   * Example:
   * ```
   * {'umsmediainfo': 'onUMSMediaInfo'} // `onUMSMediaInfo` prop function will execute when the `umsmediainfo` event happens
   * ```
   *
   * @type {Object}
   * @public
   */
  customMediaEventsMap: _propTypes2["default"].object,

  /**
   * A event map object for media events.
   *
   * @type {Object}
   * @default {@link ui/Media.handledMediaEventsMap}
   * @public
   */
  mediaEventsMap: _propTypes2["default"].object,

  /**
   * A function to be run when media updates.
   *
   * @type {Function}
   * @public
   */
  onUpdate: _propTypes2["default"].func,

  /**
   * Media sources passed as children to `mediaComponent`
   *
   * See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source
   *
   * @type {*}
   * @public
   */
  source: _propTypes2["default"].any,
  track: _propTypes2["default"].any //yhcho
};
Media.defaultProps = {
  mediaEventsMap: handledMediaEventsMap
};
var _default = Media;
exports["default"] = _default;