/* BdfServer_DirectoryStorage - Copyright (c) 2013-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.storage.directory;

import fr.exemole.bdfserver.api.configuration.LangConfiguration;
import fr.exemole.bdfserver.api.groups.GroupDef;
import fr.exemole.bdfserver.api.policies.UserAllow;
import fr.exemole.bdfserver.api.roles.RoleDef;
import fr.exemole.bdfserver.api.storage.BdfExtensionStorage;
import fr.exemole.bdfserver.api.storage.BdfStorageException;
import fr.exemole.bdfserver.api.storage.StorageCheck;
import fr.exemole.bdfserver.api.subsettree.SubsetTree;
import fr.exemole.bdfserver.conf.BdfServerDirs;
import fr.exemole.bdfserver.conf.ConfConstants;
import fr.exemole.bdfserver.storage.directory.bdfdata.BdfdataDirectory;
import fr.exemole.bdfserver.storage.directory.bdfdata.DirectoryFichotheque;
import fr.exemole.bdfserver.storage.directory.bdfdata.ExceptionHandler;
import fr.exemole.bdfserver.storage.directory.implementations.AccessStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.BalayageStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.BdfExtensionStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.BdfUserStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.ConfigurationStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.GroupStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.PasswordStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.PolicyStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.RedacteurListStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.RoleStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.ScrutariExportStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.SelectionStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.SqlExportStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.StorageRootImpl;
import fr.exemole.bdfserver.storage.directory.implementations.TableExportStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.TemplateStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.TreeStorageImpl;
import fr.exemole.bdfserver.storage.directory.implementations.UiStorageImpl;
import fr.exemole.bdfserver.storage.directory.oldversions.DirectoryMigrationEngine;
import fr.exemole.bdfserver.tools.BdfServerUtils;
import fr.exemole.bdfserver.tools.storage.Storages;
import java.io.File;
import java.util.List;
import java.util.Map;
import net.fichotheque.Fichotheque;
import net.fichotheque.FichothequeEditorProvider;
import net.fichotheque.SubsetKey;
import net.fichotheque.exportation.access.AccessDef;
import net.fichotheque.exportation.scrutari.ScrutariExportDef;
import net.fichotheque.exportation.sql.SqlExportDef;
import net.fichotheque.selection.SelectionDef;
import net.fichotheque.sphere.Redacteur;
import net.mapeadores.util.html.HtmlCleaner;
import net.mapeadores.util.html.jsoup.HtmlCleaners;
import net.mapeadores.util.logging.MultiMessageHandler;


/**
 *
 * @author Vincent Calame
 */
public class StorageFactory {

    public final static String SEVERE_FILENAME = "severe.directorystorage.filename";

    private StorageFactory() {
    }

    public static Storages newInstance(BdfServerDirs dirs, MultiMessageHandler messageHandler) {
        BdfExtensionStorage bdfExtensionStorage = new BdfExtensionStorageImpl(dirs);
        Storages storages = new Storages(dirs);
        storages
                .setBdfExtensionStorage(bdfExtensionStorage);
        DirectoryMigrationEngine directoryMigrationEngine = DirectoryMigrationEngine.init(dirs);
        DirectoryStorageCheck check = new DirectoryStorageCheck();
        BdfdataDirectory bdfdataDirectory = BdfdataDirectory.build(dirs);
        InternalExceptionHandler exceptionHandler = new InternalExceptionHandler();
        HtmlCleaner ficheHtmlCleaner = BdfServerUtils.DEFAULT_HTMLCLEANER;
        FichothequeEditorProvider fichothequeEditorProvider = DirectoryFichotheque.buildReadAndWrite(bdfdataDirectory, ficheHtmlCleaner, messageHandler, exceptionHandler);
        if (exceptionHandler.currentBdfStorageException != null) {
            throw exceptionHandler.currentBdfStorageException;
        }
        storages.setFichothequeEditorProvider(fichothequeEditorProvider);
        Fichotheque fichotheque = fichothequeEditorProvider.getFichotheque();
        storages.setPasswordStorage(new PasswordStorageImpl(bdfdataDirectory));

        ConfigurationStorageImpl configurationStorage = new ConfigurationStorageImpl(bdfdataDirectory);
        check.setLangConfiguration(configurationStorage.checkLangConfiguration(messageHandler));
        check.setActiveExtensionList(configurationStorage.checkActiveExtensionList(messageHandler));
        storages.setConfigurationStorage(configurationStorage);

        SelectionStorageImpl selectionStorage = new SelectionStorageImpl(fichotheque, bdfdataDirectory);
        check.setSelectionDefList(selectionStorage.check(messageHandler));
        storages.setSelectionStorage(selectionStorage);

        ScrutariExportStorageImpl scrutariExportStorage = new ScrutariExportStorageImpl(fichotheque, bdfdataDirectory);
        check.setScrutariExportDefList(scrutariExportStorage.check(messageHandler));
        storages.setScrutariExportStorage(scrutariExportStorage);

        SqlExportStorageImpl sqlExportStorage = new SqlExportStorageImpl(fichotheque, bdfdataDirectory);
        check.setSqlExportDefList(sqlExportStorage.check(messageHandler));
        storages.setSqlExportStorage(sqlExportStorage);

        RoleStorageImpl roleStorage = new RoleStorageImpl(bdfdataDirectory);
        check.setRoleDefList(roleStorage.check(messageHandler));
        storages.setRoleStorage(roleStorage);

        GroupStorageImpl groupStorage = new GroupStorageImpl(bdfdataDirectory);
        check.setGroupDefList(groupStorage.check(messageHandler));
        storages.setGroupStorage(groupStorage);

        TreeStorageImpl treeStorageImpl = new TreeStorageImpl(bdfdataDirectory);
        check.setSubsetTreeMap(treeStorageImpl.check(messageHandler));
        storages.setTreeStorage(treeStorageImpl);

        AccessStorageImpl accessStorageImpl = new AccessStorageImpl(fichotheque, bdfdataDirectory);
        check.setAccessDefList(accessStorageImpl.check(messageHandler));
        storages.setAccessStorage(accessStorageImpl);

        HtmlCleaner uiHtmlCleaner = HtmlCleaners.EXTENDED_WITH_STYLE;
        UiStorageImpl uiStorageImpl = new UiStorageImpl(bdfdataDirectory, uiHtmlCleaner);
        check.setUiCheckMap(uiStorageImpl.check(messageHandler));
        storages.setUiStorage(uiStorageImpl);

        PolicyStorageImpl policyStorageImpl = new PolicyStorageImpl(bdfdataDirectory);
        check.setUserAllow(policyStorageImpl.checkUserAllow(messageHandler));
        check.setSubsetPolicyMap(policyStorageImpl.checkSubsetPolicyMap(messageHandler, fichotheque));
        storages.setPolicyStorage(policyStorageImpl);

        RedacteurListStorageImpl redacteurListStorageImpl = new RedacteurListStorageImpl(bdfdataDirectory);
        check.setRedacteurListMap(redacteurListStorageImpl.checkRedacteurListMap(messageHandler, fichotheque));
        storages.setRedacteurListStorage(redacteurListStorageImpl);

        BdfUserStorageImpl bdfUserStorage = new BdfUserStorageImpl(bdfdataDirectory);
        storages.setBdfUserStorage(bdfUserStorage);

        storages.addMigrationEngine(directoryMigrationEngine);
        storages.setStorageCheck(check);

        storages
                .setBalayageStorage(new BalayageStorageImpl(fichotheque, dirs))
                .setTableExportStorage(new TableExportStorageImpl(dirs))
                .setTemplateStorage(new TemplateStorageImpl(dirs))
                .setOutputStorage(new StorageRootImpl(dirs.getDir(ConfConstants.VAR_OUTPUT)))
                .setCacheStorage(new StorageRootImpl(new File(dirs.getDir(ConfConstants.VAR_CACHE), "root")));
        return storages;
    }


    private static class InternalExceptionHandler implements ExceptionHandler {

        private BdfStorageException currentBdfStorageException;

        private InternalExceptionHandler() {
        }

        @Override
        public void handleBdfStorageException(BdfStorageException bdfStorageException) {
            currentBdfStorageException = bdfStorageException;
        }

    }


    private static class DirectoryStorageCheck implements StorageCheck {

        private LangConfiguration langConfiguration;
        private List<SelectionDef> selectionDefList;
        private List<AccessDef> accessDefList;
        private List<ScrutariExportDef> scrutariExportDefList;
        private List<SqlExportDef> sqlExportDefList;
        private List<String> activeExtensionList;
        private List<RoleDef> roleDefList;
        private List<GroupDef> groupDefList;
        private Map<Short, SubsetTree> subsetTreeMap;
        private UserAllow userAllow;
        private Map<SubsetKey, Object> subsetPolicyMap;
        private Map<String, List<Redacteur>> redacteurListMap;
        private Map<SubsetKey, UiCheck> uiCheckMap;

        private DirectoryStorageCheck() {
        }

        @Override
        public LangConfiguration getLangConfiguration() {
            return langConfiguration;
        }

        private void setLangConfiguration(LangConfiguration langConfiguration) {
            this.langConfiguration = langConfiguration;
        }

        @Override
        public List<SelectionDef> getSelectionDefList() {
            return selectionDefList;
        }

        private void setSelectionDefList(List<SelectionDef> selectionDefList) {
            this.selectionDefList = selectionDefList;
        }

        @Override
        public List<AccessDef> getAccessDefList() {
            return accessDefList;
        }

        private void setAccessDefList(List<AccessDef> accessDefList) {
            this.accessDefList = accessDefList;
        }

        @Override
        public List<ScrutariExportDef> getScrutariExportDefList() {
            return scrutariExportDefList;
        }

        private void setScrutariExportDefList(List<ScrutariExportDef> scrutariExportDefList) {
            this.scrutariExportDefList = scrutariExportDefList;
        }

        @Override
        public List<SqlExportDef> getSqlExportDefList() {
            return sqlExportDefList;
        }

        private void setSqlExportDefList(List<SqlExportDef> sqlExportDefList) {
            this.sqlExportDefList = sqlExportDefList;
        }

        @Override
        public List<String> getActiveExtensionList() {
            return activeExtensionList;
        }

        private void setActiveExtensionList(List<String> activeExtensionList) {
            this.activeExtensionList = activeExtensionList;
        }

        @Override
        public List<RoleDef> getRoleDefList() {
            return roleDefList;
        }

        private void setRoleDefList(List<RoleDef> roleDefList) {
            this.roleDefList = roleDefList;
        }

        @Override
        public List<GroupDef> getGroupDefList() {
            return groupDefList;
        }

        private void setGroupDefList(List<GroupDef> groupDefList) {
            this.groupDefList = groupDefList;
        }

        @Override
        public Map<Short, SubsetTree> getSubsetTreeMap() {
            return subsetTreeMap;
        }

        private void setSubsetTreeMap(Map<Short, SubsetTree> subsetTreeMap) {
            this.subsetTreeMap = subsetTreeMap;
        }

        @Override
        public UserAllow getUserAllow() {
            return userAllow;
        }

        private void setUserAllow(UserAllow userAllow) {
            this.userAllow = userAllow;
        }

        @Override
        public Map<SubsetKey, Object> getSubsetPolicyMap() {
            return subsetPolicyMap;
        }

        private void setSubsetPolicyMap(Map<SubsetKey, Object> subsetPolicyMap) {
            this.subsetPolicyMap = subsetPolicyMap;
        }

        @Override
        public Map<String, List<Redacteur>> getRedacteurListMap() {
            return redacteurListMap;
        }

        public void setRedacteurListMap(Map<String, List<Redacteur>> redacteurListMap) {
            this.redacteurListMap = redacteurListMap;
        }

        @Override
        public Map<SubsetKey, UiCheck> getUiCheckMap() {
            return uiCheckMap;
        }

        public void setUiCheckMap(Map<SubsetKey, UiCheck> uiCheckMap) {
            this.uiCheckMap = uiCheckMap;
        }

    }


}
