/**
 * @archivo de video.js
 * @módulo videojs
 * /
importar {versión} desde '../../package.json';
importar ventana desde 'global/window';
importar {
  manos_,
  manos,
  gancho,
  anzuelo una vez,
  Quitar gancho
} de './utils/ganchos';
importar * como configuración desde './setup';
importar * como hoja de estilo desde './utils/stylesheet.js';
importar componente desde './componente';
importar EventTarget desde './event-target';
importar * como Eventos desde './utils/events.js';
importar jugador desde './jugador';
importar complemento desde './plugin';
importar mergeOptions desde './utils/merge-options.js';
importar * como Fn desde './utils/fn.js';
importar TextTrack desde './tracks/text-track.js';
importar AudioTrack desde './tracks/audio-track.js';
importar VideoTrack desde './tracks/video-track.js';

import { createTimeRanges } from './utils/time-ranges.js';
import formatTime, { setFormatTime, resetFormatTime } from './utils/format-time.js';
registro de importación, { createLogger } desde './utils/log.js';
importar * como Dom desde './utils/dom.js';
importar * como navegador desde './utils/browser.js';
importar * como URL desde './utils/url.js';
importar {isObject} desde './utils/obj';
importar estilo computado desde './utils/computed-style.js';
importar extender desde './extend.js';
importar xhr desde '@videojs/xhr';

// Incluir las tecnologías integradas
importar tecnología desde './tech/tech.js';
importar { usar como middlewareUse, TERMINATOR } desde './tech/middleware.js';
importar defineLazyProperty desde './utils/define-lazy-property.js';

/ **
 * Normalice un valor `id` recortando un `#` inicial
 *
 * @privado
 * @param {cadena} id
 * Una cadena, tal vez con un `#` inicial.
 *
 * @return {cadena}
 * La cadena, sin ningún `#` inicial.
 * /
const normalizeId = (id) => id.indexOf('#') === 0 ? id.rebanada(1) : id;

/ **
 * La función `videojs()` se duplica como la función principal para que los usuarios creen un
 * Instancia de {@link Player}, así como el espacio de nombres de la biblioteca principal.
 *
 * También se puede usar como getter para una instancia preexistente de {@link Player}.
 * Sin embargo, recomendamos _fuertemente_ usar `videojs.getPlayer()` para esto
 * Propósito porque evita cualquier potencial de inicialización no deseada.
 *
 * Debido a [limitaciones](https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)
 * de nuestra plantilla JSDoc, no podemos documentar correctamente esto como una función
 * y un espacio de nombres, por lo que la firma de su función se documenta aquí.
 *
 * #### Argumentos
 * ##### identificación
 * cadena|Elemento, **obligatorio**
 *
 * Elemento de video o ID de elemento de video.
 *
 * ##### opciones
 * Objeto, opcional
 *
 * Objeto de opciones para proporcionar configuraciones.
 * Ver: [Guía de opciones](https://docs.videojs.com/tutorial-options.html).
 *
 * ##### listo
 * {@link Component~ReadyCallback}, opcional
 *
 * Una función que se llamará cuando {@link Player} y {@link Tech} estén listos.
 *
 * #### Valor devuelto
 *
 * La función `videojs()` devuelve una instancia de {@link Player}.
 *
 * @espacio de nombres
 *
 * @toma prestada AudioTrack como AudioTrack
 * @borrows Component.getComponent como getComponent
 * Módulo @borrows:estilo-computado~Estilo-computado como Estilo-computado
 * Módulo @borrows:events.on como en
 * Módulo @borrows: eventos.uno como uno
 * Módulo @borrows:events.off como desactivado
 * Módulo @borrows:events.trigger como disparador
 * @toma prestado EventTarget como EventTarget
 * Módulo @borrows: extender ~ extender como extender
 * Módulo @borrows:fn.bind como enlace
 * Módulo @borrows:format-time.formatTime as formatTime
 * Módulo @borrows:format-time.resetFormatTime como resetFormatTime
 * Módulo @borrows:format-time.setFormatTime como setFormatTime
 * Módulo @borrows:merge-options.mergeOptions como mergeOptions
 * Módulo @borrows:middleware.use como uso
 * @toma prestado Player.players como jugadores
 * @borrows Plugin.registerPlugin como registerPlugin
 * @borrows Plugin.deregisterPlugin como deregisterPlugin
 * @borrows Plugin.getPlugins como getPlugins
 * @toma prestado Plugin.getPlugin como getPlugin
 * @toma prestado Plugin.getPluginVersion como getPluginVersion
 * @toma prestado Tech.getTech como getTech
 * @toma prestada Tech.registerTech como registerTech
 * @toma prestado TextTrack como TextTrack
 * Módulo @borrows:time-ranges.createTimeRanges as createTimeRange
 * Módulo @borrows:time-ranges.createTimeRanges as createTimeRanges
 * Módulo @borrows:url.isCrossOrigin como isCrossOrigin
 * Módulo @borrows:url.parseUrl como parseUrl
 * @toma prestada VideoTrack como VideoTrack
 *
 * @param {cadena|Elemento} id
 * Elemento de video o ID de elemento de video.
 *
 * @param {Objeto} [opciones]
 * Objeto de opciones para proporcionar configuraciones.
 * Ver: [Guía de opciones](https://docs.videojs.com/tutorial-options.html).
 *
 * @param {Componente~ReadyCallback} [listo]
 * Una función que se llamará cuando {@link Player} y {@link Tech} estén
 * listo.
 *
 * @return {Jugador}
 * La función `videojs()` devuelve una instancia de {@link Player|Player}.
 * /
function videojs(id, opciones, listo) {
  dejar jugador = videojs.getPlayer(id);

  si (jugador) {
    si (opciones) {
      log.warn(`El jugador "${id}" ya está inicializado. Las opciones no se aplicarán.`);
    }
    si (listo) {
      jugador.listo(listo);
    }
    jugador de regreso;
  }

  const el = (tipo de id === 'cadena') ? Dom.$('#' + normalizeId(id)) : id;

  if (!Dom.isEl(el)) {
    throw new TypeError('El elemento o ID proporcionado no es válido. (videojs)');
  }

  // document.body.contains(el) solo verificará si el está contenido dentro de ese documento.
  // Esto causa problemas para los elementos en iframes.
  // En su lugar, use el documento propietario del elemento en lugar del documento global.
  // Esto asegurará que el elemento esté realmente en el dominio de ese documento.
  // Además, verifique que el documento en cuestión tenga una vista predeterminada.
  // Si el documento ya no está adjunto al dom, la vista predeterminada del documento será nula.
  if (!el.documentopropietario.vistapredeterminada || !el.documentopropietario.cuerpo.contiene(el)) {
    log.warn('El elemento suministrado no está incluido en el DOM');
  }

  opciones = opciones || {};

  // Almacenar una copia del el antes de la modificación, si se va a restaurar en destroy()
  // Si se ingiere div, almacena el div principal
  if (opciones.restoreEl === verdadero) {
    opciones.restoreEl = (el.parentNode && el.parentNode.hasAttribute('data-vjs-player') ? el.parentNode : el).cloneNode(true);
  }

  ganchos('antes de la configuración').forEach((funcióngancho) => {
    const opts = hookFunction(el, mergeOptions(opciones));

    if (!isObject(opciones) || Array.isArray(opciones)) {
      log.error('por favor devuelva un objeto antes de la configuración');
      devolver;
    }

    opciones = mergeOptions(opciones, opciones);
  });

  // Obtenemos el componente "Jugador" actual aquí en caso de que haya una integración
  // lo reemplazó con un reproductor personalizado.
  const PlayerComponent = Component.getComponent('Jugador');

  player = new PlayerComponent(el, opciones, listo);

  ganchos('configuración').forEach((funcióngancho) => hookFunction(jugador));

  jugador de regreso;
}

videojs.ganchos_ = ganchos_;
videojs.hooks = ganchos;
videojs.hook = gancho;
videojs.hookOnce = hookOnce;
videojs.removeHook = removeHook;

// Agregar estilos predeterminados
si (ventana.VIDEOJS_NO_DYNAMIC_STYLE!== verdadero && Dom.esReal()) {
  let style = Dom.$('.vjs-styles-defaults');

  si (! estilo) {
    estilo = hoja de estilo.createStyleElement('vjs-styles-defaults');
    const cabeza = Dom.$('cabeza');

    si (cabeza) {
      head.insertBefore(estilo, head.firstChild);
    }
    hoja de estilo.setTextContent(estilo, `
      .video-js {
        ancho: 300 píxeles;
        altura: 150 píxeles;
      }

      .vjs-fluid:not(.vjs-audio-only-mode) {
        acolchado superior: 56,25%
      }
    `);
  }
}

// Ejecutar reproductores de carga automática
// Debe esperar al menos una vez en caso de que este script se cargue después de su
// video en el DOM (comportamiento extraño solo con versión minimizada)
setup.autoSetupTimeout(1, videojs);

/ **
 * Versión actual de Video.js. Sigue [versiones semánticas] (https://semver.org/).
 *
 * @tipo {cadena}
 * /
videojs.VERSION = versión;

/ **
 * El objeto de opciones globales. Estos son los ajustes que surten efecto
 * si no se especifican anulaciones cuando se crea el reproductor.
 *
 * @type {Objeto}
 * /
videojs.options = Player.prototype.options_;

/ **
 * Obtener un objeto con los jugadores creados actualmente, identificados por ID de jugador
 *
 * @return {Objeto}
 * Los jugadores creados
 * /
videojs.getPlayers = () => Jugador.jugadores;

/ **
 * Obtenga un solo jugador basado en un elemento ID o DOM.
 *
 * Esto es útil si desea verificar si un elemento o ID tiene un asociado
 * Reproductor de Video.js, pero no crear uno si no lo hace.
 *
 * @param {cadena|Elemento} id
 * Un elemento HTML - `< video> `, `< audio> `, o `< video-js> `-
 * o una cadena que coincida con el `id` de dicho elemento.
 *
 * @return {Jugador|indefinido}
 * Una instancia de jugador o `indefinido` si no hay ninguna instancia de jugador
 * haciendo coincidir el argumento.
 * /
videojs.getPlayer = (id) => {
  const jugadores = Jugador.jugadores;
  dejar etiquetar;

  if (tipo de id === 'cadena') {
    const nId = normalizeId(id);
    const jugador = jugadores[nId];

    si (jugador) {
      jugador de regreso;
    }

    etiqueta = Dom.$('#' + nId);
  } else {
    etiqueta = identificación;
  }

  if (Dom.isEl(etiqueta)) {
    const {jugador, playerId} = etiqueta;

    // El elemento puede tener una propiedad `jugador` que se refiera a un ya creado
    // instancia del jugador. Si es así, devuélvelo.
    if (jugador || jugadores[jugadorId]) {
      jugador de regreso || jugadores[jugadorId];
    }
  }
};

/ **
 * Devuelve una matriz de todos los jugadores actuales.
 *
 * @return {Array}
 * Una matriz de todos los jugadores. La matriz estará en el orden que
 * Proporciona `Object.keys`, que podría variar potencialmente entre
 * Motores JavaScript.
 *
 * /
videojs.getAllPlayers = () =>

  // Los jugadores eliminados dejan una clave con un valor `nulo`, por lo que debemos asegurarnos
  // los filtramos.
  Objeto.keys(Jugador.jugadores).mapa(k => Jugador.jugadores[k]).filtro(Booleano);

videojs.jugadores = Jugador.jugadores;
videojs.getComponent = Componente.getComponent;

/ **
 * Registrar un componente para que pueda ser referido por su nombre. Se usa cuando se agrega a otros
 * componentes, ya sea a través de addChild `component.addChild('myComponent')` o a través de
 * opciones predeterminadas para niños `{ children: ['myComponent'] }`.
 *
 * > NOTA: También puede simplemente inicializar el componente antes de agregarlo.
 * `component.addChild(nuevo MiComponente());`
 *
 * @param {cadena} nombre
 * El nombre de clase del componente
 *
 * @param {Componente} composición
 * La clase de componente
 *
 * @return {Componente}
 * El componente recién registrado
 * /
videojs.registerComponent = (nombre, borrador) => {
  if (Tecnología.esTecnología(comp)) {
    log.warn(`La tecnología ${name} se registró como un componente. En su lugar, debe registrarse usando videojs.registerTech(name, tech)`);
  }

  Component.registerComponent.call(Componente, nombre, comp);
};

videojs.getTech = Tech.getTech;
videojs.registerTech = Tech.registerTech;
videojs.use = middlewareUse;

/ **
 * Un objeto que puede ser devuelto por un middleware para indicar
 * que el middleware está siendo terminado.
 *
 * @tipo {objeto}
 * @property {objeto} middleware.TERMINATOR
 * /
Objeto.defineProperty(videojs, 'middleware', {
  valor: {},
  escribible: falso,
  enumerable: verdadero
});

Objeto.defineProperty(videojs.middleware, 'TERMINATOR', {
  valor: TERMINADOR,
  escribible: falso,
  enumerable: verdadero
});

/ **
 * Una referencia al {@módulo de enlace:navegador|módulo de utilidad del navegador} como un objeto.
 *
 * @type {Objeto}
 * @ver {@enlace módulo:navegador|navegador}
 * /
videojs.browser = navegador;

/ **
 * Use {@link module:browser.TOUCH_ENABLED|browser.TOUCH_ENABLED} en su lugar; solo
 * incluido para compatibilidad con versiones anteriores con 4.x.
 *
 * @obsoleto Desde la versión 5.0, use {@link module:browser.TOUCH_ENABLED|browser.TOUCH_ENABLED en su lugar.
 * @tipo {booleano}
 * /
videojs.TOUCH_ENABLED = navegador.TOUCH_ENABLED;

videojs.extender = extender;
videojs.mergeOptions = mergeOptions;
videojs.bind = Fn.bind;
videojs.registerPlugin = Complemento.registerPlugin;
videojs.deregisterPlugin = Complemento.deregisterPlugin;

/ **
 * Método obsoleto para registrar un complemento con Video.js
 *
 * @deprecated videojs.plugin() está en desuso; use videojs.registerPlugin() en su lugar
 *
 * @param {cadena} nombre
 * El nombre del complemento
 *
 * @param {Complemento|Función} complemento
 * La subclase o función del complemento
 * /
videojs.plugin = (nombre, complemento) => {
  log.warn('videojs.plugin() está en desuso; use videojs.registerPlugin() en su lugar');
  return Plugin.registerPlugin(nombre, complemento);
};

videojs.getPlugins = Complemento.getPlugins;
videojs.getPlugin = Complemento.getPlugin;
videojs.getPluginVersion = Complemento.getPluginVersion;

/ **
 * Agregar idiomas para que estén disponibles para todos los jugadores.
 * Ejemplo: `videojs.addLanguage('es', { 'Hola': 'Hola' });`
 *
 * código @param {cadena}
 * El código de idioma o la propiedad del diccionario
 *
 * @param {Objeto} datos
 * Los valores de datos a traducir
 *
 * @return {Objeto}
 * El objeto de diccionario de idioma resultante
 * /
videojs.addLanguage = función (código, datos) {
  codigo = ('' + codigo).toLowerCase();

  videojs.opciones.idiomas = mergeOptions(
    videojs.opciones.idiomas,
    {[código]: datos}
  );

  volver videojs.opciones.idiomas[código];
};

/ **
 * Una referencia al {@módulo de enlace: registro|módulo de utilidad de registro} como un objeto.
 *
 * @tipo {Función}
 * @ver {@enlace módulo:log|log}
 * /
videojs.log = registro;
videojs.createLogger = createLogger;

videojs.createTimeRange = videojs.createTimeRanges = createTimeRanges;
videojs.formatTime = formatTime;
videojs.setFormatTime = setFormatTime;
videojs.resetFormatTime = resetFormatTime;
videojs.parseUrl = Url.parseUrl;
videojs.isCrossOrigin = Url.isCrossOrigin;
videojs.EventTarget = EventTarget;
videojs.on = Eventos.on;
videojs.one = Eventos.uno;
videojs.off = Eventos.off;
videojs.trigger = Eventos.trigger;

/ **
 * Un contenedor XMLHttpRequest para varios navegadores.
 *
 * @función
 * @param {Objeto} opciones
 * Configuración para la solicitud.
 *
 * @return {XMLHttpRequest|XDomainRequest}
 * El objeto de la solicitud.
 *
 * @ver https://github.com/Raynos/xhr
 * /
videojs.xhr = xhr;

videojs.TextTrack = TextTrack;
videojs.AudioTrack = AudioTrack;
videojs.VideoTrack = VideoTrack;

[
  'isEl',
  'esNodoDeTexto',
  'createEl',
  'hasClass',
  'agregarClase',
  'eliminarclase',
  'alternar clase',
  'establecer Atributos',
  'getAttributes',
  'vacíoEl',
  'agregar contenido',
  'insertarContenido'
].paraCada(k => {
  videojs[k] = función() {
    log.warn(`videojs.${k}() está en desuso; use videojs.dom.${k}() en su lugar`);
    return Dom[k].apply(null, argumentos);
  };
});

videojs.estilo computado = estilo computado;

/ **
 * Una referencia al {@módulo de enlace:dom|módulo de utilidad DOM} como un objeto.
 *
 * @type {Objeto}
 * @ver {@enlace módulo:dom|dom}
 * /
videojs.dom = Dom;

/ **
 * Una referencia al {@módulo de enlace:url|módulo de utilidad de URL} como un objeto.
 *
 * @type {Objeto}
 * @ver {@enlace módulo:url|url}
 * /
videojs.url = Url;

videojs.defineLazyProperty = defineLazyProperty;

// Agregar texto menos ambiguo para el botón de pantalla completa.
// En una actualización importante, esto podría convertirse en el texto y la clave predeterminados.
videojs.addLanguage('en', {'No pantalla completa': 'Salir de pantalla completa'});

exportar videojs predeterminados;