/* global Fapi,Fql */

/**
 * Objet permettant de stocker des éléments récupérés par l'API Ajax * 
 * 
 * @constructor
  */
Fapi.Cache = function () {
    this.fapiMap = new Map();
    this.thesaurusMap = new Map();
    this.fichesMap = new Map();
};


/**
 * 
 * Rétrocompatibilité
 */
Fapi.Wrapper = Fapi.Cache;

Fapi.Cache.prototype.getFapi = function (name) {
    name = this.checkName(name);
    return this.fapiMap.get(name);
};


/**
 * Retourne le thésaurus correspondant à la clé en argument
 * 
 * @param {string} key Clé du thésaurus 
 * @returns {Fapi.Cache.Thesaurus} Objet Thesaurus
 */
Fapi.Cache.prototype.getThesaurus = function (key) {
    return this.thesaurusMap.get(key);
};


/**
 * Retourne l'objet Fiches correspondant à la clé en argument
 * 
 * @param {string} key Clé d'un ensemble fiches
 * @returns {Fapi.Cache.Fiches} Objet Fiches
 */
Fapi.Cache.prototype.getFiches = function (key) {
    return this.fichesMap.get(key);
};

Fapi.Cache.prototype.putFapi = function (name, fapiArguments) {
    name = this.checkName(name);
    var fapiMap = this.fapiMap;
    if (fapiMap.has(name)) {
        let currentFapi = fapiMap.get(name);
        if (fapiArguments.fichothequeUrl) {
            currentFapi.fichothequeUrl = fapiArguments.fichothequeUrl;
        }
        currentFapi.checkOptions(fapiArguments);
        return currentFapi;
    } else {
        let newFapi = new Fapi(fapiArguments);
        fapiMap.set(name, newFapi);
        return newFapi;
    }
};


/**
 * Retourne une fonction d'appel de l'API, cette fonction prend comme argument
 * une fonction de retour pour permettre le chainage 
 * 
 * @param {Fapi} fapi Configuration à utiliser
 * @param {string} thesaurusName Nom du thésaurus
 * @param {string} thesaurusKey Clé du thésaurus à utiliser au lieu du nom du thésaurus
 * @param {Object} options Options de l'appel
 * @param {string} options.propertiesMapping Nom de l'export tabulaire à utiliser pour définir les propriétés d'un mot-clé
 * @returns {function} Fonction d'appel de l'API
 */
Fapi.Cache.prototype.initThesaurus = function (thesaurusInit) {
    var thesaurusMap = this.thesaurusMap;
    return function (callback) {
        var thesaurusArgs = {
            thesaurus: thesaurusInit.name,
            callback: function (data) {
                let thesaurus = new Fapi.Cache.Thesaurus(data);
                thesaurusMap.set(thesaurusInit.key, thesaurus);
                if (callback) {
                    callback();
                }
            }
        };
        if (thesaurusInit.propertiesMapping) {
            thesaurusArgs.propertiesMapping = thesaurusInit.propertiesMapping;
        }
        if (thesaurusInit.customRequestParameters) {
            thesaurusArgs.requestParameters =  Object.assign({}, thesaurusInit.customRequestParameters);
        }
        thesaurusInit.fapi.loadThesaurus(thesaurusArgs);
    };
};


/**
 * Retourne une fonction d'appel de l'API, cette fonction prend comme argument
 * une fonction de retour pour permettre le chainage 
 * 
 * @param {Fapi} fapi Configuration à utiliser
 * @param {string} fichesKey Clé à utiliser pour conserver le résultat
 * @param {Object} options Options de l'appel
 * @param {Object} options.propertiesMapping Nom de l'export tabulaire à utiliser pour définir les propriétés d'un mot-clé
 * @param {Fql.FicheQuery} options.Query Instance de Fql.FicheQuery indiquant les fiches à récupérer
 * @param {Object} options.ql Objet correspondant à un objet Options utilisé en argument du constructeur de Fql.FicheQuery 
 * @returns {function} Fonction d'appel de l'API
 */
Fapi.Cache.prototype.initFiches = function (fichesInit) {
    var fichesMap = this.fichesMap;
    return function (callback) {
        var fichesArgs = {
            callback: function (data) {
                let fiches = new Fapi.Cache.Fiches(data);
                fichesMap.set(fichesInit.key,fiches);
                if (callback) {
                    callback();
                }
            }
        };
        fichesArgs.ficheQueries = fichesInit.queries;
        if (fichesInit.propertiesMapping) {
            fichesArgs.propertiesMapping = fichesInit.propertiesMapping;
        }
        if (fichesInit.customRequestParameters) {
            fichesArgs.requestParameters = Object.assign({}, fichesInit.customRequestParameters);
        }
        if (fichesInit.sort) {
            if ((fichesArgs.requestParameters) && (!fichesArgs.requestParameters.sort)) {
                fichesArgs.requestParameters.sort = fichesInit.sort;
            } else {
                fichesArgs.requestParameters = {
                    sort: fichesInit.sort
                };
            }
        }
        fichesInit.fapi.loadFiches(fichesArgs);
    };
};

Fapi.Cache.prototype.checkName = function (name) {
    if (!name) {
        return "_current";
    }
    switch(name) {
        case "_default":
            return "_current";
        default:
            return name;
    }
};

/*
{
    fichotheques:  [
        {
            name: "",
            url: "",
            options: {
                version: "action",
                propertiesMapping: ""
            },
            thesaurus: [
                "name",
                {
                    name: "",
                    key: "",
                    propertiesMapping: ""
                    requestParameters: {

                    }
                }
            ],
            fiches: [
                {
                    key: "",
                    queries: "",
                    query: "",
                    sort: "",
                    propertiesMapping: ""
                    requestParameters: {

                    }
                }
            ]
        }
    ]
}
 */

Fapi.Cache.init = function (cacheSettings, callback) {
    var cache = new Fapi.Cache();
    var thesaurusInitArray = [];
    var fichesInitArray = [];
    var callbackDone = false;
    if (cacheSettings.fichotheques) {
        for(let fichotheque of cacheSettings.fichotheques) {
            _addFichotheque(fichotheque);
        }
    } else {
        _addFichotheque(cacheSettings);
    }
    
    if ((thesaurusInitArray.length > 0) || (fichesInitArray.length > 0)) {
        for(let thesaurusInit of thesaurusInitArray) {
            let initFunction = cache.initThesaurus(thesaurusInit);
            initFunction(function () {
               thesaurusInit.done = true;
               _checkInit();
            });
        }
        for(let fichesInit of fichesInitArray) {
            let initFunction = cache.initFiches(fichesInit);
            initFunction(function () {
               fichesInit.done = true;
               _checkInit();
            });
        }
    } else {
        callback(cache);
    }
    
    function _addFichotheque(fichotheque) {
        let fichothequeName = cache.checkName(fichotheque.name);
        let fichothequePrefix = "";
        if (fichothequeName !== "_current") {
            fichothequePrefix = fichothequeName + "/";
        }
        let fapi = cache.putFapi(fichothequeName, _buildFapiArguments(fichotheque));
        if (fichotheque.thesaurus) {
            for(let thesaurus of fichotheque.thesaurus) {
                if (typeof thesaurus === "string") {
                    thesaurusInitArray.push({
                        name: thesaurus,
                        key: fichothequePrefix + thesaurus,
                        fapi: fapi,
                        done: false
                    });
                } else {
                    let name = thesaurus.name;
                    if (name) {
                        let thesaurusKey = fichothequePrefix + name;
                        if (thesaurus.key) {
                            thesaurusKey = thesaurus.key;
                        }
                        thesaurusInitArray.push({
                            name: name,
                            key: thesaurusKey,
                            fapi: fapi,
                            done: false,
                            customRequestParameters: thesaurus.requestParameters,
                            propertiesMapping: thesaurus.propertiesMapping
                        });
                    }
                }
            }
        }
        if (fichotheque.fiches) {
            for(let fiches of fichotheque.fiches) {
                let queries;
                if (fiches.query) {
                    queries = fiches.query;
                } else if (fiches.queries) {
                    queries = fiches.queries;
                } else {
                    queries = {
                        corpus: fiches.key
                    };
                }
                fichesInitArray.push({
                    key: fiches.key,
                    fapi: fapi,
                    queries: queries,
                    sort: fiches.sort,
                    customRequestParameters: fiches.requestParameters,
                    propertiesMapping: fiches.propertiesMapping,
                    done: false 
                });
            }
        }
    }
    
    function _buildFapiArguments(fichotheque) {
        let fapiArguments = {};
        let fichothequeUrl = fichotheque.url;
        if (!fichothequeUrl) {
            fichothequeUrl = "";
        }
        fapiArguments.fichothequeUrl = fichothequeUrl;
        if (fichotheque.api) {
            fapiArguments.api = fichotheque.api;
        }
        let options = fichotheque.options;
        if (options) {
            for(let propKey in options) {
                fapiArguments[propKey] = options[propKey];
            }
        }
        return fapiArguments;
    }
    
    function _checkInit() {
        let allDone = true;
        if (allDone) {
            for(let thesaurusInit of thesaurusInitArray) {
                if (!thesaurusInit.done) {
                    allDone = false;
                    break;
                }
            }
        }
        if (allDone) {
            for(let fichesInit of fichesInitArray) {
                if (!fichesInit.done) {
                    allDone = false;
                    break;
                }
            }
        }
        if ((allDone) && (!callbackDone)) {
            callbackDone = true;
            callback(cache);
        }
    }

};
