package nxm.sys.intr;

import nxm.sys.lib.Intrinsic;
import nxm.sys.lib.MidasException;
import nxm.sys.lib.Shell;

/** Handle a block <code>DO</code> control statement. This implements the <code>DO</code> loop
    in NeXtMidas Macros.

    @author  Jeff Schoen

    @see Loop
    @see Enddo
 */
public class Do extends Intrinsic {
  static final String DO   = "do";   // Type indicator: DO loop
  static final String LOOP = "loop"; // Type indicator: LOOP loop

  private final String type; // Type of loop (DO or LOOP)

  /** The start value of the loop.  */
  public double start;

  /** The end value of the loop.  */
  public double end;

  /** The incrementation value of the loop.  */
  public double inc;

  /** Label to receive current count within the loop. */
  public String label;

  /** Creates a new instance of a DO loop. */
  public Do () { this(DO); }

  /** Creates a new instance, can be called from Loop() */
  Do (String type) { this.type = type; }

  public int process() {

    if (M.macro == null) {
      String cmd = Macrofunc.enterIntrMacroText(M,"%"+type,MA.getRaw(),"end"+type);
      Shell.runCommand(M,cmd);
      return FINISH;
    }

    if (type == DO) {
      label = MA.getU("LABEL");
      start = MA.getD("START");
      end   = MA.getD("END");
      inc   = MA.getD("INC");
    } else if (type == LOOP) {
      // The following matches X-Midas, note the getL("COUNT") rather than getD("COUNT")
      label = MA.getU("LABEL");
      start = 1;
      end   = MA.getL("COUNT");
      inc   = 1;
      if (end <= 0) { start = 0; end = -1; } // Special case in X-Midas
    } else {
      throw new MidasException("Unknown loop type "+type);
    }

    // decide whether to treat as integer counter
    if (label.length()<3 || label.charAt(1)!=':') {
      if (Math.rint(start)==start &&
          Math.rint(end)==end &&
          Math.rint(inc)==inc ) label = "L:"+label;
    }

    MR.put (label,start);

    // if we are already past the end, jump to the ENDDO
    if ((inc>0 && start>end) ||
  (inc<0 && start<end)) {
      M.macro.nextIndex = nextIndex;
    }
    return FINISH;
  }
}
