package nxm.sys.intr;

import java.lang.reflect.Method;

import nxm.sys.inc.InternalUseOnly;
import nxm.sys.lib.Intrinsic;

/** Turns on/off the internal debug options.

    @author Jeff Schoen / Neon Ngo
*/
public class Debug extends Intrinsic implements nxm.sys.inc.Debug {

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

  public int open () {
    int len;
    String result = "OLDDEBUGMODE";

    if ((len = MA.getLength("/SAVE")) >= 0) {
      if (len > 0) result = MA.getU("/SAVE");
      // Note: SAVE saves the LOCAL Debug flags, but LOAD will set BOTH
      // the LOCAL and GLOBAL Debug flags
      MR.put(result, M.getDebug());
      if (verbose) M.info("Saved DEBUG mode to '"+result+"'");
      return FINISH;
    }
    else if ((len = MA.getLength("/LOAD")) >= 0) {
      if (len > 0) result = MA.getU("/LOAD");
      // Sets the LOCAL Debug flags
      M.setDebug(MR.getS(result));
      // Sets the GLOBAL Debug flags
      nxm.sys.inc.Debug.saveGlobalDebugSettings(MR, M.debug); // since 3.1.2 for BUG 2562

      if (verbose) {
        M.info("Loaded DEBUG mode from '"+result+"'");
        displayCurrentSettings();       // since 3.1.1
      }
      return FINISH;
    }
    else if (!MA.find("STATE")) {
      displayCurrentSettings();
      return FINISH;
    }

    boolean state = MA.getZ("STATE");
    String  func  = MA.getS("FUNC");

    // If there's a dot in the function name, then assume its a classname and
    // try to set its static debug.
    if ( func.indexOf(".") > -1 ) {
      M.info("Turning on debug for "+MA.getQ("FUNC"));
      setStaticDebug(MA.getQ("FUNC"),state);
      return FINISH;
    }

    if (state) M.setDebug("+"+func);
    else       M.setDebug("-"+func);
    nxm.sys.inc.Debug.saveGlobalDebugSettings(MR, M.debug);      // since 3.1.2 for BUG 2562

    if (verbose) displayCurrentSettings(); // since 3.1.1

    return NORMAL;
  }

  /** display current DEBUG environment settings to terminal
      @since 3.1.1 (extracted from open so that it can be used in several places without cut/paste)
   */
  private final void displayCurrentSettings () {
    // 2012-02-22 NTN: also switched to false for recurse parameter since it should just be a masked string
    nxm.sys.intr.Results.listSingleResult(M, M.results, "ENV.DEBUG", 0, false);
  }

  /** Attempts to set the state of the static debug property in the given
      classname. The className must be a fully qualified class that contains a
      static setDebug(boolean) method. This naming convention for the debug
      method conforms with the Java Beans standard.

      @param className The fully qualified class name.
      @param state The boolean state to set debug to.
      @return True if the state was successfully set, false otherwise.
  */
  public boolean setStaticDebug (final String className, boolean state) {
    try {
      Class<?> clazz = Class.forName(className);
      Method method = clazz.getMethod("setDebug", new Class<?>[]{boolean.class});
      if (method != null) method.invoke(null, new Object[]{Boolean.valueOf(state)});
      return true;
    } catch ( Exception excep ) {
      M.warning(excep.toString()); // special case, don't include stack trace
      return false;
    }
  }

  /** Save current debug settings into GLOBAL debug settings: <br>
      1. Shell.getMidasContext() (to effect all future Midas contexts)
      2. ENV.DEBUG table (for save/load state)
      @param MR Results table
      @param debugMask debug mask to save into global debug settings
      @since NeXtMidas 3.1.2 (public for internal use in 3.5.2)
      @since NeXtMidas 3.9.2 moved to inc.Debug, but was always InternalUseOnly
  */
  @InternalUseOnly
  @Deprecated
  public static void saveGlobalDebugSettings (nxm.sys.lib.Results MR, final int debugMask) {
    nxm.sys.inc.Debug.saveGlobalDebugSettings(MR, debugMask);
  }
}
