/**
 * @file fn.js
 * @module fn
 */
import { newGUID } from './guid.js' ;
import window from 'global/window' ;

export const UPDATE_REFRESH_INTERVAL = 30 ;

/**
 * Bind (ou proxy ou contexte). Une méthode simple pour changer le contexte de
 * une fonction.
 *
 * Il stocke également un identifiant unique sur la fonction afin qu'elle puisse être facilement retirée de la base de données
 * événements.
 *
 * @fonction
 * @param {Mixed} context
 *           L'objet à lier en tant que champ d'application.
 *
 * @param {Fonction} fn
 *           La fonction à lier à un champ d'application.
 *
 * @param {number} [uid]
 *           Un identifiant unique facultatif pour la fonction à définir
 *
 * @return {Fonction}
 *           La nouvelle fonction qui sera liée au contexte donné
 */
export const bind = function(context, fn, uid) {
  // S'assurer que la fonction a un identifiant unique
  if (!fn.guid) {
    fn.guid = newGUID() ;
  }

  // Créer la nouvelle fonction qui modifie le contexte
  const bound = fn.bind(context) ;

  // Permettre d'individualiser cette fonction
  // Nécessaire dans le cas où plusieurs objets peuvent partager le même prototype
  // SI les deux éléments ajoutent un écouteur d'événement avec la même fonction, alors vous essayez d'en supprimer un seul
  // il supprimera les deux car ils ont tous les deux le même guid.
  // si vous utilisez cette méthode, vous devez également utiliser la méthode bind lorsque vous supprimez l'écouteur.
  // actuellement utilisé dans les pistes de texte
  bound.guid = (uid) ? uid + '_' + fn.guid : fn.guid ;

  retour lié ;
};

/**
 * Enveloppe la fonction donnée, `fn`, avec une nouvelle fonction qui n'invoque que `fn`
 * au maximum une fois toutes les `attentes` millisecondes.
 *
 * @fonction
 * @param {Fonction} fn
 *           La fonction à étrangler.
 *
 * @param {number} wait
 *           Le nombre de millisecondes dont il faut tenir compte pour l'étranglement.
 *
 * @return {Fonction}
 */
export const throttle = function(fn, wait) {
  let last = window.performance.now() ;

  const throttled = function(...args) {
    const now = window.performance.now() ;

    if (now - last >= wait) {
      fn(...args) ;
      dernier = maintenant ;
    }
  };

  retour étranglé ;
};

/**
 * Création d'une fonction débridée qui retarde l'invocation de `func` jusqu'à la fin de `wait`
 * millisecondes se sont écoulées depuis la dernière fois que la fonction débitée a été
 * invoquée.
 *
 * Inspiré par les implémentations lodash et underscore.
 *
 * @fonction
 * @param {Fonction} func
 *           La fonction à envelopper avec le comportement de rebond.
 *
 * @param {number} wait
 *           Le nombre de millisecondes à attendre après la dernière invocation.
 *
 * @param {boolean} [immediate]
 *           Indique si la fonction doit être invoquée immédiatement après la création.
 *
 * @param {Objet} [context=window]
 *           Le "contexte" dans lequel la fonction débitée doit être débitée. Pour
 *           par exemple, si cette fonction doit être liée à un lecteur Video.js,
 *           le joueur peut être passé ici. Alternativement, la valeur par défaut est le
 *           l'objet global `window`.
 *
 * @return {Fonction}
 *           Une fonction débaptisée.
 */
export const debounce = function(func, wait, immediate, context = window) {
  laisser le temps s'écouler ;

  const cancel = () => {
    context.clearTimeout(timeout) ;
    timeout = null ;
  };

  /* eslint-disable consistent-this */
  const debounced = function() {
    const self = this ;
    const args = arguments ;

    let later = function() {
      timeout = null ;
      plus tard = null ;
      if (!immediate) {
        func.apply(self, args) ;
      }
    };

    if (!timeout && immediate) {
      func.apply(self, args) ;
    }

    context.clearTimeout(timeout) ;
    timeout = context.setTimeout(later, wait) ;
  };
  /* eslint-enable consistent-this */

  debounced.cancel = cancel ;

  retour débouclé ;
};