package org.jboss.uninstaller;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.CodeSource;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * The first stage of uninstaller. To avoid a file locking issue with the {@code uninstaller.jar}, uninstall is run in two steps.
 * At first the content of {@code uninstaller.jar} is extracted into a temporary folder. Then a new jvm is started to perform
 * actual uninstallation, while the original process is finished to unlock the files.
 *
 * The second stage of the process is handled by {@link Uninstaller} class.
 */
public class UninstallerWrapper {

    private static final String UNINSTALLER_UNABLE_TO_START_CLEANUP = "uninstaller.unable.to.start.cleanup";
    private static final String UNINSTALLER_UNABLE_TO_LOCATE_UNINSTALLER = "uninstaller.unable.to.locate.uninstaller";
    private static final String UNINSTALLER_UNABLE_TO_CREATE_TEMP = "uninstaller.unable.to.create.temp";

    public static void main(String[] args) {
        boolean console = false;
        for (String arg : args) {
            if ("-console".equals(arg) || "-c".equals(arg)) {
                console = true;
            }
        }

        // figure out where the uninstaller.jar is
        final Path uninstallerJarPath = locateUninstallerJar();

        // create temporary folder
        final Path tempDirPath = extractResources(uninstallerJarPath);

        // start the uninstaller process
        try {
            final ProcessBuilder pb = new ProcessBuilder("java", "-cp", tempDirPath.toString(),
                    Uninstaller.class.getName(), "-Dtemp.path=" + tempDirPath, console ? "-console" : "");
            pb.start();
        } catch (IOException e) {
            handleError(UNINSTALLER_UNABLE_TO_START_CLEANUP);
        }

        // exit current process to unlock the uninstaller.jar
        System.exit(0);
    }

    private static Path locateUninstallerJar() {
        try {
            final CodeSource codeSource = UninstallerWrapper.class.getProtectionDomain().getCodeSource();
            return Path.of(codeSource.getLocation().toURI());
        } catch (URISyntaxException e) {
            handleError(UNINSTALLER_UNABLE_TO_LOCATE_UNINSTALLER);
            // that'll never happen - we exit on error
            return null;
        }
    }

    private static Path extractResources(Path uninstallerJarPath) {
        try {
            final Path tempDirPath = Files.createTempDirectory("eap-uninstaller");
            unpack(uninstallerJarPath, tempDirPath);
            return tempDirPath;
        } catch (IOException e) {
            handleError(UNINSTALLER_UNABLE_TO_CREATE_TEMP);
            // that'll never happen - we exit on error
            return null;
        }
    }

    private static void handleError(String key) {
        final String error = Uninstaller.translations.getString("uninstaller.error");
        final String msg = Uninstaller.translations.getString(key);
        System.err.println(String.format(error, msg));
        System.exit(1);
    }

    private static void unpack(Path uninstallerJarPath, Path tempFolder) throws IOException {
        final JarFile jarFile = new JarFile(uninstallerJarPath.toFile(), true);

        try {
            final Enumeration<JarEntry> entries = jarFile.entries();

            while (entries.hasMoreElements()) {
                final JarEntry jarEntry = entries.nextElement();
                Path targetPath = tempFolder.resolve(jarEntry.getName());
                if (jarEntry.isDirectory()) {
                    Files.createDirectories(targetPath);
                } else {
                    if (!Files.exists(targetPath.getParent())) {
                        Files.createDirectories(targetPath.getParent());
                    }
                    Files.copy(jarFile.getInputStream(jarEntry), targetPath);
                }
            }
        } finally {
            jarFile.close();
        }
    }
}
