package nxm.sys.test.junit.lib;

import java.net.UnknownHostException;

import nxm.sys.lib.Command;
import nxm.sys.lib.Midas;
import nxm.sys.lib.NeXtMidas;
import nxm.sys.lib.Shell;
import nxm.sys.prim.fft;
import nxm.sys.prim.plot;
import nxm.sys.prim.waveform;
import nxm.sys.test.junit.NMTestCase;

/** WARNING: This will mess up your nextmidas session - run with caution.
 *  This will test that the setting of state works as intended
 *  When using the {@link nxm.sys.inc.Commandable#FINISH}, the command should exit out and be removed from the registry
 *  When using the {@link nxm.sys.inc.Commandable#Stop}, the command should exit out and remain in the registry
 *  The registry functions tested will be
 *  @author Jeanette McCall / Kevin Esterheld
 *
 */
public class CommandTest extends NMTestCase {

  int SLEEP = 2000;

  /** public constructor to allow running this test case directly with JUnit. */
  public CommandTest (String methodName) { this(methodName, null); }

  /** This constructor is required by NeXtMidas Unit Testing framework.
      @param methodName The name of the method being called.
      @param midas      The midas context to use when running the tests.
   */
  public CommandTest (String methodName, Midas midas) {
    super(methodName, midas);

  }

  private static final NeXtMidas NXM = NeXtMidas.getGlobalInstance();

  /**
   * Starts up the pipe
   */
  private void startupPipe () {
    NXM.setHeadless(true);
    NXM.runCommand("PIPE,ON");
    NXM.runCommand("PIPE,RUN");
  }

  /**
   * Stop the pipe
   */
  private void stopPipe () {
    NXM.runCommand("PIPE,STOP");
  }

  /**
   * Runs the commands to have state tested.
   * @param id the unique id to reference the command object in the registry
   * @return   the command objects that have been run
   */
  private Command[] runCommands(String id) {
    String plotTitle = "Plot FFT for setState test";
    Command waveCmd = NXM.runCommand("WAVEFORM/BG/ID=WAVE_"+id+
        " _WAVE_"+id+
        " FORM=CF"+
        " ELEM=inf"+
        " SHAPE=SINE"+
        " RF=300.1e6"+
        " VRF=300e6" +
        " BW=1e6" +
        " /RT");
    Command fftCmd = NXM.runCommand("FFT/BG/ID=FFT_"+id+
        " _WAVE_"+id+
        " _FFT_"+id+
        " NFFT=16K"+
        " OVER=0.0"+
        " /PSD=1");
    if (!Shell.isGradleBuild()) {
      Command fftPlotCmd = NXM.runCommand("PLOT/BG/ID=FFT_PLOT_"+id+
          " _FFT_"+id+
          " /THEME=WoB"+
          " /WTITLE=\""+plotTitle+"\""+
          " /READOUT=OnAxis");
      return new Command[] {waveCmd, fftCmd, fftPlotCmd};
    }
    else return new Command[] {waveCmd, fftCmd};
  }

  public void testSetStateStop () {
    startupPipe();
    String id = "SET_STATE_STOP";
    Command[] runningCmds = runCommands(id);
    stop(runningCmds, Command.STOP);
    assertEquals(NXM.getShell().M.getRegistry().get("WAVE_"+id).getClass(), waveform.class);
    assertEquals(NXM.getShell().M.getRegistry().get("FFT_"+id).getClass(), fft.class);
    if (!Shell.isGradleBuild()) assertEquals(NXM.getShell().M.getRegistry().get("FFT_PLOT_"+id).getClass(), plot.class);
    stopPipe();
  }

  public void testSetStateFinish () throws UnknownHostException {
    startupPipe();
    String id = "SET_STATE_FINISH";
    Command[] runningCmds = runCommands(id);
    long start = System.currentTimeMillis();
    try {
      stop(runningCmds, Command.FINISH);
      // Sleep to give the commands time to exit out.
      Thread.sleep(SLEEP);

    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    while(NXM.getShell().M.getRegistry().get("WAVE_"+id)!=null) {
      if(System.currentTimeMillis()-start >20) break; // Break out and fail tests, took way too long
    }
    assertNull(NXM.getShell().M.getRegistry().get("WAVE_"+id));
    assertNull(NXM.getShell().M.getRegistry().get("FFT_"+id));
    if (!Shell.isGradleBuild()) assertNull(NXM.getShell().M.getRegistry().get("FFT_PLOT_"+id));
    stopPipe();
  }
  /** Tells everything to stop. */
  private void stop (Command[] cmdsToStop, int setStateCmd) {
    String strSetStateCmd = null;
    switch (setStateCmd) {
      case Command.ABORT:
        strSetStateCmd = "FINISH";
        break;
      case Command.STOP:
        strSetStateCmd = "STOP";
        break;
    }

    for (Command cmd : cmdsToStop) {

      if (cmd !=null) {
        Midas.log("Stopping cmd: "+ cmd.id + " with " + strSetStateCmd, Midas.INFO);
        cmd.setState(setStateCmd);
      }
    }
  }


}