/**
 * @module
 * Fonctions permettant la recherche approximative de termes.
 */

import * as diacritics from 'diacritics';

/**
 * Motifs de désuffixation des mots français.
 */
const stemPatterns = [
    [/aux$/, 'al'],
    [/(.)s$/, '$1'],
    [/(.)e$/, '$1'],
];

/**
 * Motif de séparation des mots.
 */
const splitPattern = /[\s-]+/g;

/**
 * Désuffixe un mot français.
 *
 * @param word Mot originel.
 * @return Mot désuffixé.
 */
const stemWord = word =>
{
    let result = word;

    for (let [pattern, replacement] of stemPatterns)
    {
        result = result.replace(pattern, replacement);
    }

    return result;
};

/**
 * Met le nom d’un terme sous forme normalisée pour la recherche approximative.
 *
 * Dans la forme normalisée, tous les accents sont ôtés, la casse est réduite
 * en minuscules et les mots sont désuffixés.
 *
 * @param name Nom à normaliser.
 * @return Liste des mots du nom de terme normalisé.
 */
const normalizeName = name =>
    name.toLowerCase()
        .split(splitPattern)
        .map(stemWord)
        .map(word => diacritics.remove(word));

/**
 * Filtre une liste de termes pour ne garder que ceux qui sont similaires à une
 * saisie.
 *
 * @param search Contenu de la saisie.
 * @param term Terme à vérifier.
 * @return Ensemble des termes sélectionnés.
 */
export const filterTerms = (search, terms) =>
{
    // Normalisation des mots recherchés
    const needle = normalizeName(search);

    return terms.filter(term =>
    {
        // Normalisation du nom et des alias du terme
        const haystack = [term.name].concat(term.alias)
            .map(normalizeName)
            .reduce((prev, next) => prev.concat(next), []);

        return needle.every(item =>
            haystack.some(word =>
                word.startsWith(item)
            )
        );
    }).sort((term1, term2) => term2.weight - term1.weight);
};
