package nxm.sys.libg;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

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

/** Defines a class that will act as a top-level window for NeXtMidas. While any
    class that implements this interface may act as a top-level window it does
    not need to be an actual top-level window (as is the case with the
    {@link nxm.sys.libg.MJPanel} class). <br>
    <br>
    This is an interface to permit {@link nxm.sys.libg.MWindow} to work with frames that may
    be implemented using either AWT or swing components.

    @see nxm.sys.libg.MWindow
    @author  J. Czechowski IV
    @since   NeXtMidas 1.9.2
    @since   NeXtMidas 3.9.2 - created to provide modularity with jdk 11
 */
public interface MidasFrame extends MidasFrameModSwap {

  // Get legacy inc.MidasFrame class and methods, if they exist
  /** Legacy MidasFrame Class in INC package */
  static final Class<?> LEGACY_INC_MIDAS_FRAME_CLASS = ReflectUtil.getClassForName("nxm.sys.inc.MidasFrame");
  /** Legacy MidasFrame.display method from INC package */
  @InternalUseOnly
  public static final Method LEGACY_INC_MIDAS_FRAME_DISPLAY = (LEGACY_INC_MIDAS_FRAME_CLASS == null) ?
      null : ReflectUtil.getMethodOfClass(LEGACY_INC_MIDAS_FRAME_CLASS,"display", int.class);;
      /** Legacy MidasFrame MWindow instance from INC package */
      static final Method LEGACY_INC_MIDAS_FRAME_GET_MWINDOW = (LEGACY_INC_MIDAS_FRAME_CLASS == null) ?
      null : ReflectUtil.getMethodOfClass(LEGACY_INC_MIDAS_FRAME_CLASS,"getMWindow");;

  /** Checks if it is an instance of MidasFrame
   *  (accounts for legacy inc.MidasFrame and the new libg.MidasFrame)
   *  @param obj The object to check
   *  @return    True if it is an instance
   *  @since NeXtMidas 3.9.2
   */
  @InternalUseOnly
  public static boolean isMidasFrame (Object obj) {
    if (LEGACY_INC_MIDAS_FRAME_CLASS == null) {
      return obj instanceof MidasFrame;
    }
    else
      return LEGACY_INC_MIDAS_FRAME_CLASS.isInstance(obj);
  }

  /** Set the frame to FRONT, BACK or ICONIFIED.  Front also de-iconify
   *
   *  @param midasFrameObj The MidasFrame to execute the method
   *  @param mode The int value of the mode
   *  @since NeXtMidas 3.9.2
   */
  @InternalUseOnly
  public static void midasFrameDisplayViaReflection (Object midasFrameObj, int mode) {
    if (LEGACY_INC_MIDAS_FRAME_DISPLAY != null ) {
      // note we can use the inc.MidasFrame, since libg.MidasFrame is an inc
      try {
        LEGACY_INC_MIDAS_FRAME_DISPLAY.invoke(midasFrameObj, mode);
      } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        return;
      }
    }
    else {
      // if inc.MidasFrame has been removed, use the libg code directly
      if (midasFrameObj instanceof MidasFrame) {
        ((MidasFrame)midasFrameObj).display(mode); // Bug 1267: Window XP needs this to display the Frame in the FRONT
      }
    }
  }

  /** Get the MWindow from the MidasFrame (inc or libg version)
   *
   *  @param midasFrameObj   The MidasFrame to get the MWindow from
   *  @return      The MWindow
   *  @since NeXtMidas 3.9.2
   */
  @InternalUseOnly
  public static MWindow getMidasFrameMWindowViaReflection (Object midasFrameObj) {
    if (LEGACY_INC_MIDAS_FRAME_DISPLAY != null ) {
      // note we can use the inc.MidasFrame, since libg.MidasFrame is an inc
      try {
        return (MWindow) LEGACY_INC_MIDAS_FRAME_GET_MWINDOW.invoke(midasFrameObj);
      } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        return null;
      }
    }
    else if (midasFrameObj instanceof MidasFrame) {  // updated in 4.0.0 for NXM-3678
        // if inc.MidasFrame has been removed, use the libg code directly
        return ((MidasFrame)midasFrameObj).getMWindow();
    }
    return null;
  }

}
