package nxm.sys.intr;

import nxm.sys.lib.Command;
import nxm.sys.lib.Intrinsic;
import nxm.sys.lib.Macro;
import nxm.sys.lib.Midas;
import nxm.sys.lib.Shell;
import nxm.sys.lib.Time;

/**
  Handles changing piped processing modes.

  @author Jeff Schoen

*/
public class Pipe extends Intrinsic {

  String func, controls;

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

  public int process() {

    func = MA.getU("FUNC");

    if (func.equals("INIT") || func.equals("ON")) {
      setPipeMode(Midas.PINIT);
      if (MA.find("/PANEL")) {
        String switches = "/MSGID=MAIN/SETUP="+MA.getS("/SETUP");
        if (MA.find("/CONTROLS")) switches += "/CONTROLS="+MA.getS("/CONTROLS");
        Shell.runCommand(M,"PANEL"+switches);
      }
      // This command is in the SPEECH option tree. Uncomment and add option to run
      // if (MA.find("/SPEECHCONTROL")) {
      //   Shell.runCommand(M,"SPEECHCONTROL/MSGID=MAIN/ID=SC");
      // }
    }
    else if (func.equals("RUN")) {
      setPipeMode(Midas.PRUN);
    }
    else if (func.equals("PAUSE")) {
      setPipeMode(Midas.PPAUSE);
      // handled in pipe io class
    }
    else if (func.equals("WAIT")) {
      setPipeMode(Midas.PWAIT);
    }
    else if (func.equals("WAITFOR")) {
      setPipeMode(Midas.PWAIT);
      String regname = MA.getU(2);
      if (M.macro==null) M.warning("No macro running");
      else if (M.registry.get(regname)==null)
	M.warning("WaitFor command "+regname+" not found in registry");
      else M.macro.waitFor = regname;
    }
    else if (func.equals("STOP")) {
      setPipeMode(Midas.PSTOP);
    }
    else if (func.equals("OFF")) {
      nxm.sys.lib.Table.Iterator ti;
      nxm.sys.lib.Table mreg = M.registry.table;
      if (M.macro==null) {
        setPipeMode(Midas.PWAIT);
        // wait for all registered commands to finish
        while (mreg.size()>1) Time.sleep(0.1);
      }
      else if (M.pipeMode==Midas.PINIT || M.pipeMode==Midas.PRUN) {
        setPipeMode(Midas.PWAIT);
        M.macro.nextIndex--;	// repeat command
        return (FINISH);
      }
      setPipeMode(Midas.POFF);
      M.status = Command.EXIT;

      // remove any defunct commands (those that are stuck in INIT state)
      if (M.macro!=null && M.macro.getRegistry()!=null) {
        mreg = M.macro.getRegistry();
        for (ti=mreg.iterator(); ti.getNext();) {
          if (ti.value instanceof Command && ((Command)ti.value).state!=INIT); // ignore commands not stuck in INIT state
          else mreg.remove(ti.key); // remove commands stuck in INIT or other REG entries (e.g. SHELL, HANDLERS, RMIF remotes, etc.)
        }
      }
      // wait for all registered commands to finish
      if (mreg!=null) for (int i=0; i<20 && mreg.size()>1; i++) Time.sleep(0.1);
      // System.out.println("Table size  "+mreg.size()+" "+mreg.toString());
      if (mreg.size()>1) for (ti=mreg.iterator(); ti.getNext();) {
        if (!ti.key.equals("MAIN")) M.warning("Timeout closing "+ti.value);
      }
      if (M.macro!=null && !M.macro.isShared(Macro.SHARE_PIPES)) { // this check added in 3.1.2 to prevent child from removing parent pipes (Bug 2586)
        removePipes(); // since 2.9.0: instead of calling M.pipes.clear() for Bug 2130
      }

      M.status = 0;
    }
    else {
      M.error("Unsupported pipe function: "+func);
    }

    return (FINISH);
  }

  /** Remove only the instances of Pipes from the M.pipes macro
      @since NeXtMidas 2.8.1 / 2.9.0
   */
  private void removePipes () {
    for (String key : M.pipes.getKeys()) {
      Object obj = M.pipes.get(key);
      if (obj instanceof nxm.sys.lib.Pipe) { M.pipes.remove(key); }
    }
  }

  private void setPipeMode (int mode) {
    if (M.macro != null) M.macro.setPipeMode(mode);
    M.pipeMode = mode;
  }

}
