/**
 * @Datei text-track.js
 * /
import TextTrackCueList from './text-track-cue-list';
import * as Fn from '../utils/fn.js';
importiere {TextTrackKind, TextTrackMode} von './track-enums';
import log from '../utils/log.js';
import window from 'global/window';
importiere Track aus './track.js';
import { isCrossOrigin } from '../utils/url.js';
importiere XHR von '@videojs/xhr';
importiere merge von '../utils/merge-options';

/**
 * Nimmt den Inhalt einer webvtt-Datei und zerlegt ihn in Stichwörter
 *
 * @param {string} srcInhalt
 *        inhalt der webVTT-Datei
 *
 * @param {TextTrack} track
 *        TextTrack zum Hinzufügen von Stichwörtern. Die Hinweise stammen aus dem srcContent.
 *
 * @privat
 * /
const parseCues = function(srcContent, track) {
  const parser = new window.WebVTT.Parser(
    fenster,
    window.vttjs,
    window.WebVTT.StringDecoder()
  );
  const errors = [];

  parser.oncue = function(cue) {
    track.addCue(cue);
  };

  parser.onparsingerror = function(error) {
    errors.push(error);
  };

  parser.onflush = function() {
    track.trigger({
      typ: 'Geladene Daten',
      ziel: Spur
    });
  };

  parser.parse(srcContent);
  if (errors.length > 0) {
    if (window.console && window.console.groupCollapsed) {
      window.console.groupCollapsed(`Text Track parsing errors for ${track.src}`);
    }
    errors.forEach((error) => log.error(error));
    if (window.console && window.console.groupEnd) {
      window.console.groupEnd();
    }
  }

  parser.flush();
};

/**
 * Lädt einen `TextTrack` von einer angegebenen Url.
 *
 * @param {string} src
 *        Url zum Laden des Tracks von.
 *
 * @param {TextTrack} track
 *        Spur zum Hinzufügen von Stichwörtern. Ergibt sich aus dem Inhalt am Ende von `url`.
 *
 * @privat
 * /
const loadTrack = function(src, track) {
  const opts = {
    uri: src
  };
  const crossOrigin = isCrossOrigin(src);

  if (crossOrigin) {
    opts.cors = crossOrigin;
  }

  const withCredentials = track.tech_.crossOrigin() === 'use-credentials';

  if (withCredentials) {
    opts.withCredentials = withCredentials;
  }

  XHR(opts, Fn.bind(this, function(err, response, responseBody) {
    if (err) {
      return log.error(err, response);
    }

    track.loaded_ = true;

    // Stellen Sie sicher, dass vttjs geladen wurde, andernfalls warten Sie, bis es fertig geladen ist
    // HINWEIS: dies wird nur für den Aufbau von alt/video.novtt.js verwendet
    if (typeof window.WebVTT !== 'function') {
      if (track.tech_) {
        // um die Verwendung vor der Definition von eslint-Fehlern zu verhindern, definieren wir loadHandler
        // hier als ein Let
        track.tech_.any(['vttjsloaded', 'vttjserror'], (event) => {
          if (event.type === 'vttjserror') {
            log.error(`vttjs konnte nicht geladen werden, der Versuch, ${track.src} zu verarbeiten, wurde abgebrochen`);
            rückkehr;
          }
          return parseCues(responseBody, track);
        });
      }
    } else {
      parseCues(responseBody, track);
    }

  }));
};

/**
 * Eine Darstellung einer einzelnen "TextSpur".
 *
 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack}
 * @erweitert Spur
 * /
class TextTrack extends Track {

  /**
   * Erstellen Sie eine Instanz dieser Klasse.
   *
   * @param {Object} options={}
   *        Objekt der Optionsnamen und -werte
   *
   * @param {Tech} options.tech
   *        Ein Verweis auf den Techniker, dem dieser TextTrack gehört.
   *
   * @param {TextTrack~Kind} [options.kind='subtitles']
   *        Eine gültige Textspurart.
   *
   * @param {TextTrack~Mode} [options.mode='disabled']
   *        Ein gültiger Textspurmodus.
   *
   * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
   *        Eine eindeutige ID für diesen TextTrack.
   *
   * @param {string} [options.label='']
   *        Die Menübezeichnung für diesen Titel.
   *
   * @param {string} [options.language='']
   *        Ein gültiger zweistelliger Sprachcode.
   *
   * @param {string} [options.srclang='']
   *        Ein gültiger zweistelliger Sprachcode. Eine alternative, aber depriorisierte
   *        version von `options.language`
   *
   * @param {string} [options.src]
   *        Eine Url zu TextTrack-Stichwörtern.
   *
   * @param {boolean} [options.default]
   *        Ob diese Spur standardmäßig ein- oder ausgeschaltet sein soll.
   * /
  constructor(options = {}) {
    if (!options.tech) {
      throw new Error('Ein Techniker wurde nicht bereitgestellt.');
    }

    const settings = merge(options, {
      art: TextTrackKind[options.kind] || 'Untertitel',
      sprache: options.language || options.srclang || ''
    });
    let mode = TextTrackMode[settings.mode] || 'disabled';
    const default_ = settings.default;

    if (einstellungen.art === 'metadaten' || einstellungen.art === 'kapitel') {
      modus = 'versteckt';
    }
    super(Einstellungen);

    this.tech_ = settings.tech;

    this.cues_ = [];
    this.activeCues_ = [];

    this.preload_ = this.tech_.preloadTextTracks !== false;

    const cues = new TextTrackCueList(this.cues_);
    const activeCues = new TextTrackCueList(this.activeCues_);
    let changed = false;

    this.timeupdateHandler = Fn.bind(this, function(event = {}) {
      if (this.tech_.isDisposed()) {
        rückkehr;
      }

      if (!this.tech_.isReady_) {
        if (event.type !== 'timeupdate') {
          this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
        }

        rückkehr;
      }

      // Zugriff auf this.activeCues für die Nebeneffekte der Selbstaktualisierung
      // aufgrund seiner Natur als Getter-Funktion. Nicht entfernen, sonst werden Cues
      // Stoppen Sie die Aktualisierung!
      // Verwenden Sie den Setter, um das Löschen von uglify zu verhindern (pure_getters-Regel)
      this.activeCues = this.activeCues;
      if (geändert) {
        this.trigger('cuechange');
        geändert = falsch;
      }

      if (event.type !== 'timeupdate') {
        this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
      }

    });

    const disposeHandler = () => {
      this.stopTracking();
    };

    this.tech_.one('dispose', disposeHandler);
    if (Modus !== 'deaktiviert') {
      this.startTracking();
    }

    Object.defineProperties(this, {
      /**
       * @Mitglied von TextTrack
       * @member {boolean} default
       *         Wenn diese Spur standardmäßig ein- oder ausgeschaltet ist. Kann nicht geändert werden nach
       *         erstellung.
       * @Instanz
       *
       * @readonly
       * /
      standard: {
        get() {
          return default_;
        },
        set() {}
      },

      /**
       * @Mitglied von TextTrack
       * @member {string} mode
       *         Setzt den Modus dieses TextTracks auf einen gültigen {@link TextTrack~Mode}. Will
       *         nicht gesetzt werden, wenn sie auf einen ungültigen Modus eingestellt sind.
       * @Instanz
       *
       * @feuert TextTrack#Moduswechsel
       * /
      modus: {
        get() {
          rückkehrmodus;
        },
        set(newMode) {
          if (!TextTrackMode[newMode]) {
            rückkehr;
          }
          if (mode === newMode) {
            rückkehr;
          }

          modus = newMode;
          if (!this.preload_ && mode !== 'disabled' && this.cues.length === 0) {
            // Last auf Abruf.
            loadTrack(this.src, this);
          }
          this.stopTracking();

          if (Modus !== 'deaktiviert') {
            this.startTracking();
          }
          /**
           * Ein Ereignis, das ausgelöst wird, wenn sich der Modus auf dieser Spur ändert. Dies ermöglicht
           * die TextTrackList, die diesen Track enthält, um entsprechend zu handeln.
           *
           * > Anmerkung: Dies ist nicht Teil der Spezifikation!
           *
           * @Ereignis TextTrack#Moduswechsel
           * @Typ {EventTarget~Event}
           * /
          this.trigger('modechange');

        }
      },

      /**
       * @Mitglied von TextTrack
       * @member {TextTrackCueList} cues
       *         Die Texttrack-Cue-Liste für diesen TextTrack.
       * @Instanz
       * /
      stichwörter: {
        get() {
          if (!this.loaded_) {
            null zurückgeben;
          }

          hinweise zurückgeben;
        },
        set() {}
      },

      /**
       * @Mitglied von TextTrack
       * @member {TextTrackCueList} activeCues
       *         Die Liste der Text-Track-Cues, die derzeit für diesen TextTrack aktiv sind.
       * @Instanz
       * /
      activeCues: {
        get() {
          if (!this.loaded_) {
            null zurückgeben;
          }

          // nichts zu tun
          if (this.cues.length === 0) {
            return activeCues;
          }

          const = this.tech_.currentTime();
          const active = [];

          for (let i = 0, l = this.cues.length; i < l; i++) {
            const cue = this.cues[i];

            if (cue.startTime <= ct && cue.endTime >= ct) {
              active.push(cue);
            } else if (cue.startTime === cue.endTime &&
                       cue.startTime <= ct &&
                       cue.startTime + 0.5 >= ct) {
              active.push(cue);
            }
          }

          geändert = falsch;

          if (active.length !== this.activeCues_.length) {
            geändert = wahr;
          } else {
            for (let i = 0; i < active.length; i++) {
              if (this.activeCues_.indexOf(active[i]) === -1) {
                geändert = wahr;
              }
            }
          }

          this.activeCues_ = active;
          activeCues.setCues_(this.activeCues_);

          return activeCues;
        },

        /!\ Diesen Setter leer lassen (siehe den Timeupdate-Handler oben)
        set() {}
      }
    });

    if (einstellungen.src) {
      this.src = settings.src;
      if (!this.preload_) {
        // Tracks werden bei Bedarf geladen.
        // Tu so, als ob wir für andere Zwecke geladen wären.
        this.loaded_ = true;
      }
      if (this.preload_ || (settings.kind !== 'subtitles' && settings.kind !== 'captions')) {
        loadTrack(this.src, this);
      }
    } else {
      this.loaded_ = true;
    }
  }

  startTracking() {
    // Präzisere Hinweise auf der Grundlage von requestVideoFrameCallback mit einem requestAnimationFram-Fallback
    this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
    // Höre auch auf timeupdate, falls rVFC/rAF stoppt (Fenster im Hintergrund, Audio im Video el)
    this.tech_.on('timeupdate', this.timeupdateHandler);
  }

  stopTracking() {
    if (this.rvf_) {
      this.tech_.cancelVideoFrameCallback(this.rvf_);
      this.rvf_ = undefiniert;
    }
    this.tech_.off('timeupdate', this.timeupdateHandler);
  }

  /**
   * Fügen Sie der internen Liste von Stichwörtern ein Stichwort hinzu.
   *
   * @param {TextTrack~Cue} cue
   *        Das Stichwort, um unsere interne Liste zu ergänzen
   * /
  addCue(originalCue) {
    let cue = originalCue;

    if (window.vttjs && !(originalCue instanceof window.vttjs.VTTCue)) {
      cue = new window.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);

      for (const prop in originalCue) {
        if (!(prop in cue)) {
          cue[prop] = originalCue[prop];
        }
      }

      // Sicherstellen, dass `id` übernommen wird
      cue.id = originalCue.id;
      cue.originalCue_ = originalCue;
    }

    const tracks = this.tech_.textTracks();

    for (let i = 0; i < tracks.length; i++) {
      if (tracks[i] !== this) {
        tracks[i].removeCue(cue);
      }
    }

    this.cues_.push(cue);
    this.cues.setCues_(this.cues_);
  }

  /**
   * Entfernen eines Stichworts aus unserer internen Liste
   *
   * @param {TextTrack~Cue} removeCue
   *        Das Stichwort zum Entfernen aus unserer internen Liste
   * /
  removeCue(removeCue) {
    let i = this.cues_.length;

    while (i--) {
      const cue = this.cues_[i];

      if (cue === removeCue || (cue.originalCue_ && cue.originalCue_ === removeCue)) {
        this.cues_.splice(i, 1);
        this.cues.setCues_(this.cues_);
        pause;
      }
    }
  }
}

/**
 * cuechange - Ein oder mehrere Cues im Track sind aktiv geworden oder haben aufgehört, aktiv zu sein.
 * /
TextTrack.prototype.allowedEvents_ = {
  cuechange: "cuechange" (Stichwortwechsel)
};

standard-TextSpur exportieren;