package nxm.sys.intr;

import nxm.sys.lib.BaseFile;
import nxm.sys.lib.FileName;
import nxm.sys.lib.Intrinsic;
import nxm.sys.lib.OptionTree;
import nxm.sys.lib.Parser;
import nxm.sys.lib.Shell;
import nxm.sys.lib.Table;
import nxm.sys.lib.TextFile;

/**
  Configures various sections of the Midas environment.
  Check for commands not in alphabetical order.

  @author Jeff Schoen / Jay Hallam
*/
public class Configure extends Intrinsic {

  private final int MIN_CMD_ABBREV = 2;
  private boolean warn = true;

  /** default constructor */
  public Configure () {}

  public int process () {

    String func = MA.getU("FUNC");
    String opt  = MA.getU("OPT", "SYS");
    warn = MA.getState("/WARN", true);

    if (func.indexOf("K") >= 0) clear_commands();
    if (!opt.equals("") && func.indexOf("C") >= 0) add_commands(opt);  // Check for "" added for BUG 2202

    return FINISH;
  }

  /** Clear current command dictionary. */
  private void clear_commands () {
    M.dictionary.clear();
    MR.put("OPT.PATH","", Table.FORCE);

    OptionTree.removeFromOptClasspath(MR.getTable("OPT.CLASSPATH"), "*"); // since 2.9.3 for BUG 1795
  }

  /** Add a command or list of commands to the dictionary.
      @param option Name of the option tree.
   */
  private void add_commands (String option) {
    int ln,la; String line;
    String prevLine = null;
    String fname = M.io.name ("CFG","COMMANDS","CNF",option);
    TextFile file = new TextFile (M,fname);
    boolean open = file.open(BaseFile.INPUT|BaseFile.NOABORT);
    if (!open) {
      String cfg = M.io.name ("CFG","COMMANDS","CFG",option); // X-Midas commands.cfg

      if ((new BaseFile(this,cfg)).exists()) {
        M.info("No NeXtMidas commands found for option ["+option+"], only X-Midas commands were found.");
      }
      else {
        // 2010-11-22 NTN: safe fix for BUG 2279
        String optCfgPath = OptionTree.getOptionPath(M, option, "cfg");
        if (optCfgPath == null) {
          if (warn) M.warning("Unable to find option ["+option+"] on command.cnf. Assuming raw jar. ");
        } else {
          cfg = FileName.addPathRootExt(optCfgPath, "commands", "cfg"); // X-Midas commands.cfg
          if ((new BaseFile(this,cfg)).exists()) {
            M.info("No NeXtMidas commands found; only X-Midas commands were found for option ["+option+"]");
          } else {
            if (warn) M.warning("No file commands.cnf found for option ["+option+"] at path=["+optCfgPath+"]. Assuming raw jar.");
          }
        }
      }
    }
    while (open && (line=file.readProper())!=null) {
      Parser conf = new Parser (line);
      conf.clean();
      String name = conf.get(1);
      ln = name.length();
      la = name.indexOf("*");
      if (la>0) name = name.substring(0,la)+name.substring(la+1);
      else {
// Pre 2.5.0, a minimum abbreviation was used.  Want to use ENTIRE name is none is specified.
//        la = Math.min(name.length(),2);
        if (name.length() > MIN_CMD_ABBREV) {
          M.deprecate("Two character default command abbreviations have been deprecated since 2.5.0.\n"
                     +"Run the UPDATE command on '"+name+"' to remove this warning");
        }
        la = Math.min(name.length(),MIN_CMD_ABBREV);
        //if (la <= MIN_CMD_ABBREV) System.out.println("Name '"+name+"', len "+name.length()+" la "+la);
      }
      name += ";"+option+":"+la;
      line = conf.getAll();
      line = name+line.substring(ln);
      if (prevLine != null) {
        if (line.charAt(0) < prevLine.charAt(0)) {
          M.warning ("Command '"+line+"'"+" appears out-of-order in "+option);
        }
      }
      prevLine = line;
      line = checkArgCount(line);
      if (option.equals("SYS")) M.dictionary.append(line);
      else M.dictionary.insert(line);
    }
    file.close();
    M.dictionary.genAlpha();
    removeFromPath(option);
    addToPath(option);
  }

  private String checkArgCount(String line) {
    Parser parser = new Parser(line);
    String NARGS = parser.get(3);
    boolean xargs = false;
    if (NARGS.endsWith("+")) {
      NARGS = NARGS.substring(0, NARGS.length() - 1);
      xargs = true;
    }
    int numArgs = -1;
    try {
      numArgs = Integer.parseInt(NARGS);
    } catch (Exception e) {
      e.printStackTrace();
    }

    int argCount = 0;
    for (int arg = 1; (arg+3) <= parser.elements(); arg++) {
      // unfortunately we can't do simple arithmetic here because we need to ignore switches
      if (parser.get(arg+3).startsWith("/"))
        continue;
      argCount++;
    }

    if (!xargs && argCount > numArgs) {
      String[] nameParts = parser.get(1).split("[:;]");
      Shell.warning(String.format("The %s command takes in %d parameters, but %d defaults given. Please run 'UPDATE %s;%s' to correct this.",
        nameParts[0], numArgs, argCount, nameParts[0], nameParts[1]));
      // modify line
      String newLine = parser.get(1) + "," + parser.get(2) + "," + argCount + ",";
      for (int i = 4; i <= parser.elements(); i++)
        newLine += parser.get(i) + ",";
      return newLine;
    }
    return line;
  }

  private void addToPath (String optName) {
    String s = MR.getS("OPT.PATH");
    if (s==null||s.length()==0) s = optName;
    else s = optName+","+s;
    MR.put("OPT.PATH", s, Table.FORCE);
    Shell.addOptToClasspath(optName, true); // Since 2.9.3: passing true for BUG 1795
  }

  private void removeFromPath (String optName) {
    String s = MR.getS("OPT.PATH");
    if (s==null||s.length()==0) return;
    String sc = ","+s+",";
    String oc = ","+optName+",";
    int i = sc.indexOf(oc);
    if (i<0) return;
    else if (i==0) sc = sc.substring(optName.length()+1);
    else sc = sc.substring(0,i)+sc.substring(i+optName.length()+1);
    if (sc.equals(",")) s = "";
    else s = sc.substring(1,sc.length()-1);
    MR.put("OPT.PATH", s , Table.FORCE);
  }

}
