package org.graphwalker.studio;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import org.apache.commons.lang3.StringUtils;
import org.graphwalker.studio.util.LoggerUtil;
import org.graphwalker.websocket.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;

/**
 * @author Nils Olsson
 */
@ComponentScan
@EnableAutoConfiguration
public class Application {

  private static final Logger logger = LoggerFactory.getLogger(Application.class);

  public static void main(String[] args) throws UnknownHostException {
    Application app = new Application();
    try {
      app.run(args);
    } catch (Exception e) {
      // We should have caught all exceptions up until here, but there
      // might have been problems with the command parser for instance...
      System.err.println(e + System.lineSeparator());
      logger.error("An error occurred when running command: " + StringUtils.join(args, " "), e);
    }
  }

  private void run(String[] args) {
    Options options = new Options();
    JCommander jc = new JCommander(options);
    jc.setProgramName("java -jar graphwalker.jar");
    try {
      jc.parseWithoutValidation(args);
    } catch (Exception e) {
      // ignore
    }

    try {
      setLogLevel(options);

      if (options.help) {
        options = new Options();
        jc = new JCommander(options);
        jc.parse(args);
        jc.usage();
        return;
      } else if (options.version) {
        System.out.println(printVersionInformation());
        return;
      }

      WebSocketServer gwSocketServer = new WebSocketServer(options.wsPort);
      gwSocketServer.start();

      Properties props = System.getProperties();
      props.setProperty("server.port", String.valueOf(options.browserPort));

      SpringApplication application = new SpringApplication(Application.class);
      Environment environment = application.run(args).getEnvironment();
      logger.info("Access URLs:\n----------------------------------------------------------\n\t" +
          "Local web service: \t\t\t\thttp://127.0.0.1:" + options.browserPort + "\n\t" +
          "External web service: \t\t\thttp://" + InetAddress.getLocalHost().getHostAddress() + ":" + options.browserPort + "\n\t" +
          "Local websocket service: \t\thttp://127.0.0.1:" + options.wsPort + "\n\t" +
          "External websocket service: \thttp://" + InetAddress.getLocalHost().getHostAddress() + ":" + options.wsPort + "\n----------------------------------------------------------");

    } catch (ParameterException e) {
      System.err.println("An error occurred when running command: " + StringUtils.join(args, " "));
      System.err.println(e.getMessage() + System.lineSeparator());
      if (jc.getParsedCommand() != null) {
        jc.usage(jc.getParsedCommand());
      }
    } catch (Exception e) {
      System.err.println("An error occurred when running command: " + StringUtils.join(args, " "));
      System.err.println(e.getMessage() + System.lineSeparator());
      logger.error("An error occurred when running command: " + StringUtils.join(args, " "), e);
    }
  }

  private void setLogLevel(Options options) {
    // OFF, ERROR, WARN, INFO, DEBUG, TRACE, ALL
    if (options.debug.equalsIgnoreCase("OFF")) {
      LoggerUtil.setLogLevel(LoggerUtil.Level.OFF);
    } else if (options.debug.equalsIgnoreCase("ERROR")) {
      LoggerUtil.setLogLevel(LoggerUtil.Level.ERROR);
    } else if (options.debug.equalsIgnoreCase("WARN")) {
      LoggerUtil.setLogLevel(LoggerUtil.Level.WARN);
    } else if (options.debug.equalsIgnoreCase("INFO")) {
      LoggerUtil.setLogLevel(LoggerUtil.Level.INFO);
    } else if (options.debug.equalsIgnoreCase("DEBUG")) {
      LoggerUtil.setLogLevel(LoggerUtil.Level.DEBUG);
    } else if (options.debug.equalsIgnoreCase("TRACE")) {
      LoggerUtil.setLogLevel(LoggerUtil.Level.TRACE);
    } else if (options.debug.equalsIgnoreCase("ALL")) {
      LoggerUtil.setLogLevel(LoggerUtil.Level.ALL);
    } else {
      throw new ParameterException("Incorrect argument to --debug");
    }
  }

  private String printVersionInformation() {
    String version = "org.graphwalker version: " + getVersionString() + System.getProperty("line.separator");
    version += System.getProperty("line.separator");

    version += "org.graphwalker is open source software licensed under MIT license" + System.getProperty("line.separator");
    version += "The software (and it's source) can be downloaded from http://graphwalker.org" + System.getProperty("line.separator");
    version += "For a complete list of this package software dependencies, see http://graphwalker.org/archive/site/graphwalker-cli/dependencies.html" + System.getProperty("line.separator");

    return version;
  }

  private String getVersionString() {
    Properties properties = new Properties();
    InputStream inputStream = getClass().getResourceAsStream("/version.properties");
    if (null != inputStream) {
      try {
        properties.load(inputStream);
      } catch (IOException e) {
        logger.error("An error occurred when trying to get the version string", e);
        return "unknown";
      }
    }
    return properties.getProperty("graphwalker.version");
  }
}

@@ -2421,18 +2421,16 @@
 ------%5Cn
-%5Ct
 %22 +%0A    
@@ -2428,32 +2428,34 @@
 n%22 +%0A          %22
+  
 Local web servic
@@ -2461,16 +2461,17 @@
 ce: 
-%5Ct%5Ct%5Ct%5Ct
+         
 http
@@ -2504,34 +2504,32 @@
 rowserPort + %22%5Cn
-%5Ct
 %22 +%0A          %22E
@@ -2519,32 +2519,34 @@
 n%22 +%0A          %22
+  
 External web ser
@@ -2555,14 +2555,14 @@
 ce: 
-%5Ct%5Ct%5Ct
+      
 http
@@ -2637,34 +2637,32 @@
 rowserPort + %22%5Cn
-%5Ct
 %22 +%0A          %22L
@@ -2660,16 +2660,18 @@
        %22
+  
 Local we
@@ -2691,12 +2691,11 @@
 ce: 
-%5Ct%5Ct
+   
 http
@@ -2731,18 +2731,16 @@
 rt + %22%5Cn
-%5Ct
 %22 +%0A    
@@ -2746,16 +2746,18 @@
        %22
+  
 External
@@ -2780,10 +2780,8 @@
 ce: 
-%5Ct
 http

Prettified output