package nxm.sys.libg;

import java.awt.Component;
import java.awt.Container;
import java.awt.Frame;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import nxm.sys.lib.Command;
import nxm.sys.lib.Message;
import nxm.sys.lib.Table;
import nxm.sys.libg.GridSheet.GridSheetReference;

/**
    A class for handling F1 keyboard events. When the event is processed, this class finds
    the component over which the mouse is pointed, and sends a help message to the macro,
    if there is one. The message sent has a name value of "HELP" and a data value that is
    the component's name (a label for GWidget, the id for a plot, panel, or GridSheet).
 */
public class HelpKeyListener extends KeyAdapter {
  MWindow mwindow = null;

  /**  Constructs a new HelpKeyListener.
   *   @param mw MWindow associated with this HelpKeyListner  */
  public HelpKeyListener(MWindow mw) {
    mwindow = mw;
  }

  @SuppressWarnings("deprecation")
  public void keyPressed(KeyEvent e){
    int keycode = e.getKeyCode();
    if (keycode == KeyEvent.VK_F1) {

      Component sourceComp = (Component) e.getSource();
      Container cont = sourceComp.getParent();

      //get the top level container, which is either a Frame(Frame or JFrame)
      while (!(cont instanceof Frame)) {
        cont = cont.getParent();
      }
      //get the MWindow of the top level container
      MWindow topmw = null;
      if (cont instanceof MFrame)
        topmw = ((MFrame)cont).MW;
      else if (cont instanceof MJFrame)
        topmw = ((MJFrame)cont).MW;
      else return;

      //Get handle to the macro to which this message is sent
      Command cmd = null;
      if (topmw.mh instanceof Command) cmd = (Command)topmw.mh;
      if (cmd == null || cmd.M.macro == null) return;

      //get all nested components in the top-level container
      ArrayList<Component> allComps = getComponents(cont);
      MWindow mw = null;

      String compName = "";
      Object compValue = null;

      Table data = new Table();

      //Find the MWindow where the mouse pointer is active
      //Get the name of the component over which the pointer rests
      for (Component c : allComps) {
        mw = null;

        if (c instanceof MPanel) {
          mw = ((MPanel)c).MW;
          if (mw.pactive) {
            if (mw instanceof GWidget) {
              GWidget gw  = ((GWidget)mw);
              compName  = gw.getLabel();
              compValue = gw.getValue();
            }
            else if (mw instanceof MPlot) {
              if (mw.mh instanceof Command)
                compName = ((Command)mw.mh).getID();
            }
            else { //it's a GridSheet (LIST) or MPanel
              Component compo = mw.panel.getComponentAt(mw.px, mw.py);
              if (mw.mh instanceof Command) {
                if (mw.mh instanceof GridSheet.GridSheetReference) { // i.e. it's a LIST
                  GridSheet gs = ((GridSheetReference)mw.mh).getGridSheet();
                  int row = gs.getSelectedRow();
                  int col = gs.getSelectedColumn();
                  data.put("ROW", row);
                  data.put("COL", col);
                  if (row > 0 && col > 0) {
                    compValue = gs.getCell(row,col);
                  }
                }
                compName = ((Command)mw.mh).getID();
              }
            }
            if (!compName.equals("")) break;
          } //end if (mw.pactive)
        } //end if (c instanceof MPanel)
      } //end for
      //If no active mwindow found, return
      if (compName.equals("")) return;
      //Send the message
      data.put("NAME", compName);
      data.put("VALUE", compValue);
      Message msg = new Message("HELP", 0, data);
      cmd.M.macro.processMessage(msg);
      e.consume();
    }
  }
  /** Recursively get the components nested within the given component,
        if it is a Container.
        @param c The component under which to search for nested components.
        @return An ArrayList containing the component parameter, and any
        nested components if it is a Container.
   */
  private ArrayList<Component> getComponents(Component c) {
    ArrayList<Component> clist = new ArrayList<>(), al = null;
    clist.add(c);
    if (!(c instanceof Container)) return clist;
    else {
      Component[] comps = ((Container)c).getComponents();
      for (Component comp : comps) {
        al = getComponents(comp);
        for (Component childComp : al) {
          clist.add(childComp);
        }
      }
      return clist;
    }
  }
}
