/**
 * Fonctions utilitaires de manipulation d'objets.
 *
 * @module
 */

const EMPTY = Object.freeze({});

/**
 * Applique Object.freeze l'objet et à ses attributs.
 * @param {any} obj
 * @returns objet immuable
 */
export const deepFreeze = (obj) => {
    Object.keys(obj).forEach((prop) => {
        if (typeof obj[prop] === 'object') deepFreeze(obj[prop]);
    });
    return Object.freeze(obj);
};

/**
 * Créé un objet immuable dont les clés et les valeurs sont les mêmes que l'élément ou les éléments du tableau.
 * La fonction est prévue pour les chaînes mais est assez permissive.
 *
 * Ex:
 * createConstantsFrom('a')         =>  { a: 'a' }
 * createConstantsFrom(['a', 'b'])  =>  { a: 'a', b: 'b' }
 *
 * @param {any} stringOrArray - toute donnée mais de préférence une chaîne ou un tableau de chaînes
 * @returns objet immuable
 */
export const createConstantsFrom = (stringOrArray) => {
    if (stringOrArray === undefined || stringOrArray === null || stringOrArray === '') {
        return EMPTY;
    }
    const input = Array.isArray(stringOrArray) ? stringOrArray : [stringOrArray];
    return deepFreeze(
        input.reduce((acc, val) => {
            acc[val] = val;
            return acc;
        }, {})
    );
};

/**
 * Indique une valeur non null, non undefined.
 * @param {any} val - valeur à tester
 * @returns true s'il ne s'agit pas de null ou undefined
 */
/** Indique une valeur non null, non undefined (et sert de type guard) */
export const isPresent = (val) => val !== undefined && val !== null;
