Source: utils/AudioTracksUtils.js

/**
 * Check if the kind is of audio description type.
 *
 * @param {String} kind indicates the category of the audio
 *
 * @returns {Boolean} true if audio description, false otherwise
 */
function isAudioDescription(kind) {
  return ['description', 'descriptions', 'main-desc'].includes(kind);
}


/**
 * Check if the kind is of regular audio type.
 *
 * @param {String} kind indicates the category of the audio
 *
 * @returns {Boolean} true if regular audio, false otherwise
 */
function isRegularTrack(kind) {
  return ['alternative', 'main', 'translation'].includes(kind);
}

/**
 * Find the active track.
 *
 * @param {Array} tracks array of audio tracks
 *
 * @returns {Object|undefined} the active track or undefine if no track is active
 */
function findActiveTrack(tracks) {
  return Array.from(tracks).find(({ enabled }) => enabled);
}

/**
 * Find all audio tracks by language regardless of type.
 *
 * @param {*} language language code
 * @param {Array} tracks array of audio tracks
 *
 * @returns {Array}
 */
function findAllTracksByLanguage(language, tracks) {
  return tracks.filter(track => track.language === language);
}

/**
 * Find a track by language.
 *
 * @param {String} language language code
 * @param {Array} tracks array of audio tracks
 * @returns {Object|undefined} the track or undefined if no track correspond to the language.
 */
function findTrackByLanguage(language, tracks) {
  return tracks.find(track => track.language === language);
}

/**
 * Find an audio described track by language.
 *
 * @param {String} language language code
 * @param {Array} tracks array of audio tracks
 *
 * @returns {Object|undefined} the track or undefined if no audio described track is found.
 */
function findAudioDescriptionTrackByLanguage(language, tracks) {
  return tracks.find(track => track.language === language && isAudioDescription(track.kind));
}

/**
 * Check if a language exists in a track list.
 *
 * @param {String} language language code
 * @param {Array} tracks array of audio tracks
 *
 * @returns {Boolean} true if the language exists false otherwise
 */
function hasLanguageTrack(language, tracks) {
  return !!findTrackByLanguage(language, tracks);
}

/**
 * Check if a specific language is audio described.
 *
 * @param {String} language language code
 * @param {Array} tracks array of audio tracks
 *
 * @returns {Boolean} true if and audio described track exists false otherwise
 */
function hasAudioDescriptionLanguageTrack(language, tracks) {
  return !!findAudioDescriptionTrackByLanguage(language, tracks);
}

/**
 * Check if the track list contains only the audio description for a given language.
 *
 * @param {String} language language code
 * @param {Array} tracks array of audio tracks
 *
 * @returns {Boolean} true if it only contains audio description, false otherwise
 */
function isLanguageOnlyAudioDescription(language, tracks) {
  const hasDescription = hasAudioDescriptionLanguageTrack(language, tracks);
  const onlyHasDescription = findAllTracksByLanguage(language, tracks)
    .filter(track => isRegularTrack(track.kind)).length === 0;

  return hasDescription && onlyHasDescription;
}

/**
 * Format an object or AudioTrack  to .
 *
 * @param {Object|AudioTrack} obj
 * @property {String} obj.kind indicates the category of the audio
 * @property {String} obj.language language code
 *
 * @returns {Object|undefined} returns an object containing the language and description properties, undefined otherwise
 */
function format(
  {
    language, kind,
  } = {},
) {
  if (language) {
    return {
      language,
      description: isAudioDescription(kind),
    };
  }

  return undefined;
}

/**
 * Sanitize the parameter.
 *
 * @param {Object} value
 *
 * @returns {Object}
 */
function sanitizeParameter(value) {
  if (typeof value !== 'object' && value !== undefined) {
    const language = value;

    return format({ language });
  }

  return value;
}

/**
 * Tries to activate the audio track according to the language and description properties.
 * - Do nothing if the language does not exist in the list of audio tracks.
 * - If the description property is true but no audio matches, the language is used to enable audio as default behavior.
 * - If the description property is false but no regular audio matches, the audio described language is used as default behavior.
 *
 * @param {Object} obj contains a language and a description property
 * @property {String} obj.language language code
 * @property {Boolean} obj.description true if audio described false otherwise
 * @param {AudioTrackList} tracks audio track list
 */
function enableTrack({ language, description = false }, tracks) {
  if (!hasLanguageTrack(language, tracks)) return;

  if (!hasAudioDescriptionLanguageTrack(language, tracks)
    || isLanguageOnlyAudioDescription(language, tracks)) {
    tracks.forEach((track) => {
      // eslint-disable-next-line no-param-reassign
      track.enabled = track.language === language;
    });

    return;
  }

  tracks.forEach((track) => {
    // eslint-disable-next-line no-param-reassign
    track.enabled = track.language === language
      && typeof description === 'boolean'
      && description === isAudioDescription(track.kind);
  });
}

export default {
  enableTrack,
  findActiveTrack,
  findAudioDescriptionTrackByLanguage,
  findTrackByLanguage,
  format,
  hasAudioDescriptionLanguageTrack,
  hasLanguageTrack,
  isAudioDescription,
  isRegularTrack,
  sanitizeParameter,
};