/* BdfServer - Copyright (c) 2015-2023 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.conf;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import net.mapeadores.util.exceptions.InitException;


/**
 *
 *
 * @author Vincent Calame
 */
public class WebappDirs implements ConfDirs {

    private final boolean multiBdf;
    private final Map<String, File> dirMap;

    private WebappDirs(boolean multiBdf, Map<String, File> dirMap) {
        this.multiBdf = multiBdf;
        this.dirMap = dirMap;
    }

    public boolean isMultiBdf() {
        return multiBdf;
    }

    public BdfServerDirs getBdfServerDirs(String name) {
        if (multiBdf) {
            return new MultiDirs(name);
        } else {
            return new UniqueDirs();
        }
    }

    public ConfDirs getMultiDirs() {
        if (!multiBdf) {
            throw new IllegalStateException("not a multi instance");
        }
        return new MultiDirs("_multi");
    }

    @Override
    public File getDir(String dirKey) {
        return dirMap.get(dirKey);
    }

    public static WebappDirs build(boolean multiBdf, File etcDirectory, File varDirectory, Map<String, File> customDirMap) {
        Map<String, File> dirMap = new HashMap<String, File>();
        for (Map.Entry<String, File> entry : customDirMap.entrySet()) {
            dirMap.put(checkAlias(entry.getKey()), entry.getValue());
        }
        checkKey(dirMap, ConfConstants.ETC_CONFIG, etcDirectory);
        checkKey(dirMap, ConfConstants.ETC_CONFIG_DEFAULT, etcDirectory);
        checkKey(dirMap, ConfConstants.ETC_RESOURCES, etcDirectory);
        checkKey(dirMap, ConfConstants.ETC_SCRIPTS, etcDirectory);
        checkKey(dirMap, ConfConstants.VAR_DATA, varDirectory);
        checkKey(dirMap, ConfConstants.VAR_OUTPUT, varDirectory);
        checkKey(dirMap, ConfConstants.VAR_CACHE, varDirectory);
        checkKey(dirMap, ConfConstants.VAR_BACKUP, varDirectory);
        checkKey(dirMap, ConfConstants.VAR_RUN, varDirectory);
        dirMap.put(ConfConstants.ETC_ROOT, etcDirectory);
        dirMap.put(ConfConstants.VAR_ROOT, varDirectory);
        checkVarDirectories(dirMap);
        return new WebappDirs(multiBdf, dirMap);
    }

    private static void checkKey(Map<String, File> dirMap, String dirKey, File parentDir) {
        if (dirMap.containsKey(dirKey)) {
            return;
        }
        File dir = getDefaultSubdir(parentDir, dirKey);
        dirMap.put(dirKey, dir);
    }

    private static void checkVarDirectories(Map<String, File> dirMap) {
        for (Map.Entry<String, File> entry : dirMap.entrySet()) {
            switch (entry.getKey()) {
                case ConfConstants.VAR_DATA:
                case ConfConstants.VAR_OUTPUT:
                case ConfConstants.VAR_CACHE:
                case ConfConstants.VAR_BACKUP: {
                    File dir = entry.getValue();
                    if (!dir.exists()) {
                        boolean done = dir.mkdirs();
                        if (!done) {
                            throw new InitException("Unable to create var directory: " + dir.getPath());
                        }
                    }
                }
            }
        }
    }

    private static File getDefaultSubdir(File parentDir, String dirKey) {
        switch (dirKey) {
            case ConfConstants.ETC_CONFIG:
                return new File(parentDir, "config");
            case ConfConstants.ETC_CONFIG_DEFAULT:
                return new File(parentDir, "config");
            case ConfConstants.ETC_RESOURCES:
                return new File(parentDir, "resources");
            case ConfConstants.ETC_SCRIPTS:
                return new File(parentDir, "scripts");
            case ConfConstants.VAR_DATA:
                return parentDir;
            case ConfConstants.VAR_OUTPUT:
                return checkFile(parentDir, "_output", "output");
            case ConfConstants.VAR_CACHE:
                return checkFile(parentDir, "_cache", "cache");
            case ConfConstants.VAR_BACKUP:
                return checkFile(parentDir, "_backup", "backup");
            case ConfConstants.VAR_RUN:
                return new File(parentDir, "_run");
            default:
                return parentDir;
        }
    }

    private static File checkFile(File parentDir, String dirName, String alias) {
        File result = new File(parentDir, dirName);
        if (!result.exists()) {
            File aliasFile = new File(parentDir, alias);
            if (aliasFile.exists()) {
                aliasFile.renameTo(result);
            }
        }
        return result;
    }

    private static String checkAlias(String dirKey) {
        switch (dirKey) {
            case "usr.extensionlib":
            case "usr.extensions":
                return ConfConstants.LIB_EXTENSIONS;
            default:
                return dirKey;
        }
    }


    private class UniqueDirs implements BdfServerDirs {

        private UniqueDirs() {

        }

        @Override
        public String getName() {
            return ConfConstants.UNIQUE_NAME;
        }

        @Override
        public File getDir(String dirKey) {
            return dirMap.get(dirKey);
        }

    }


    private class MultiDirs implements BdfServerDirs {

        private final String name;

        private MultiDirs(String name) {
            this.name = name;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public File getDir(String dirKey) {
            switch (dirKey) {
                case ConfConstants.ETC_ROOT:
                case ConfConstants.ETC_CONFIG_DEFAULT:
                case ConfConstants.ETC_RESOURCES:
                case ConfConstants.VAR_ROOT:
                case ConfConstants.LIB_EXTENSIONS:
                    return dirMap.get(dirKey);
                default:
                    if (dirKey.startsWith("custom.")) {
                        return dirMap.get(dirKey);
                    } else {
                        return new File(dirMap.get(dirKey), name);
                    }
            }
        }

    }

}
