package io.playpen.core;

import io.playpen.core.coordinator.PlayPen;
import io.playpen.core.coordinator.VMShutdownThread;
import io.playpen.core.coordinator.client.Client;
import io.playpen.core.coordinator.local.Local;
import io.playpen.core.coordinator.network.Network;
import io.playpen.core.utils.JarUtils;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Paths;

@Log4j2
public class Bootstrap {
    @Getter
    private static final int protocolVersion = 5; // update ONLY on breaking protocol changes

    @Getter
    private static File homeDir;

    private static boolean copyFileFromJar(String file) throws IOException, URISyntaxException {
        File f = Paths.get(homeDir.getPath(), file).toFile();
        if(!f.exists()) {
            JarUtils.exportResource(Bootstrap.class, "/" + file, f.getPath());
            return true;
        }

        return false;
    }

    private static boolean copyFilesFromJar(String[] files) throws IOException, URISyntaxException {
        boolean didCopy = false;
        for(String file : files) {
            if(copyFileFromJar(file))
                didCopy = true;
        }

        return didCopy;
    }

    public static void main(String[] args) {
        boolean didCopyResources = false;

        try {
            homeDir = new File(Bootstrap.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
        }
        catch(URISyntaxException e) {}

        if(!"true".equalsIgnoreCase(System.getenv("PLAYPEN_NO_SETUP"))) {
            try {
                didCopyResources = copyFilesFromJar(new String[]{
                        "logging-network.xml",
                        "logging-local.xml",
                        "logging-cli.xml",
                        "logging-p3.xml",
                        "keystore.json",
                        "packages.json",
                        "local.json",
                        "network.json",
                        "playpen-network.bat",
                        "playpen-local.bat",
                        "playpen-cli.bat",
                        "playpen-p3.bat",
                        "playpen-network.sh",
                        "playpen-local.sh",
                        "playpen-cli.sh",
                        "playpen-p3.sh"
                });

                if (Paths.get(homeDir.getPath(), "cache", "packages").toFile().mkdirs())
                    didCopyResources = true;

                if (Paths.get(homeDir.getPath(), "packages").toFile().mkdirs())
                    didCopyResources = true;

                if (Paths.get(homeDir.getPath(), "assets").toFile().mkdirs())
                    didCopyResources = true;

                if (Paths.get(homeDir.getPath(), "plugins").toFile().mkdirs())
                    didCopyResources = true;

                if (Paths.get(homeDir.getPath(), "servers").toFile().mkdirs())
                    didCopyResources = true;

                if (Paths.get(homeDir.getPath(), "frozen").toFile().mkdirs())
                    didCopyResources = true;

                if (Paths.get(homeDir.getPath(), "temp").toFile().mkdirs())
                    didCopyResources = true;

                if (Paths.get(homeDir.getPath(), "server-logs").toFile().mkdirs())
                    didCopyResources = true;
            } catch (Exception e) {
                System.err.println("Unable to copy default resources");
                e.printStackTrace(System.err);
                return;
            }
        }

        if(didCopyResources) {
            System.err.println("It looks like you were missing some resource files, so I've copied some defaults for you! " +
                    "I'll give you a chance to edit them. Bye!");
            return;
        }

        if(args.length < 1) {
            System.err.println("playpen <local/network/p3/cli> [arguments...]");
            return;
        }

        switch(args[0].toLowerCase()) {
            case "local":
                runLocalCoordinator();
                break;

            case "network":
                runNetworkCoordinator();
                break;

            case "p3":
                P3Tool.run(args);
                break;

            case "cli":
                runClient(args);
                break;

            default:
                System.err.println("playpen <local/network/p3/cli> [arguments...]");
                return;
        }
    }

    private static void runLocalCoordinator() {
        log.info("Bootstrap starting local coordinator (autorestart enabled)");

        Runtime.getRuntime().addShutdownHook(new VMShutdownThread());

        try {
            while(true) {
                //PlayPen.reset(); // DO NOT RESET PLAYPEN! If we get disconnected from the network, we don't want to
                                   // shutdown any servers that are running. We just want to reconnect to the network.
                if(!Local.get().run())
                    break;

                log.info("Waiting 10 seconds before restarting...");
                Thread.sleep(1000L * 10L);
            }
        }
        catch(Exception e) {
            log.fatal("Caught exception at bootstrap level while running local coordinator", e);
            return;
        }

        log.info("Ending local coordinator session");
    }

    private static void runNetworkCoordinator() {
        log.info("Bootstrap starting network coordinator (autorestart enabled)");

        Runtime.getRuntime().addShutdownHook(new VMShutdownThread());

        try {
            while (true) {
                PlayPen.reset();
                if(!Network.get().run())
                    break;

                log.info("Waiting 10 seconds before restarting...");
                Thread.sleep(1000L * 10L);
            }
        }
        catch(Exception e) {
            log.fatal("Caught exception at bootstrap level while running network coordinator", e);
            return;
        }

        log.info("Ending network coordinator session");
    }

    private static void runClient(String[] arguments) {
        log.info("Bootstrap starting client");

        Runtime.getRuntime().addShutdownHook(new VMShutdownThread());

        try {
            Client.get().run(arguments);
        }
        catch(Exception e) {
            log.fatal("Caught exception at bootstrap level while running client", e);
            return;
        }

        log.info("Ending client session");
    }
}

@@ -1361,38 +1361,200 @@
 false;%0A%0A        
+S
 tr
-y %7B%0A
+ing homeDirEnv = System.getenv(%22PLAYPEN_HOME%22);%0A        if (homeDirEnv != null) %7B%0A            homeDir = new File(homeDirEnv);%0A        %7D else %7B%0A            try %7B%0A    
             home
@@ -1679,32 +1679,29 @@
 %0A       
- %7D%0A
      
-  
+%7D
  catch
+ 
 (URISynt
@@ -1716,16 +1716,39 @@
 ion e) %7B
+%0A            %7D%0A        
 %7D%0A%0A     

Allow specifying the PlayPen home directory in the environment.