package ch.deletescape.jterm.commandcontexts.scripting;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import javax.script.ScriptException;

import ch.deletescape.jterm.CommandUtils;
import ch.deletescape.jterm.JTerm;
import ch.deletescape.jterm.Util;
import ch.deletescape.jterm.commandcontexts.CommandContext;
import ch.deletescape.jterm.config.Resources;
import ch.deletescape.jterm.io.Printer;

public class Scripting extends CommandContext {

  @Override
  protected void init() {
    CommandUtils.addListener("if", this::ifThenElse);
    CommandUtils.addListener("while", this::whileDo);
    CommandUtils.addListener("readLine", this::readLine);
    CommandUtils.addListener("var", this::var);
    CommandUtils.addListener("run", Scripting::run);
  }

  boolean eval(String arg) throws ScriptException {
    String expr = CommandUtils.parseInlineCommands(arg);
    return (boolean) JTerm.getJsEngine().eval(expr);
  }

  private boolean ifThenElse(String args) throws ScriptException {
    boolean hasElse = args.contains(" else ");
    String condition = args.split(" then ")[0];
    String part2 = args.split(" then ")[1];
    String then = hasElse ? part2.split(" else ")[0] : part2;
    if (eval(condition)) {
      CommandUtils.evaluateCommand(CommandUtils.parseInlineCommands(then));
      return true;
    }
    if (hasElse) {
      String elseCmd = part2.split(" else ")[1];
      CommandUtils.evaluateCommand(CommandUtils.parseInlineCommands(elseCmd));
    }
    return false;
  }

  private int whileDo(String args) throws ScriptException {
    int count = 0;
    String condition = args.split(" do ")[0];
    String command = args.split(" do ")[1];
    while (eval(condition)) {
      CommandUtils.evaluateCommand(CommandUtils.parseInlineCommands(command));
      count++;
    }
    return count;
  }

  private String readLine(String arg) {
    String hint = CommandUtils.parseInlineCommands(arg);
    Printer.out.forced().print(hint + " ");
    return JTerm.getScanner().nextLine();
  }

  Object var(String args) throws ScriptingException, ScriptException {
    String arguments = CommandUtils.parseInlineCommands(args);
    if (arguments.contains("=")) {
      String name = arguments.split("=")[0].trim();
      String value = arguments.split("=")[1].trim();
      validateVariableName(name);
      if (!value.matches("[0-9]*|true|false")) {
        value = "\"" + value + "\"";
      }
      JTerm.getJsEngine().eval("var " + name + " = " + value);
      return JTerm.getJsEngine().eval(name);
    }
    validateVariableName(arguments);
    Object value = JTerm.getJsEngine().eval(arguments);
    Printer.out.println(value);
    return value;
  }

  void validateVariableName(String name) throws ScriptingException {
    if(!name.matches("^[a-zA-Z_$][\\w$]*")){
      throw new ScriptingException(String.format(Resources.getString("Scripting.InvalidVariableName"),name));
    }
  }

  public static boolean run(String cmd) throws IOException {
    String command = CommandUtils.parseInlineCommands(cmd);
    Path path = JTerm.getCurrPath().resolve(Util.makePathString(command)).toRealPath();
    if (Files.isDirectory(path)) {
      Printer.err.println(Resources.getString("Scripting.FileIsDirectory"), path);
      return false;
    }
    Path bak = JTerm.getCurrPath();
    JTerm.setCurrPath(path.getParent());
    try (BufferedReader in = Files.newBufferedReader(path)) {
      for (String s = in.readLine(); s != null; s = in.readLine()) {
        while (s.endsWith("\\;")) {
          s = s.substring(0, s.length() - 2) + " " + in.readLine().trim();
        }
        s = s.trim();
        if (!s.isEmpty()) {
          CommandUtils.evaluateCommand(s);
        }
      }
    }
    JTerm.setCurrPath(bak);
    return true;
  }
}

@@ -1062,71 +1062,26 @@
     
-boolean hasElse = args.contains(%22 else %22);%0A    String condition
+String%5B%5D thenSplit
  = a
@@ -1099,19 +1099,16 @@
  then %22)
-%5B0%5D
 ;%0A    St
@@ -1115,75 +1115,35 @@
 ring
- part2 = args.split(%22 then %22)%5B1%5D;%0A    String then = hasElse ? part2
+%5B%5D elseSplit = thenSplit%5B1%5D
 .spl
@@ -1158,19 +1158,8 @@
 e %22)
-%5B0%5D : part2
 ;%0A  
@@ -1165,33 +1165,36 @@
    if (eval(
-condition
+thenSplit%5B0%5D
 )) %7B%0A      C
@@ -1254,20 +1254,28 @@
 ommands(
-then
+elseSplit%5B0%5D
 ));%0A    
@@ -1307,67 +1307,29 @@
 if (
-hasElse) %7B%0A      String elseCmd = part2.split(%22 else %22)%5B1%5D;
+elseSplit.length%3E1) %7B
 %0A   
@@ -1401,11 +1401,16 @@
 else
-Cmd
+Split%5B1%5D
 ));%0A
@@ -1531,62 +1531,18 @@
 ring
- condition = args.split(%22 do %22)%5B0%5D;%0A    String command
+%5B%5D doSplit
  = a
@@ -1558,19 +1558,16 @@
 (%22 do %22)
-%5B1%5D
 ;%0A    wh
@@ -1580,17 +1580,18 @@
 val(
-condition
+doSplit%5B0%5D
 )) %7B
@@ -1659,23 +1659,26 @@
 ommands(
-command
+doSplit%5B1%5D
 ));%0A    

Simplify if then else and while