package nxm.sys.libg;

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

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

/** This is the new GPrimitive that will extend lib.GPrimitive until the switch to Modularity.
 *
 *  @author Kevin Esterheld
 *  @since 3.9.2
 */
public class GPrimitive extends GPrimitiveModSwap {
  // Reflection is used to execute the correct methods based on instance type (lib.gprimitive vs libg.gprimitive)
  private static final Class<?> LEGACY_LIB_GPRIMITIVE_CLASS;
  private static final Method LEGACY_LIB_GPRIMITIVE_GET_MWINDOW;
  private static final Method LEGACY_LIB_GPRIMITIVE_GET_GRAPHICS_CONTAINER;

  static {
    Class<?> libGPrimitiveClass;
    // If the legacy lib version exists, then it will be used.  The new libg GPrimitive
    // extends lib while we are still supporting both.  Users should move to the libg version,
    // which was created to support having graphics/commands in a separate JDK module than
    // non-graphical library code.  Since 3.9.2.
    try {
      libGPrimitiveClass = Class.forName("nxm.sys.lib.GPrimitive");
    }
    catch (ClassNotFoundException e) {
      libGPrimitiveClass = null;
    }
    if (libGPrimitiveClass != null) {
      LEGACY_LIB_GPRIMITIVE_CLASS = libGPrimitiveClass;
      LEGACY_LIB_GPRIMITIVE_GET_MWINDOW = ReflectUtil.getMethodOfClass(LEGACY_LIB_GPRIMITIVE_CLASS,"getMWindow");
      LEGACY_LIB_GPRIMITIVE_GET_GRAPHICS_CONTAINER = ReflectUtil.getMethodOfClass(LEGACY_LIB_GPRIMITIVE_CLASS,"getGraphicsContainer");
    }
    else {
      LEGACY_LIB_GPRIMITIVE_CLASS = null;
      LEGACY_LIB_GPRIMITIVE_GET_MWINDOW = null;
      LEGACY_LIB_GPRIMITIVE_GET_GRAPHICS_CONTAINER = null;
    }
  }

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

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

  /** Get the MWindow from the GPrimitve (lib or libg version)
  *
  *   @param obj   The GPrimitive to get the MWindow from
  *   @return      The Mwindow
  *   @since NeXtMidas 3.9.2
  */
  @InternalUseOnly
  public static MWindow getMWindowViaReflection (Object obj) {
    if (LEGACY_LIB_GPRIMITIVE_GET_MWINDOW != null ) {
      try {
        return (MWindow) LEGACY_LIB_GPRIMITIVE_GET_MWINDOW.invoke(obj);
      }
      catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
       return null;
      }
    }
    else if (obj instanceof GPrimitive) {
      // if lib.GPrimitive has been removed, use the libg code directly
      return ((GPrimitive)obj).getMWindow();
    }
    return null;
  }

  /** The container that the GPrimitive is in
   *
   *  @param obj The GPrimitive to get the container from
   *  @return    The Container object
   *  @since NeXtMidas 3.9.2
   */
  @InternalUseOnly
  public static Container getGraphicsContainerViaReflection (Object obj) {
    if (LEGACY_LIB_GPRIMITIVE_GET_MWINDOW != null ) {
      try {
        return (Container) LEGACY_LIB_GPRIMITIVE_GET_GRAPHICS_CONTAINER.invoke(obj);
      } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        return null;
      }
    }
    else if (obj instanceof GPrimitive) {
      // if lib.GPrimitive has been removed, use the libg code directly
      return ((GPrimitive)obj).getGraphicsContainer();
    }
    return null;
  }

}
