/**
 * @Datei create-logger.js
 * @modul create-logger
 * /
import window from 'global/window';

// Dies ist die private Tracking-Variable für den Protokollierungsverlauf.
let history = [];

/**
 * Protokollierung von Meldungen auf der Konsole und im Verlauf je nach Art der Meldung
 *
 * @privat
 * @param {string} type
 *         Der Name der zu verwendenden Konsolenmethode.
 *
 * @param {Array} args
 *         Die Argumente, die an die entsprechende Konsolenmethode übergeben werden.
 * /
const LogByTypeFactory = (name, log) => (type, level, args) => {
  const lvl = log.levels[level];
  const lvlRegExp = new RegExp(`^(${lvl})$`);

  if (type !== 'log') {

    // Fügen Sie den Typ am Anfang der Nachricht hinzu, wenn er nicht "log" lautet.
    args.unshift(type.toUpperCase() + ':');
  }

  // Konsolenpräfix nach dem Hinzufügen zur Historie hinzufügen.
  args.unshift(name + ':');

  // Fügen Sie einen Klon der Argumente an diesem Punkt zur Historie hinzu.
  wenn (Geschichte) {
    history.push([].concat(args));

    // nur 1000 Historieneinträge speichern
    const splice = history.length - 1000;

    history.splice(0, splice > 0 ? splice : 0);
  }

  // Wenn keine Konsole vorhanden ist, wird nicht versucht, Meldungen auszugeben, aber sie werden ausgegeben
  // noch in der Historie gespeichert werden.
  if (!window.console) {
    rückkehr;
  }

  // Wurde einmal außerhalb dieser Funktion gesetzt, enthält sie aber
  // in der Funktion erleichtert das Testen von Fällen, in denen die Konsole nicht vorhanden ist
  // wenn das Modul ausgeführt wird.
  let fn = window.console[type];

  if (!fn && type === 'debug') {
    // Bestimmte Browser haben keine Unterstützung für console.debug. Für diese, wir
    // sollte das nächstgelegene vergleichbare Protokoll verwendet werden.
    fn = window.console.info || window.console.log;
  }

  // Bailout, wenn es keine Konsole gibt oder wenn dieser Typ nicht durch die Konsole erlaubt ist
  // aktuelle Protokollierungsstufe.
  if (!fn || !lvl || !lvlRegExp.test(type)) {
    rückkehr;
  }

  fn[Array.isArray(args) ? 'apply' : 'call'](window.console, args);
};

export default function createLogger(name) {
  // Dies ist die private Tracking-Variable für die Protokollierungsstufe.
  let level = 'info';

  // der kurierte logByType, der an das spezifische Protokoll und den Verlauf gebunden ist
  let logByType;

  /**
   * Protokolliert einfache Debug-Meldungen. Ähnlich wie `console.log`.
   *
   * 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
   * ##### *args
   * Gemischt[]
   *
   * Jede Kombination von Werten, die an `console.log()` übergeben werden können.
   *
   * #### Rückgabewert
   *
   * undefiniert
   *
   * @Namensraum
   * @param {Mixed[]} args
   *           Eine oder mehrere Meldungen oder Objekte, die protokolliert werden sollen.
   * /
  const log = function(...args) {
    logByType('log', level, args);
  };

  // Dies ist die logByType-Hilfsfunktion, die von den folgenden Protokollierungsmethoden verwendet wird
  logByType = LogByTypeFactory(name, log);

  /**
   * Erstellen Sie einen neuen Sublogger, der den alten Namen mit dem neuen Namen verknüpft.
   *
   * Wenn Sie zum Beispiel `videojs.log.createLogger('player')` ausführen und dann diesen Logger verwenden, wird Folgendes aufgezeichnet:
   * ``js
   *  mylogger('foo');
   *  // > VIDEOJS: player: foo
   * ```
   *
   * @param {string} name
   *        Der Name, der den neuen Logger aufrufen soll
   * @return {Object}
   * /
  log.createLogger = (subname) => createLogger(name + ': ' + subname);

  /**
   * Aufzählung der verfügbaren Protokollierungsebenen, wobei die Schlüssel die Namen der Ebenen sind
   * und die Werte sind `|`-getrennte Zeichenketten, die erlaubte Protokollierungsmethoden enthalten
   * in dieser Protokollierungsebene. Diese Zeichenketten werden verwendet, um einen regulären Ausdruck zu erstellen
   * die mit dem Namen der aufgerufenen Funktion übereinstimmt.
   *
   * Die von Video.js bereitgestellten Levels sind:
   *
   * - aus": Entspricht keinen Anrufen. Jeder Wert, der in "False" umgewandelt werden kann, hat
   *   diese Wirkung. Am restriktivsten.
   * - alle": Entspricht nur den von Video.js bereitgestellten Funktionen (`debug`, `log`,
   *   `log.warn` und `log.error`).
   * - Debuggen": Entspricht den Aufrufen `log.debug`, `log`, `log.warn` und `log.error`.
   * - info" (Voreinstellung): Entspricht den Aufrufen `log`, `log.warn` und `log.error`.
   * - Warnung": Entspricht den Aufrufen `log.warn` und `log.error`.
   * - `Fehler`: Passt nur auf `log.error`-Aufrufe.
   *
   * @Typ {Objekt}
   * /
  log.levels = {
    all: 'debug|log|warn|error',
    aus: '',
    debug: 'debug|log|warn|error',
    info: 'log|warn|error',
    warn: 'warn|fehler',
    fehler: "Fehler",
    DEFAULT: Niveau
  };

  /**
   * Abrufen oder Einstellen der aktuellen Protokollierungsstufe.
   *
   * Wenn eine Zeichenkette, die einem Schlüssel aus {@link module:log.levels} entspricht, angegeben wird, wird
   * als Einrichter.
   *
   * @param {string} [lvl]
   *         Übergeben Sie eine gültige Stufe, um eine neue Protokollierungsstufe festzulegen.
   *
   * @return {string}
   *         Die aktuelle Protokollierungsstufe.
   * /
  log.level = (lvl) => {
    if (typeof lvl === 'string') {
      if (!log.levels.hasOwnProperty(lvl)) {
        throw new Error(`"${lvl}" ist keine gültige Protokollstufe`);
      }
      level = lvl;
    }
    rückgabeebene;
  };

  /**
   * Gibt ein Array zurück, das alles enthält, was in der Historie protokolliert wurde.
   *
   * Dieses Array ist ein oberflächlicher Klon des internen Verlaufsdatensatzes. Allerdings ist die
   * der Inhalt wird _nicht_ geklont; daher wird das Ändern von Objekten innerhalb dieses Arrays
   * sie in der Geschichte mutieren.
   *
   * @return {Array}
   * /
  log.history = () => history ? [].concat(history) : [];

  /**
   * Ermöglicht das Filtern der Historie nach dem angegebenen Loggernamen
   *
   * @param {string} fname
   *        Der Name, nach dem gefiltert werden soll
   *
   * @return {Array}
   *         Die gefilterte Liste, die zurückgegeben werden soll
   * /
  log.history.filter = (fname) => {
    return (history || []).filter((historyItem) => {
      // wenn der erste Eintrag in jedem historyItem `fname` enthält, dann ist es eine Übereinstimmung
      return new RegExp(`.*${fname}.*`).test(historyItem[0]);
    });
  };

  /**
   * Löscht die interne Historienverfolgung, verhindert aber nicht weitere Historien
   * verfolgung.
   * /
  log.history.clear = () => {
    wenn (Geschichte) {
      history.length = 0;
    }
  };

  /**
   * Deaktivieren Sie die Verlaufsverfolgung, wenn sie derzeit aktiviert ist.
   * /
  log.history.disable = () => {
    if (Geschichte !== null) {
      history.length = 0;
      geschichte = null;
    }
  };

  /**
   * Aktivieren Sie die Verlaufsverfolgung, wenn sie derzeit deaktiviert ist.
   * /
  log.history.enable = () => {
    if (Geschichte === null) {
      geschichte = [];
    }
  };

  /**
   * Protokolliert Fehlermeldungen. Ähnlich wie `console.error`.
   *
   * @param {Mixed[]} args
   *        Eine oder mehrere Meldungen oder Objekte, die als Fehler protokolliert werden sollen
   * /
  log.error = (...args) => logByType('error', level, args);

  /**
   * Protokolliert Warnmeldungen. Ähnlich wie `console.warn`.
   *
   * @param {Mixed[]} args
   *        Eine oder mehrere Meldungen oder Objekte, die als Warnung protokolliert werden sollen.
   * /
  log.warn = (...args) => logByType('warn', level, args);

  /**
   * Protokolliert Debug-Meldungen. Ähnlich wie `console.debug`, kann aber auch als vergleichbare
   * protokollieren, wenn `console.debug` nicht verfügbar ist
   *
   * @param {Mixed[]} args
   *        Eine oder mehrere Meldungen oder Objekte, die als Debug protokolliert werden sollen.
   * /
  log.debug = (...args) => logByType('debug', level, args);

  protokoll zurückgeben;
}