/**
 * @file time-ranges.js
 * @module time-ranges
 */
import window from 'global/window' ;

/**
 * Renvoie l'heure pour l'index spécifié au début ou à la fin
 * d'un objet TimeRange.
 *
 * @typedef {Fonction} TimeRangeIndex
 *
 * @param {number} [index=0]
 *             Le numéro de la plage pour laquelle l'heure doit être renvoyée.
 *
 * @return {number}
 *             Le décalage temporel à l'index spécifié.
 *
 * @deprecated L'argument index doit être fourni.
 *             À l'avenir, le fait de l'omettre entraînera une erreur.
 */

/**
 * Un objet qui contient des plages de temps.
 *
 * @typedef {Objet} Plage de temps
 *
 * @property {number} length
 *           Le nombre de plages horaires représentées par cet objet.
 *
 * @property {module:time-ranges~TimeRangeIndex} start
 *           Renvoie le décalage temporel à partir duquel commence un intervalle de temps spécifié.
 *
 * @property {module:time-ranges~TimeRangeIndex} end
 *           Renvoie le décalage temporel auquel se termine un intervalle de temps spécifié.
 *
 * voir https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
 */

/**
 * Vérifier si l'un des intervalles de temps est supérieur à l'indice maximal.
 *
 * @private
 * @param {string} fnName
 *          Le nom de la fonction à utiliser pour l'enregistrement
 *
 * @param {number} index
 *          L'index à vérifier
 *
 * @param {number} maxIndex
 *          L'indice maximal possible
 *
 * @throws {Error} if the timeRanges provided are over the maxIndex
 */
function rangeCheck(fnName, index, maxIndex) {
  if (typeof index !== 'number' || index < 0 || index > maxIndex) {
    throw new Error(`Echec de l'exécution de '${fnName}' sur 'TimeRanges' : L'index fourni (${index}) est non numérique ou hors limites (0-${maxIndex}).`) ;
  }
}

/**
 * Obtenir l'heure pour l'index spécifié au début ou à la fin
 * d'un objet TimeRange.
 *
 * @private
 * @param {string} fnName
 *             Le nom de la fonction à utiliser pour l'enregistrement
 *
 * @param {string} valueIndex
 *             La propriété qui doit être utilisée pour obtenir l'heure doit être
 *             début" ou "fin"
 *
 * @param {Array} ranges
 *             Un tableau d'intervalles de temps
 *
 * @param {Array} [rangeIndex=0]
 *             L'index à partir duquel la recherche doit être lancée
 *
 * @return {number}
 *             L'heure qui s'est décalée à l'index spécifié.
 *
 * @deprecated rangeIndex must be set to a value, in the future this will throw an error.
 * @throws {Error} if rangeIndex is more than the length of ranges
 */
function getRange(fnName, valueIndex, ranges, rangeIndex) {
  rangeCheck(fnName, rangeIndex, ranges.length - 1) ;
  return ranges[rangeIndex][valueIndex] ;
}

/**
 * Créer un objet d'intervalle de temps à partir d'intervalles de temps donnés.
 *
 * @private
 * @param {Array} [ranges]
 *          Un tableau d'intervalles de temps.
 */
function createTimeRangesObj(ranges) {
  let timeRangesObj ;

  if (ranges === undefined || ranges.length === 0) {
    timeRangesObj = {
      longueur : 0,
      start() {
        lancer une nouvelle erreur ('Cet objet TimeRanges est vide') ;
      },
      end() {
        lancer une nouvelle erreur ('Cet objet TimeRanges est vide') ;
      }
    };
  } else {
    timeRangesObj = {
      length : ranges.length,
      start : getRange.bind(null, 'start', 0, ranges),
      end : getRange.bind(null, 'end', 1, ranges)
    };
  }

  if (window.Symbol && window.Symbol.iterator) {
    timeRangesObj[window.Symbol.iterator] = () => (ranges || []).values() ;
  }

  return timeRangesObj ;
}

/**
 * Créer un objet `TimeRange` qui imite un objet
 * {@link https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges|HTML5 TimeRanges instance}.
 *
 * @param {number|Array[]} start
 *        Le début d'une plage unique (un nombre) ou d'un tableau de plages (un
 *        tableau de tableaux de deux nombres chacun).
 *
 * @param {number} end
 *        La fin d'une plage unique. Ne peut être utilisé avec la forme tableau de
 *        l'argument `start`.
 */
export function createTimeRanges(start, end) {
  if (Array.isArray(start)) {
    return createTimeRangesObj(start) ;
  } else if (start === undefined || end === undefined) {
    return createTimeRangesObj() ;
  }
  return createTimeRangesObj([[start, end]]) ;
}

export { createTimeRanges as createTimeRange } ;