package nxm.sys.libg;

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

import nxm.sys.lib.ReflectUtil;

/**
 *  Interface Definitions for Widget Panels.
 *  @author Jeff Schoen
 *  @since NeXtMidas 3.9.2 inc.WidgetPanel is in process of being moved to libg,
 *  due to libg dependencies and the transition to having separate JDK modules for
 *  graphics and the non-graphical library code
 */
public interface WidgetPanel extends nxm.sys.inc.WidgetPanel {

  /** Reference for Interface {@link nxm.sys.inc.WidgetPanel} */
  static final Class<?> INC_WIDGET_PANEL_CLASS = ReflectUtil.getClassForName("nxm.sys.inc.WidgetPanel");
  /** Reference for Method "addWidget": nxm.sys.inc.WidgetPaneladdWidget(GWidget) */
  static final Method WIDGET_PANEL_ADD_WIDGET = ReflectUtil.getMethodOfClass(INC_WIDGET_PANEL_CLASS, "addWidget", GWidget.class);
  /** Reference for Method "layoutWidget": nxm.sys.inc.WidgetPanel.layoutWidget(GWidget) */
  static final Method WIDGET_PANEL_LAYOUT_WIDGET = ReflectUtil.getMethodOfClass(INC_WIDGET_PANEL_CLASS, "layoutWidget", GWidget.class);

  /** Checks to see whether or not a given Java Object is an instance of
      {@link nxm.sys.libg.WidgetPanel} or {@link nxm.sys.inc.WidgetPanel}
      @param obj Object to be checked
      @return whether or not the given Object is an instance of WidgetPanel
   */
  public static boolean isWidgetPanel(Object obj) {
    if (INC_WIDGET_PANEL_CLASS == null) {
      return obj instanceof WidgetPanel;
    }
    else {
      return INC_WIDGET_PANEL_CLASS.isInstance(obj);
    }
  }

  /** Adds a Widget Via Reflection by invoking either:
      {@link #WIDGET_PANEL_ADD_WIDGET} or
      {@link #addWidget(GWidget)}
      depending on the reference to widgetPanel
      @param widgetPanel widgetPanel reference to be checked
      @param obj         the Widget to add
      @return the Widget after it has been added
   */
  public static Object addWidgetViaReflection (Object widgetPanel, GWidget obj) {
    if (WIDGET_PANEL_ADD_WIDGET != null) {
      try {
        return WIDGET_PANEL_ADD_WIDGET.invoke(widgetPanel, obj);
      }
      catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        return null;
      }
    }
    else {
      return ((WidgetPanel)widgetPanel).addWidget(obj);
    }
  }

  /** Layout a Widget Via Reflection by invoking either:
      {@link #WIDGET_PANEL_LAYOUT_WIDGET} or
      {@link #layoutWidget(GWidget)}
      depending on the reference to widgetPanel
      @param widgetPanel widgetPanel reference to be checked
      @param obj         the Widget to layout in the panel
   */
  public static void layoutWidgetViaReflection (Object widgetPanel, GWidget obj) {
    if (WIDGET_PANEL_LAYOUT_WIDGET != null) {
      try {
        WIDGET_PANEL_LAYOUT_WIDGET.invoke(widgetPanel, obj);
      }
      catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {

      }
    }
    else {
      ((WidgetPanel)widgetPanel).layoutWidget(obj);
    }
  }

  /** Adds a widget to the panel. <br>
      <b>Note:</b> To avoid a possible race condition, this method should always be called by the EDT.

      @param obj The widget to add.
      @return <code>obj</code> after it has been added.
   */
  Object addWidget (GWidget obj);

  /** Layout widget panel.
      @param obj The widget to layout in the panel.
   */
  void layoutWidget (GWidget obj);
  }
