/* BdfServer_API - Copyright (c) 2006-2025 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package fr.exemole.bdfserver.api;

import fr.exemole.bdfserver.api.configuration.LangConfiguration;
import fr.exemole.bdfserver.api.managers.AccessManager;
import fr.exemole.bdfserver.api.managers.BalayageManager;
import fr.exemole.bdfserver.api.managers.ExtensionManager;
import fr.exemole.bdfserver.api.managers.ExternalScriptManager;
import fr.exemole.bdfserver.api.managers.GroupManager;
import fr.exemole.bdfserver.api.managers.JsLibManager;
import fr.exemole.bdfserver.api.managers.L10nManager;
import fr.exemole.bdfserver.api.managers.PasswordManager;
import fr.exemole.bdfserver.api.managers.PermissionManager;
import fr.exemole.bdfserver.api.managers.PolicyManager;
import fr.exemole.bdfserver.api.managers.ScrutariExportManager;
import fr.exemole.bdfserver.api.managers.SelectionManager;
import fr.exemole.bdfserver.api.managers.SqlExportManager;
import fr.exemole.bdfserver.api.managers.TableExportManager;
import fr.exemole.bdfserver.api.managers.TransformationManager;
import fr.exemole.bdfserver.api.managers.TreeManager;
import fr.exemole.bdfserver.api.managers.UiManager;
import fr.exemole.bdfserver.api.storage.BdfUserStorage;
import fr.exemole.bdfserver.api.storage.EditableResourceStorage;
import fr.exemole.bdfserver.api.storage.StorageRoot;
import fr.exemole.bdfserver.api.users.BdfUser;
import fr.exemole.bdfserver.conf.BdfServerDirs;
import fr.exemole.bdfserver.tools.users.BdfUserUtils;
import java.util.Map;
import net.fichotheque.EditOrigin;
import net.fichotheque.Fichotheque;
import net.fichotheque.exportation.table.TableExportContext;
import net.fichotheque.externalsource.ExternalSourceProvider;
import net.fichotheque.format.FormatContext;
import net.fichotheque.importation.ImportationContext;
import net.fichotheque.sphere.Redacteur;
import net.fichotheque.thesaurus.metadata.ThesaurusLangChecker;
import net.fichotheque.utils.EditOriginUtils;
import net.mapeadores.util.annotation.Nullable;
import net.mapeadores.util.buildinfo.BuildInfo;
import net.mapeadores.util.html.HtmlCleaner;
import net.mapeadores.util.io.DocStream;
import net.mapeadores.util.io.ResourceStorages;
import net.mapeadores.util.jslib.JsAnalyser;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.logging.SourceLogs;
import net.mapeadores.util.mimetype.MimeTypeResolver;
import net.mapeadores.util.mimetype.MimeTypeUtils;
import net.mapeadores.util.text.RelativePath;
import net.fichotheque.FichothequeQuestioner;


/**
 * Interface centrale
 *
 * @author Vincent Calame
 */
public interface BdfServer {

    /**
     * Retourne le journal de l'initialisation contenant les erreurs ou les
     * avertissements (fichiers mal lus, valeurs incorrectes) qui n'ont pas été
     * critiques. Les erreurs critiques (par exemple, un problème
     * d'entrée-sortie sur le disque dur) sont signalées par des exceptions.
     */
    public SourceLogs getInitLogs();

    /**
     * Retourne le nom du serveur dans son contexte. Dans le cas de fichothèques
     * multiples, il s'agira du nom identifiant la fichothèque parmi les autres.
     *
     * @return nom du serveur dans son contexte
     */
    public String getName();

    /**
     * Retourne les informations sur les répertoires qui ont servi à construire
     * l'instance.
     *
     * @return
     */
    public BdfServerDirs getBdfServerDirs();


    /**
     * Retourne des objets définis hors de BdfServer et lié au contexte
     * d'exécution. Retourne l'instance BdfServer elle-même si objectName est
     * égal à BdfServerConstants.BDFSERVER_CONTEXTOBJECT
     *
     * @param objectName
     * @return
     */
    @Nullable
    public Object getContextObject(String objectName);

    /**
     * Retourne l'instance de Fichotheque autour de laquelle s'est construite
     * l'instance de BdfServer.
     *
     * @return l'instance de Fichotheque contenant le cœur des données de la
     * base
     */
    public Fichotheque getFichotheque();

    /**
     * Retourne le gestionnaire des permissions des utilisateurs.
     *
     * @return l'implémentation de PermissionManager pour la base en cours
     */
    public PermissionManager getPermissionManager();

    /**
     * Retourne le gestionnaire de mots de passe.
     *
     * @return l'implémentation de PasswordManager pour la base en cours
     */
    public PasswordManager getPasswordManager();

    /**
     * Retourne le gestionnaire des gabarits de transformation
     *
     * @return l'implémentation de TransformationManager pour la base en cours
     */
    public TransformationManager getTransformationManager();

    /**
     * Retourne le gestionnaire des formulaires de saisie.
     *
     * @return l'implémentation de UiManager pour la base en cours
     */
    public UiManager getUiManager();

    /**
     * Retourne le gestionnaire des politiques de saisie.
     *
     * @return l'implémentation de PolicyManager pour la base en cours
     */
    public PolicyManager getPolicyManager();

    /**
     * Retourne le gestionnaire des exportations tabulaires.
     *
     * @return l'implémentation de TableExportManager pour la base en cours
     */
    public TableExportManager getTableExportManager();

    /**
     * Retourne le gestionnaire des sélections.
     *
     * @return l'implémentation de ScrutariExportManager pour la base en cours
     */
    public SelectionManager getSelectionManager();

    /**
     * Retourne le gestionnaire des exportations au format Scrutari.
     *
     * @return l'implémentation de ScrutariExportManager pour la base en cours
     */
    public ScrutariExportManager getScrutariExportManager();

    /**
     * Retourne le gestionnaire des exportations au format SQL.
     *
     * @return l'implémentation de SqlExportManager pour la base en cours
     */
    public SqlExportManager getSqlExportManager();

    /**
     * Retourne le gestionnaire des extensions.
     *
     * @return l'implémentation de ExtensionManager pour la base en cours
     */
    public ExtensionManager getExtensionManager();

    /**
     * Retourne le gestionnaire des balayages.
     *
     * @return l'implémentation de BalayageManager pour la base en cours
     */
    public BalayageManager getBalayageManager();

    /**
     * Retourne le gestionnaire des scripts externes.
     *
     * @return l'implémentation de ExternalScriptManager pour la base en cours
     */
    public ExternalScriptManager getExternalScriptManager();

    public AccessManager getAccessManager();

    /**
     * Retourne le gestionnaire des bibliothèques Javascript
     *
     * @return l'implémentation de JsLibManager pour la base en cours
     */
    public JsLibManager getJsLibManager();

    public BdfUserStorage getBdfUserStorage();

    public GroupManager getGroupManager();

    public TreeManager getTreeManager();

    public L10nManager getL10nManager();

    public JsAnalyser getJsAnalyser();

    public ExternalSourceProvider getExternalSourceProvider();

    public BdfUser createBdfUser(Redacteur redacteur);

    public LangConfiguration getLangConfiguration();

    public void addEditionSessionListener(EditSessionListener editSessionListener);

    public void removeEditionSessionListener(EditSessionListener editSessionListener);

    public EditSession initEditSession(EditOrigin editOrigin);

    public TableExportContext getTableExportContext();

    public ImportationContext getImportationContext();

    public ThesaurusLangChecker getThesaurusLangChecker();

    public HtmlCleaner getHtmlCleaner();

    public BuildInfo getBuildInfo();

    public ResourceStorages getResourceStorages();

    public StorageRoot getOutputStorage();

    public StorageRoot getCacheStorage();

    public FichothequeQuestioner getFichothequeQuestioner();

    public default FormatContext getFormatContext() {
        return getTableExportContext().getFormatContext();
    }

    public default MimeTypeResolver getMimeTypeResolver() {
        Object object = getContextObject(BdfServerConstants.MIMETYPERESOLVER_CONTEXTOBJECT);
        if (object != null) {
            return (MimeTypeResolver) object;
        } else {
            return MimeTypeUtils.DEFAULT_RESOLVER;
        }
    }

    public default DocStream getResourceDocStream(RelativePath relativePath) {
        return getResourceStorages().getResourceDocStream(relativePath, getMimeTypeResolver());
    }

    public default EditableResourceStorage getVarResourceStorage() {
        return (EditableResourceStorage) getResourceStorages().getResourceStorage(BdfServerConstants.VAR_STORAGE);
    }

    public default EditSession initEditSession(String source) {
        return initEditSession(EditOriginUtils.newEditOrigin(source));
    }

    public default EditSession initEditSession(String redacteurGlobalId, String source) {
        return initEditSession(EditOriginUtils.newEditOrigin(source, null, redacteurGlobalId));
    }

    public default EditSession initEditSession(BdfUser bdfUser, String source) {
        return initEditSession(bdfUser.newEditOrigin(source));
    }

    public default EditSession initEditSession(BdfUser bdfUser, String domain, String commandName) {
        return initEditSession(bdfUser.newEditOrigin(domain, commandName));
    }

    public default void store(BdfUser bdfUser, String storeName, String storeKey, String storeValue) {
        if (!BdfUserUtils.isValidStoreKey(storeKey)) {
            throw new IllegalArgumentException("Invalid store key: " + storeKey);
        }
        BdfUserStorage bdfUserStorage = getBdfUserStorage();
        Redacteur redacteur = bdfUser.getRedacteur();
        Map<String, String> storeMap = bdfUserStorage.getStoreMap(redacteur, storeName);

        boolean done = false;
        String currentValue = storeMap.get(storeKey);
        if (storeValue == null) {
            if (currentValue != null) {
                storeMap.remove(storeKey);
                done = true;
            }
        } else {
            if ((currentValue == null) || (!currentValue.equals(storeValue))) {
                storeMap.put(storeKey, storeValue);
                done = true;
            }
        }
        if (done) {
            bdfUserStorage.putStoreMap(redacteur, storeName, storeMap);
        }
    }

    public default void store(BdfUser bdfUser, String storeName, Map<String, String> map) {
        BdfUserStorage bdfUserStorage = getBdfUserStorage();
        Redacteur redacteur = bdfUser.getRedacteur();
        Map<String, String> storeMap = bdfUserStorage.getStoreMap(redacteur, storeName);
        boolean done = false;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            String storeKey = entry.getKey();
            if (BdfUserUtils.isValidStoreKey(storeKey)) {
                String storeValue = entry.getValue();
                String currentValue = storeMap.get(storeKey);
                if (storeValue == null) {
                    if (currentValue != null) {
                        storeMap.remove(storeKey);
                        done = true;
                    }
                } else {
                    if ((currentValue == null) || (!currentValue.equals(storeValue))) {
                        storeMap.put(storeKey, storeValue);
                        done = true;
                    }
                }
            }

        }
        if (done) {
            bdfUserStorage.putStoreMap(redacteur, storeName, storeMap);
        }
    }

    public default String getStoredValue(BdfUser bdfUser, String storeName, String storeKey) {
        BdfUserStorage bdfUserStorage = getBdfUserStorage();
        Redacteur redacteur = bdfUser.getRedacteur();
        Map<String, String> storeMap = bdfUserStorage.getStoreMap(redacteur, storeName);
        return storeMap.get(storeKey);
    }

    public default Map<String, String> getStoredValues(BdfUser bdfUser, String storeName) {
        BdfUserStorage bdfUserStorage = getBdfUserStorage();
        Redacteur redacteur = bdfUser.getRedacteur();
        return bdfUserStorage.getStoreMap(redacteur, storeName);
    }

    public default Lang getDefaultWorkingLang() {
        return getLangConfiguration().getWorkingLangs().get(0);
    }

}
