/**
 * @Datei video.js
 * @modul videojs
 * /
importiere {version} von '../../package.json';
import window from 'global/window';
importieren {
  hooks_,
  haken,
  haken,
  hookOnce,
  removeHook
} von './utils/hooks';
importiere * als setup von './setup';
importiere * als Stylesheet aus './utils/stylesheet.js';
importiere Komponente von './komponente';
import EventTarget von './event-target';
import * as Events aus './utils/events.js';
import Player von './player';
import Plugin von './plugin';
importiere mergeOptions aus './utils/merge-options.js';
import * as Fn from './utils/fn.js';
import TextTrack from './tracks/text-track.js';
import AudioTrack from './tracks/audio-track.js';
import VideoTrack from './tracks/video-track.js';

importieren { createTimeRanges } from './utils/time-ranges.js';
import formatTime, { setFormatTime, resetFormatTime } from './utils/format-time.js';
import log, { createLogger } from './utils/log.js';
importiere * as Dom aus './utils/dom.js';
importiere * as browser aus './utils/browser.js';
import * as Url from './utils/url.js';
importiere {isObject} von './utils/obj';
importiere computedStyle aus './utils/computed-style.js';
importieren Sie extend aus './extend.js';
import xhr from '@videojs/xhr';

// Einbindung der eingebauten Techs
importiere Tech aus './tech/tech.js';
importieren { use as middlewareUse, TERMINATOR } from './tech/middleware.js';
importiere defineLazyProperty aus './utils/define-lazy-property.js';

/**
 * Normalisieren eines "id"-Werts durch Abschneiden eines führenden "#"
 *
 * @privat
 * @param {string} id
 *          Eine Zeichenkette, möglicherweise mit einem führenden "#".
 *
 * @return {string}
 *          Die Zeichenkette, ohne führendes "#".
 * /
const normalizeId = (id) => id.indexOf('#') === 0 ? id.slice(1) : id;

/**
 * Die Funktion "videojs()" ist gleichzeitig die Hauptfunktion, mit der die Benutzer eine
 * instanz von {@link Player} sowie den Haupt-Namensraum der Bibliothek.
 *
 * Sie kann auch als Getter für eine bereits existierende {@link Player}-Instanz verwendet werden.
 * Wir empfehlen jedoch _stark_ die Verwendung von `videojs.getPlayer()`
 * zweck, weil dadurch jede Möglichkeit einer unbeabsichtigten Initialisierung vermieden wird.
 *
 * Aufgrund von [Einschränkungen] (https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)
 * unserer JSDoc-Vorlage können wir dies nicht ordnungsgemäß als eine Funktion dokumentieren
 * und einen Namespace, so dass seine Funktionssignatur hier dokumentiert ist.
 *
 * #### Argumente
 * ##### id
 * string|Element, **erforderlich**
 *
 * Videoelement oder Videoelement-ID.
 *
 * ##### Optionen
 * Objekt, optional
 *
 * Optionsobjekt für die Bereitstellung von Einstellungen.
 * Siehe: [Optionen-Leitfaden] (https://docs.videojs.com/tutorial-options.html).
 *
 * ##### bereit
 * {@link Component~ReadyCallback}, optional
 *
 * Eine Funktion, die aufgerufen wird, wenn der {@link Player} und {@link Tech} bereit sind.
 *
 * #### Rückgabewert
 *
 * Die Funktion "videojs()" gibt eine Instanz von {@link Player} zurück.
 *
 * @Namensraum
 *
 * @borrows AudioTrack als AudioTrack
 * @borrows Component.getComponent als getComponent
 * @borrows module:computed-style~computedStyle als computedStyle
 * @borrows module:events.on als on
 * @borrows module:events.one as one
 * @borrows module:events.off als off
 * @borrows module:events.trigger als Auslöser
 * @borrows EventTarget as EventTarget
 * @borrows module:extend~extend as extend
 * @borrows module:fn.bind as bind
 * @borrows module:format-time.formatTime als formatTime
 * @borrows module:format-time.resetFormatTime as resetFormatTime
 * @borrows module:format-time.setFormatTime as setFormatTime
 * @borrows module:merge-options.mergeOptions as mergeOptions
 * @borrows module:middleware.use als use
 * @borrows Spieler.spieler als Spieler
 * @borrows Plugin.registerPlugin as registerPlugin
 * @borrows Plugin.deregisterPlugin as deregisterPlugin
 * @borrows Plugin.getPlugins as getPlugins
 * @borrows Plugin.getPlugin as getPlugin
 * @borrows Plugin.getPluginVersion as getPluginVersion
 * @borrows Tech.getTech als getTech
 * @borrows Tech.registerTech als registerTech
 * @borrows TextTrack as TextTrack
 * @borrows module:time-ranges.createTimeRanges as createTimeRange
 * @borrows module:time-ranges.createTimeRanges as createTimeRanges
 * @borrows module:url.isCrossOrigin as isCrossOrigin
 * @borrows module:url.parseUrl as parseUrl
 * @borrows VideoTrack als VideoTrack
 *
 * @param {String|Element} id
 *         Videoelement oder Videoelement-ID.
 *
 * @param {Object} [Optionen]
 *         Optionsobjekt für die Bereitstellung von Einstellungen.
 *         Siehe: [Optionen-Leitfaden] (https://docs.videojs.com/tutorial-options.html).
 *
 * @param {Component~ReadyCallback} [ready]
 *         Eine Funktion, die aufgerufen wird, wenn die {@link Player} und {@link Tech}
 *         bereit.
 *
 * @return {Player}
 *         Die Funktion "videojs()" gibt eine Instanz von {@link Player|Player} zurück.
 * /
function videojs(id, options, ready) {
  let player = videojs.getPlayer(id);

  wenn (Spieler) {
    wenn (Optionen) {
      log.warn(`Der Spieler "${id}" ist bereits initialisiert. Optionen werden nicht angewandt.`);
    }
    wenn (bereit) {
      player.ready(ready);
    }
    rückspieler;
  }

  const el = (typeof id === 'string') ? Dom.$('#' + normalizeId(id)) : id;

  if (!Dom.isEl(el)) {
    throw new TypeError('Das angegebene Element oder die ID ist nicht gültig. (videojs)');
  }

  // document.body.contains(el) prüft nur, ob el in diesem einen Dokument enthalten ist.
  // Dies führt zu Problemen bei Elementen in iframes.
  // Verwenden Sie stattdessen das ownerDocument des Elements anstelle des globalen Dokuments.
  // Damit wird sichergestellt, dass das Element tatsächlich im Dom des Dokuments enthalten ist.
  // Prüfen Sie außerdem, ob das betreffende Dokument eine Standardansicht hat.
  // Wenn das Dokument nicht mehr mit dem Dom verbunden ist, ist die Standardansicht des Dokuments null.
  if (!el.ownerDocument.defaultView || !el.ownerDocument.body.contains(el)) {
    log.warn('Das angegebene Element ist nicht im DOM enthalten');
  }

  optionen = Optionen || {};

  // Speichern Sie eine Kopie der el vor der Änderung, wenn sie in destroy() wiederhergestellt werden soll
  // Wenn div ingest, speichere das übergeordnete div
  if (options.restoreEl === true) {
    options.restoreEl = (el.parentNode && el.parentNode.hasAttribute('data-vjs-player') ? el.parentNode : el).cloneNode(true);
  }

  hooks('beforesetup').forEach((hookFunction) => {
    const opts = hookFunction(el, mergeOptions(options));

    if (!isObject(opts) || Array.isArray(opts)) {
      log.error('Bitte geben Sie ein Objekt in beforesetup hooks zurück');
      rückkehr;
    }

    options = mergeOptions(options, opts);
  });

  // Wir holen uns hier die aktuelle "Player"-Komponente, falls eine Integration vorliegt
  // durch einen benutzerdefinierten Player ersetzt.
  const PlayerComponent = Component.getComponent('Player');

  player = new PlayerComponent(el, options, ready);

  hooks('setup').forEach((hookFunction) => hookFunction(player));

  rückspieler;
}

videojs.hooks_ = hooks_;
videojs.hooks = hooks;
videojs.hook = hook;
videojs.hookOnce = hookOnce;
videojs.removeHook = removeHook;

// Hinzufügen von Standardstilen
if (window.VIDEOJS_NO_DYNAMIC_STYLE !== true && Dom.isReal()) {
  let style = Dom.$('.vjs-styles-defaults');

  if (!style) {
    style = stylesheet.createStyleElement('vjs-styles-defaults');
    const head = Dom.$('head');

    wenn (Kopf) {
      head.insertBefore(style, head.firstChild);
    }
    stylesheet.setTextInhalt(style, `
      .video-js {
        Breite: 300px;
        Höhe: 150px;
      }

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

// Automatisches Laden von Spielern ausführen
// Sie müssen mindestens einmal warten, falls dieses Skript nach Ihrem
// Video im DOM (seltsames Verhalten nur bei der Minified-Version)
setup.autoSetupTimeout(1, videojs);

/**
 * Aktuelle Video.js-Version. Folgt [semantische Versionierung] (https://semver.org/).
 *
 * @Typ {String}
 * /
videojs.VERSION = version;

/**
 * Das Objekt "Globale Optionen". Die folgenden Einstellungen werden wirksam
 * wenn bei der Erstellung des Players keine Überschreibungen angegeben wurden.
 *
 * @Typ {Objekt}
 * /
videojs.options = Player.prototype.options_;

/**
 * Abrufen eines Objekts mit den aktuell erstellten Spielern, verschlüsselt durch die Spieler-ID
 *
 * @return {Object}
 *         Die erstellten Spieler
 * /
videojs.getPlayers = () => Player.players;

/**
 * Abrufen eines einzelnen Spielers auf der Grundlage einer ID oder eines DOM-Elements.
 *
 * Dies ist nützlich, wenn Sie prüfen wollen, ob ein Element oder eine ID eine zugehörige
 * Video.js-Player, aber erstellen Sie keinen, wenn er nicht vorhanden ist.
 *
 * @param {String|Element} id
 *          Ein HTML-Element - `<video>`, `<audio>`, oder `<video-js>` -
 *          oder eine Zeichenkette, die mit der "id" eines solchen Elements übereinstimmt.
 *
 * @return {Player|undefined}
 *          Eine Spielerinstanz oder `undefined`, wenn es keine Spielerinstanz gibt
 *          die dem Argument entsprechen.
 * /
videojs.getPlayer = (id) => {
  const players = Player.players;
  tag lassen;

  if (typeof id === 'string') {
    const nId = normalizeId(id);
    const player = players[nId];

    wenn (Spieler) {
      rückspieler;
    }

    tag = Dom.$('#' + nId);
  } else {
    tag = id;
  }

  if (Dom.isEl(tag)) {
    const {player, playerId} = tag;

    // Element kann eine Eigenschaft `player` haben, die sich auf einen bereits erstellten
    // Spieler-Instanz. Wenn ja, geben Sie das zurück.
    if (Spieler || Spieler[SpielerId]) {
      return spieler || spieler[spielerId];
    }
  }
};

/**
 * Gibt ein Array mit allen aktuellen Spielern zurück.
 *
 * @return {Array}
 *         Ein Array mit allen Spielern. Die Anordnung erfolgt in der Reihenfolge, in der
 *         object.keys" liefert, die möglicherweise variieren können zwischen
 *         JavaScript-Engines.
 *
 * /
videojs.getAllPlayers = () =>

  // Abgeworfene Spieler hinterlassen einen Schlüssel mit einem "Null"-Wert, also müssen wir sicherstellen, dass
  // Wir filtern diese heraus.
  Object.keys(Player.players).map(k => Player.players[k]).filter(Boolean);

videojs.players = Player.players;
videojs.getComponent = Component.getComponent;

/**
 * Registrieren Sie eine Komponente, damit sie mit einem Namen bezeichnet werden kann. Wird beim Hinzufügen zu anderen
 * komponenten, entweder durch addChild `component.addChild('myComponent')` oder durch
 * standard-Kinderoptionen `{ Kinder: ['myComponent'] }`.
 *
 * > HINWEIS: Sie können die Komponente auch einfach initialisieren, bevor Sie sie hinzufügen.
 * komponente.addChild(new MeineKomponente());`
 *
 * @param {string} name
 *        Der Klassenname der Komponente
 *
 * @param {Komponente} comp
 *        Die Komponentenklasse
 *
 * @return {Komponente}
 *         Die neu registrierte Komponente
 * /
videojs.registerComponent = (name, comp) => {
  if (Tech.isTech(comp)) {
    log.warn(`Der ${name} tech wurde als Komponente registriert. Sie sollte stattdessen mit videojs.registerTech(name, tech)`) registriert werden;
  }

  Component.registerComponent.call(Component, name, comp);
};

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

/**
 * Ein Objekt, das von einer Middleware zurückgegeben werden kann, um zu signalisieren
 * dass die Middleware beendet wird.
 *
 * @Typ {Objekt}
 * @Eigenschaft {Objekt} middleware.TERMINATOR
 * /
Object.defineProperty(videojs, 'middleware', {
  wert: {},
  beschreibbar: false,
  aufzählbar: wahr
});

Object.defineProperty(videojs.middleware, 'TERMINATOR', {
  wert: TERMINATOR,
  beschreibbar: false,
  aufzählbar: wahr
});

/**
 * Ein Verweis auf das {@link module:browser|browser utility module} als Objekt.
 *
 * @Typ {Objekt}
 * @siehe {@link module:browser|browser}
 * /
videojs.browser = browser;

/**
 * Verwenden Sie stattdessen {@link module:browser.TOUCH_ENABLED|browser.TOUCH_ENABLED}; nur
 * für die Abwärtskompatibilität mit 4.x enthalten.
 *
 * @deprecated Seit Version 5.0 verwenden Sie stattdessen {@link module:browser.TOUCH_ENABLED|browser.TOUCH_ENABLED.
 * @Typ {boolean}
 * /
videojs.TOUCH_ENABLED = browser.TOUCH_ENABLED;

videojs.extend = extend;
videojs.mergeOptions = mergeOptions;
videojs.bind = Fn.bind;
videojs.registerPlugin = Plugin.registerPlugin;
videojs.deregisterPlugin = Plugin.deregisterPlugin;

/**
 * Veraltete Methode zur Registrierung eines Plugins bei Video.js
 *
 * @deprecated videojs.plugin() ist veraltet; verwenden Sie stattdessen videojs.registerPlugin()
 *
 * @param {string} name
 *        Der Name des Plugins
 *
 * @param {Plugin|Funktion} plugin
 *         Die Plugin-Unterklasse oder Funktion
 * /
videojs.plugin = (Name, Plugin) => {
  log.warn('videojs.plugin() ist veraltet; verwenden Sie stattdessen videojs.registerPlugin()');
  return Plugin.registerPlugin(name, plugin);
};

videojs.getPlugins = Plugin.getPlugins;
videojs.getPlugin = Plugin.getPlugin;
videojs.getPluginVersion = Plugin.getPluginVersion;

/**
 * Hinzufügen von Sprachen, damit sie für alle Spieler verfügbar sind.
 * Beispiel: `videojs.addLanguage('es', { 'Hallo': 'Hola' });`
 *
 * @param {string} code
 *        Der Sprachcode oder die Wörterbuch-Eigenschaft
 *
 * @param {Object} data
 *        Die zu übersetzenden Datenwerte
 *
 * @return {Object}
 *         Das resultierende Objekt des Sprachwörterbuchs
 * /
videojs.addLanguage = function(code, data) {
  code = ('' + code).toLowerCase();

  videojs.options.languages = mergeOptions(
    videojs.options.languages,
    {[Code]: Daten}
  );

  return videojs.options.languages[code];
};

/**
 * Ein Verweis auf das {@link module:log|log utility module} als Objekt.
 *
 * @Typ {Funktion}
 * @siehe {@link module:log|log}
 * /
videojs.log = log;
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 = Events.on;
videojs.one = Events.one;
videojs.off = Events.off;
videojs.trigger = Events.trigger;

/**
 * Ein browserübergreifender XMLHttpRequest-Wrapper.
 *
 * @Funktion
 * @param {Object} options
 *           Einstellungen für die Anfrage.
 *
 * @return {XMLHttpRequest|XDomainRequest}
 *           Das Anfrageobjekt.
 *
 * @see https://github.com/Raynos/xhr
 * /
videojs.xhr = xhr;

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

[
  'isEl',
  isTextNode',
  'createEl',
  hasClass',
  'addClass',
  removeClass',
  'toggleClass',
  'setAttributes',
  'getAttributes',
  leerEl",
  appendContent',
  insertContent
].forEach(k => {
  videojs[k] = function() {
    log.warn(`videojs.${k}() ist veraltet; verwenden Sie stattdessen videojs.dom.${k}()`);
    return Dom[k].apply(null, arguments);
  };
});

videojs.computedStyle = computedStyle;

/**
 * Ein Verweis auf das {@link module:dom|DOM utility module} als Objekt.
 *
 * @Typ {Objekt}
 * @siehe {@link module:dom|dom}
 * /
videojs.dom = Dom;

/**
 * Ein Verweis auf das {@link module:url|URL utility module} als Objekt.
 *
 * @Typ {Objekt}
 * @siehe {@link module:url|url}
 * /
videojs.url = Url;

videojs.defineLazyProperty = defineLazyProperty;

// Hinzufügen eines weniger zweideutigen Textes für die Schaltfläche "Vollbild".
// Bei einer größeren Aktualisierung könnte dies der Standardtext und -schlüssel werden.
videojs.addLanguage('en', {'Non-Fullscreen': 'Vollbild beenden'});

standard-Videojs exportieren;