/* BdfServer - Copyright (c) 2010-2020 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.impl;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.configuration.PathConfiguration;
import fr.exemole.bdfserver.api.externalscript.ExternalScript;
import fr.exemole.bdfserver.api.managers.ExternalScriptManager;
import fr.exemole.bdfserver.conf.ConfConstants;
import fr.exemole.bdfserver.tools.configuration.ConfigurationUtils;
import fr.exemole.bdfserver.tools.configuration.PathConfigurationBuilder;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import net.mapeadores.util.exceptions.ShouldNotOccurException;


/**
 *
 * @author Vincent Calame
 */
class ExternalScriptManagerImpl implements ExternalScriptManager {

    private final static Pattern SCRIPTNAME_PATTERN;
    private final BdfServer bdfServer;

    static {
        try {
            SCRIPTNAME_PATTERN = Pattern.compile("^[a-zA-Z][-_a-zA-Z0-9.]+$");
        } catch (PatternSyntaxException pse) {
            throw new ShouldNotOccurException(pse);
        }
    }

    ExternalScriptManagerImpl(BdfServer bdfServer) {
        this.bdfServer = bdfServer;
    }

    @Override
    public SortedSet<String> getScriptNameSet() {
        File scriptDirectory = bdfServer.getBdfServerDirs().getDir(ConfConstants.ETC_SCRIPTS);
        SortedSet<String> set = new TreeSet<String>();
        if ((scriptDirectory.exists()) && (scriptDirectory.isDirectory())) {
            for (File file : scriptDirectory.listFiles()) {
                if (!file.isDirectory()) {
                    String name = file.getName();
                    if (SCRIPTNAME_PATTERN.matcher(name).matches()) {
                        set.add(name);
                    }
                }
            }
        }
        return set;
    }

    @Override
    public ExternalScript getExternalScript(String name) {
        File scriptDirectory = bdfServer.getBdfServerDirs().getDir(ConfConstants.ETC_SCRIPTS);
        if ((!scriptDirectory.exists()) || (!scriptDirectory.isDirectory())) {
            return null;
        }
        PathConfiguration pathConfiguration = PathConfigurationBuilder.build(bdfServer);
        for (File file : scriptDirectory.listFiles()) {
            if (!file.isDirectory()) {
                String fileName = file.getName();
                if (fileName.equals(name)) {
                    return new ImplExternalScript(bdfServer, name, file, pathConfiguration);
                }
            }
        }
        return null;
    }


    private static class ImplExternalScript implements ExternalScript {

        private final BdfServer bdfServer;
        private final String name;
        private final File file;
        private final PathConfiguration pathConfiguration;

        private ImplExternalScript(BdfServer bdfServer, String name, File file, PathConfiguration pathConfiguration) {
            this.bdfServer = bdfServer;
            this.name = name;
            this.file = file;
            this.pathConfiguration = pathConfiguration;
        }

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

        @Override
        public Process exec() throws IOException {
            File resultFile = ConfigurationUtils.getScriptResultLogFile(bdfServer, name);
            File errorFile = ConfigurationUtils.getScriptErrorLogFile(bdfServer, name);
            ProcessBuilder processBuilder = new ProcessBuilder(file.getPath());
            processBuilder
                    .redirectError(errorFile)
                    .redirectOutput(resultFile);
            Map<String, String> env = processBuilder.environment();
            for (String targetName : pathConfiguration.getTargetNameSet()) {
                File dir = pathConfiguration.getTargetDirectory(targetName);
                env.put("BDF_TARGET_" + targetName, dir.getCanonicalPath());
            }
            processBuilder.directory(file.getParentFile());
            return processBuilder.start();
        }

    }

}
