/* global Fql */

/**
 * Objet d'accès à une fichothèque
 * L'objet options permet de conserver des options avec l'objet
 * 
 * @constructor
 * @param {string} fichothequeUrl URL de la fichothèque (doit être fini par un /)
 * @param {Object} options Options conservées par la configuration
  */
Fapi = function (fichothequeUrl, options) {
    var finalUrl = fichothequeUrl;
    var finalOptions = options;
    if (arguments.length === 1) {
        let firstArgument = arguments[0];
        if (typeof firstArgument === "string") {
            finalUrl = firstArgument;
            finalOptions = false;
        } else {
            finalUrl = firstArgument.fichothequeUrl;
            finalOptions = firstArgument;
        }
    }
    if (!finalUrl) {
        finalUrl = "";
    }
    this.fichothequeUrl = finalUrl;
    this.accessType = "private";
    this.accessToken = "";
    this.version = "action";
    this.apiName = "";
    this.options =   {};
    this.checkOptions(finalOptions);
};

Fapi.prototype.isPublicApi = function () {
    return (this.accessType === "public");
};

Fapi.prototype.isWithCredentials = function () {
    return (this.accessType === "private");
};

/**
 * Retourne l'URL correspondant à une action sur une fichothèque
 * 
 * @param {string} actionName Nom de l'action
 * @returns {string} URL de l'action
 */
Fapi.prototype.getActionUrl = function (actionName) {
    return this.fichothequeUrl + actionName;
};

Fapi.prototype.getApiUrl = function (name, version, endpoint) {
    return this.fichothequeUrl + "api/" + version + "/" + name + "/" + endpoint;
};


/**
 * Retourne l'URL correspondant à une action sur une fichothèque
 * 
 * @param {string} endPointName Nom du point de terminaison
 * @returns {Fapi.EndPoint} endPoint Définition du point de terminaison
 */
Fapi.prototype.getEndPoint = function (endPointName) {
    var fapi = this;
    switch(this.version) {
        case "action":
            return _getActionEndPoint();
        case "v1":
            return _getV1EndPoint();
        default:
            throw new Exception("Unknown version: " + this.version);
    }
    
    function _getActionEndPoint() {
        switch(endPointName) {
            case "fiche":
                return __newActionEndpoint("corpus", "fiche");
            case "fiche-array":
                return __newActionEndpoint("pioche", "fiche");
             case "motcle":
                return __newActionEndpoint("thesaurus", "motcle");
            case "motcle-array":
                return __newActionEndpoint("pioche", "motcle");
            case "fiches":
                return __newActionEndpoint("corpus", "fiches");
            case "thesaurus":
                return __newActionEndpoint("thesaurus", "thesaurus");
            default :
                throw new Exception("Unknown endpoint: " + endPointName);
        }
        
        function __newActionEndpoint(actionName, jsonName) {
            return fapi.getActionEndPoint(actionName, jsonName);
        }
        
    }
    
    function _getV1EndPoint() {
        switch(endPointName) {
            case "fiche":
                return __newV1EndPoint("fiche");
            case "fiche-array":
                return __newV1EndPoint("fiche-array");
            case "motcle":
                return __newV1EndPoint("motcle");
            case "motcle-array":
                return __newV1EndPoint("motcle-array");
             case "fiches":
                return __newV1EndPoint("fiches");
            case "thesaurus":
                return __newV1EndPoint("thesaurus");
            default :
                throw new Exception("Unknown endpoint: " + endPointName);
        }
        
        function __newV1EndPoint(name) {
            return new Fapi.EndPoint(fapi.getApiUrl(fapi.apiName, fapi.version, name), "", "v1");
        }
    }
 
};

Fapi.prototype.getActionEndPoint = function (actionName, jsonName) {
    return new Fapi.EndPoint(this.getActionUrl(actionName), jsonName, "action");
};


/**
 * Retourne l'URL de consultation d'une fiche
 * 
 * @param {string} corpus Nom du corpus
 * @param {number} id Identifiant de la fiche
 * @param {string} [format] Nom du gabarit d'affichage à utiliser
 * @returns {string} URL de la fiche
 */
Fapi.prototype.getFicheUrl = function (corpus, id, format) {
    var url = this.fichothequeUrl + "fiches/" + corpus + "-" + id;
    if (format) {
        url += "-" + format;
    }
    url = url + ".html";
    return url;
};

Fapi.prototype.checkOptions = function (source) {
    var fapi = this;
    if (!source) {
        return;
    }
    var accessType = "private";
    var accessToken = "";
    var publicApi = false;
    for(let key in source) {
        let value = source[key];
        switch(key) {
            case "fichothequeUrl":
                break;
            case "api":
                fapi.version = value.version;
                publicApi = value.public;
                fapi.apiName = value.name;
                break;
            case "version":
                fapi.version = value;
                break;
            case "public":
                publicApi = value;
                break;
            case "name":
                fapi.apiName = value;
                break;
            case "token":
                accessToken = value;
                break;
            default:
                fapi.options[key] = value;
        }
    }
    if (accessToken) {
        accessType = "token";
    } else if (publicApi) {
        accessType = "public";
    }
    fapi.accessType = accessType;
    fapi.accessToken = accessToken;
};

Fapi.prototype.ping = function (argObject) {
    Fapi.Ajax.exit(this, argObject);
};

Fapi.prototype.exit = function (argObject) {
    Fapi.Ajax.exit(this, argObject);
};

Fapi.prototype.loadFiche = function (argObject) {
    this.checkDefault(argObject);
    let corpus = argObject.corpus;
    let id = argObject.id;
    if (argObject.requestParameters) {
        if (corpus) {
            argObject.requestParameters.corpus = corpus;
        }
        if (id) {
            argObject.requestParameters.id = id;
        }
    } else {
        argObject.requestParameters = {
            corpus: corpus,
            id: id
        };
    }
    Fapi.Ajax.loadFiche(this, argObject);
};

Fapi.prototype.loadFicheArray = function (argObject) {
    this.checkDefault(argObject);
    let ficheQuery = argObject.ficheQuery;
    if (!(ficheQuery instanceof Fql.FicheQuery)) {
        ficheQuery = new Fql.FicheQuery(ficheQuery);
    }
    Fapi.Ajax.loadFicheArray(this, ficheQuery, argObject);
};

Fapi.prototype.loadMotcle = function (argObject) {
    this.checkDefault(argObject);
    let thesaurus = argObject.thesaurus;
    let id = argObject.id;
    let idalpha = argObject.idalpha;
    if (argObject.requestParameters) {
        if (thesaurus) {
            argObject.requestParameters.thesaurus = thesaurus;
        }
    } else {
        argObject.requestParameters = {
            thesaurus: thesaurus
        };
    }
    if (id) {
        argObject.requestParameters.id = id;
    }
    if (idalpha) {
        argObject.requestParameters.idalpha = idalpha;
    }
    Fapi.Ajax.loadMotcle(this, argObject);
};


Fapi.prototype.loadMotcleArray = function (argObject) {
    this.checkDefault(argObject);
    let motcleQuery = argObject.motcleQuery;
    if (!(motcleQuery instanceof Fql.MotcleQuery)) {
        motcleQuery = new Fql.MotcleQuery(motcleQuery);
    }
    Fapi.Ajax.loadMotcleArray(this, motcleQuery, argObject);
};

Fapi.prototype.loadThesaurus = function (argObject) {
    this.checkDefault(argObject);
    let thesaurus = argObject.thesaurus;
    if (argObject.requestParameters) {
        if ((!thesaurus) && (argObject.requestParameters.thesaurus)) {
            thesaurus = argObject.requestParameters.thesaurus;
        }
    }
    Fapi.Ajax.loadThesaurus(this, thesaurus, argObject);
};

Fapi.prototype.loadFiches = function (argObject) {
    this.checkDefault(argObject);
    let queries = argObject.ficheQueries;
    if ((!queries) && (argObject.ficheQuery)) {
        queries = argObject.ficheQuery;
    }
    Fapi.Ajax.loadFiches(this, queries, argObject);
};

Fapi.prototype.checkDefault = function (argObject) {
    var fapi = this;
    _checkProperty("propertiesMapping");    
    
    function _checkProperty(name) {
        if (!argObject.hasOwnProperty(name)) {
            if (fapi.options.hasOwnProperty(name)) {
                argObject[name] = fapi.options[name]; 
            }
        }
    }
};

/**
 * Construit l'objet destiné à la propriété data d'une requête Ajax.
 * Si l'objet options existe, rajoute les propriétés de la propriété requestParameters de l'objet options
 * 
 * @param {Fapi.EndPoint} endPoint
 * @param {Object} options Objet définissant les options
 * @param {Object} options.requestParameters Surcharge des paramètres de la requête
 * @param {Object} defaultRequestParameters Paramètres par défaut de la requête
 * @returns {Object} Objet construit
 */
Fapi.prototype.buildRequestParameters = function (endPoint, options, defaultRequestParameters) {
    var requestParameters = {};
    if (this.accessToken) {
        requestParameters.token = this.accessToken;
    }
    if (defaultRequestParameters) {
        Object.assign(requestParameters, defaultRequestParameters);
    }
    if (options) {
        if (options.requestParameters) {
            Object.assign(requestParameters, options.requestParameters);
        }
        if (options.propertiesMapping) {
            if (endPoint.version === "action")  {
                let propertiesMapping = options.propertiesMapping;
                if (propertiesMapping.indexOf(':') === -1) {
                    propertiesMapping = "tableexport:" + propertiesMapping;
                }
                requestParameters.properties = propertiesMapping;
            }
        }
    }
    if (endPoint.jsonName) {
        requestParameters.json = endPoint.jsonName;
    }
    return requestParameters;
};

/**
 * Traite les données de la réponse Ajax
 *
 * @param {object} data objet des donnnées
 * @param {boolean} logError Ne pas tenir compte des erreurs
 * @param {function} options.callback Fonction de rappel appliquée aux données de la réponse
 * @returns {undefined}
 */
Fapi.prototype.handleResponseData = function (data, logError, callback) {
    if (logError && (Fapi.hasErrorCommandMessage(data))) {
        Fapi.logCommandMessage(data.commandMessage);
        return;
    }
    if (callback) {
        callback(data);
    }
};


/**
 * Affiche le message dans la console si elle est opérationnelle.
 * 
 * @param {String} msg Message à afficher
 * @returns {undefined}
 */
Fapi.log = function (msg) {
    if ((console) && (console.log)) {
        console.log(msg);
    }
};


/**
 * Affiche un objet de message d'erreur
 * 
 * @param {Object} commandMessage Objet du message
 * @param {Object} commandMessage.text Texte du message
 * @param {Object} commandMessage.key Clé du message (utilisé si le texte n'est pas défini) 
 * @returns {undefined}
 */
Fapi.logCommandMessage = function (commandMessage) {
    var msg = "[" + commandMessage.type + "] - ";
    if (commandMessage.text) {
        msg += commandMessage.text;
    } else {
        msg += commandMessage.key;
    }
    Fapi.log(msg);
};


/**
 * Indique si les données transmises par la réponse contiennent un message d'erreur
 * 
 * @param {Object} data Données transmises par la réponse
 * @returns {Boolean}
 */
Fapi.hasErrorCommandMessage = function (data) {
    return ((data.commandMessage) && (data.commandMessage.type) && (data.commandMessage.type === "error"));
};
