package nxm.xbc.prim;

import java.awt.Graphics;

import nxm.sys.inc.Filter;
import nxm.sys.lib.Args;
import nxm.sys.lib.Convert;
import nxm.sys.lib.Data;
import nxm.sys.lib.DataFile;
import nxm.sys.lib.Message;
import nxm.sys.lib.Midas;
import nxm.sys.lib.Shell;
import nxm.sys.lib.Table;
import nxm.sys.libg.GAlert;
import nxm.sys.libg.GLabel;
import nxm.sys.libg.GMenu;
import nxm.sys.libg.GPrimitive;
import nxm.sys.libg.GQuery;
import nxm.sys.libg.GWidget;
import nxm.sys.libg.MWindow;
import nxm.sys.libg.WidgetPanel;

/**
  Panel for XPIPE/XCNTRL functions

  @author Jeff Schoen
  @since NeXtMidas 2.7.0
*/
public class xpanel extends GPrimitive implements WidgetPanel, Filter {

  private boolean headless;
  private int filterMode;
  private int maxWidget=64;

  private int initialEntry,eachEntry,finalEntry;
  private int controlsEntry=0;
  private boolean inControls;

  private Data sdd,scp;
  private DataFile sdf;
  private int ncp;

  private GMenu mainmenu;
  private int nwidget;
  private GWidget[] widget = new GWidget[maxWidget];

  private static final String exitList = "RETURN,MENU,MESSAGE,WINDOW";
  private static final int EXIT_RETURN=0x1, EXIT_MENU=0x2, EXIT_MESSAGE=0x4, EXIT_WINDOW=0x8;
  private int exit;

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

  public int open () {
    String title;
    exit = MA.getOptionMask("/EXIT", exitList, exit);
    if (M.macro==null) {
      title = "X-Pipe";
    } else {
      title = M.macro.getName();
      int setup = MA.getL("/SETUP");
      if (setup>0) {
        openSetupFile(setup);
        prepTxtArgs(MA);
        for (int i=1; i<M.macro.lastIndex; i++) prepTxtArgs(M.macro.lines[i]);
      }
      M.macro.adjustStaticCount(1);
      initialEntry = M.macro.lookupIndex("INITIALENTRY");
      eachEntry    = M.macro.lookupIndex("EACHENTRY");
      finalEntry   = M.macro.lookupIndex("FINALENTRY");
    }
    MW = new MWindow(title,this);
    if (!headless) {
      MW.open();
      MW.addTo(this);
      mainmenu = new GMenu(MW,"X-PIPE","Macro Options,Primitives,Controls,End Macro",0,GMenu.PERM,this);
    }
    if (MA.getState("/CONTROLS")) MQ.put("X-PIPE",0,"CONTROLS");
    return NORMAL;
  }

  public int process () {
    for (int i=1; i<=nwidget; i++) widget[i].poll();
    return NOOP;
  }

  public int close () {
    MW.close();
    return NORMAL;
  }

  /** Refresh the panel */
  public void refresh () {
    if (MQ != null) MQ.remove("REFRESH");
    if ((MW != null) && (MW.panel != null)) MW.panel.repaint();
  }

  /** Resize panel - TODO: not implemented */
  public void resize() {
  }

  private void paint (Graphics g) {
    if (headless) return;
    MW.setGraphics(g);
    MW.clear(g);
  }

  public int processMessage (Message msg) {
    String text;

    // convert a few special sequences to specifically named messages
    if (msg.name.equals("KEYPRESS")) {
      text = msg.getS();
      if (text.equalsIgnoreCase("M")) msg.name = "MENU";
      if (text.equalsIgnoreCase("Enter") && (exit&EXIT_RETURN)!=0) msg.name = "EXIT";
    }
    if (msg.name.equals("BUTTON") && msg.info==2) {
      msg.name = "MENU";
    }

    if (msg.from instanceof GWidget) {
      GWidget gw = (GWidget)msg.from;
      if (gw.label!=null && gw.label.length()>0) {
        if (gw instanceof GMenu) MR.put(gw.label,msg.info);
        else  MR.put(gw.label,msg.data);
      }
      if (gw.callback > 0) MQ.put(new Message("EXEC",gw.callback,null),"MAIN");
    }
    else if (msg.name.equals("PAINT")) {
      paint ((Graphics)msg.data);
    }
    else if (msg.name.equals("RESIZE")) {
      resize();
    }
    else if (msg.name.equals("POINTER")) {
    }
    else if (msg.name.equals("SHOW")) {
      MW.display(msg.info);
    }
    else if (msg.name.equals("SHOWN")) {
      if (MW.status!=MWindow.INIT) MW.status=msg.info;
    }
    else if (msg.name.equals("REFRESH")) {
      refresh(); // doesn't actually draw
    }
    else if (msg.name.equals("RESIZE")) {
      resize();
    }
    else if (msg.name.equals("MENU")) {
      if (inControls) new GMenu(MW,"CONTROL-PANEL","Refresh,Configure,Learn,ExitControls",0,0,this);
    }
    else if (msg.name.equals("X-PIPE")) {
      text = msg.getS();
      if (text.equals("MACRO OPTIONS")) {
        new GMenu(MW,"MACRO OPTIONS","Run,Pause,Sync,Learn,Spawn,Scan,Pipes,Commands,Results,Remotes,Terminal",0,0,this);
      }
      else if (text.equals("PRIMITIVES")) {
        Table t = Convert.o2t(MR.get("REG")); filterMode=1;
        new GMenu (MW,"Primitives",t.getKeyList(this),0,GMenu.STICKY,this);
      }
      else if (text.equals("CONTROLS")) {
        if (initialEntry<0) new GAlert (MW,"Alert","No controls section found","OK",1,0,this);
        else {
          mainmenu.panel.setVisible(false);
          if (controlsEntry==0) MQ.put(new Message("EXEC",initialEntry,null),"MAIN");
          if (eachEntry==0) MQ.put(new Message("EXEC",eachEntry,null),"MAIN");
          if (controlsEntry>0) for (int i=1; i<=nwidget; i++) widget[i].panel.setVisible(true);
          controlsEntry++;
          inControls = true;
        }
      }
      else if (text.equals("END MACRO")) {
        if (M.macro==null) setState(FINISH);
        else M.macro.setPipeMode(Midas.PSTOP);
      }
    }
    else if (msg.name.equals("CONTROL-PANEL")) {
      text = msg.getS();
      if (text.equals("EXITCONTROLS")) {
        inControls = false;
        mainmenu.panel.setVisible(true);
        for (int i=1; i<=nwidget; i++) widget[i].panel.setVisible(false);
      }
    }
    else if (msg.name.equals("MACRO OPTIONS")) {
      text = msg.getS();
           if (M.macro==null);
      else if (text.equals("RUN")) M.macro.setPipeMode(Midas.PWAIT);
      else if (text.equals("PAUSE")) M.macro.setPipeMode(Midas.PPAUSE);
      else if (text.equals("REGISTRY")) new GQuery (MW,"Query Registry",M.registry.table,0,this);
      else if (text.equals("RESULTS")) new GQuery (MW,"Query Results",MR,0,this);
      else if (text.equals("PIPES")) {
        Table t = Convert.o2t(MR.get("RAM"));
        new GMenu (MW,"Pipe",t.getKeyList(),0,GMenu.STICKY,this);
      }
      else if (text.equals("COMMANDS")) {
        Table t = Convert.o2t(MR.get("REG")); filterMode=1;
        new GMenu (MW,"Command",t.getKeyList(this),0,GMenu.STICKY,this);
      }
      else if (text.equals("REMOTES")) {
        Table t = Convert.o2t(MR.get("REG")); filterMode=2;
        new GMenu (MW,"Remote",t.getKeyList(this),0,GMenu.STICKY,this);
      }
      else if (text.equals("SYNC")) {
      }
      else if (text.equals("LEARN")) {
      }
      else if (text.equals("SPAWN")) {
      }
      else if (text.equals("SCAN")) {
        M.macro.getControlWidgets().dump();
        Table t = new Table(MR.getFunctions());
        t.dump();
      }
      else if (text.equals("TERMINAL")) {
        Shell.runCommand (M,"SHELLGUI/ATTACH/BG");
      }
      else if (text.equals("PIPEMON")) {
        Shell.runCommand (M,"GCONTROL,PIPEMON");
      }
    }
    else if (msg.name.equals("DEBUG")) {
      text = msg.getS();
           if (text.equals("RESULTS")) new GQuery (MW,"Query Results",MR,0,this);
      else if (text.equals("TERMINAL")) Shell.runCommand (M,"SHELLGUI/ATTACH/BG");
    }
    else if (msg.name.equals("PIPE")) {
      text = msg.getS();
      new GQuery (MW,"Query "+text,M.pipes.get(text),GQuery.NOEDIT,this);
    }
    else if (msg.name.equals("COMMAND")
          || msg.name.equals("PRIMITIVES")
          || msg.name.equals("REMOTE")) {
      text = msg.getS();
      new GQuery (MW,"Query "+text,M.registry.get(text),0,this);
    }
    else if (msg.name.equals("WINDOW")) {
      if ((exit&EXIT_WINDOW)!=0 && msg.data.equals("CLOSING")
           && M.macro!=null) M.macro.setPipeMode(Midas.PSTOP);
    }
    else if (msg.name.equals("EXIT")) {
      if ((exit&EXIT_MESSAGE)!=0) return FINISH;
    }
    else if (msg.name.equals("FOCUS"));
    else {
      M.info("Unhandled message: "+msg);
    }

    return NORMAL;
  }

  /** Open the xpanel setup file
   *  @param setup the xpanel setup file
   */
  public void openSetupFile (int setup) {
    sdf = new DataFile(M,M.macro.getFileName());
    String ext = "set";
    if (setup>1) ext += setup;
    sdf.setExt(ext);
    sdf.open();
    sdd = sdf.getDataBuffer(1);
    scp = (Data)sdf.keywords.get("PANEL_SETUP");
    if (scp!=null) ncp = scp.getSize()/3;
  }

  /** Prepare xpanel arguments
   *  @param args The Midas Arguments
   */
  public void prepTxtArgs (Args args) {
    int xs = args.getL("/XS");
    if (xs>0) {
      if (MA.getState("/XAUTOID")) {
        args.put("/ID",""+xs);
      }
      if (sdf!=null && xs<=sdf.getSize()) {
        sdf.read(sdd,(double)(xs-1),1);
        if (args.support=='P') {
          java.awt.Rectangle r = nxm.sys.libg.MJFrame.getDisplay("0").getBounds();
          int xl = (sdd.getL(0) * r.width/1000);
          int xt = (sdd.getL(1) * r.height/1000);
          int xw = (sdd.getL(2) * r.width/1000);
          int xh = (sdd.getL(3) * r.height/1000);
          args.put("/WPOS","("+xl+","+xt+","+xw+","+xh+")");
        } else {
          args.put("/XL",""+sdd.getL(0));
          args.put("/XT",""+sdd.getL(1));
          args.put("/XW",""+sdd.getL(2));
          args.put("/XH",""+sdd.getL(3));
        }
      }
    }
  }

  GLabel curGLabel,gwg;

  public Object addWidget (GWidget gw) {
//System.out.println("Adding "+gw);

    if (gw==null) return null;
    if (gw instanceof GLabel) curGLabel=(GLabel)gw;
    GLabel gwg = curGLabel;
    int i = ++nwidget;
    if (gw.group != null) {
      for (i=1; i<nwidget && !widget[i].group.equals(gw.group); i++);
      gwg = (GLabel)widget[i]; // not adding to curGLabel
      for (;i<nwidget && widget[i].group.equals(gw.group); i++);
      for (int j=nwidget; j>i; j--) widget[j]=widget[j-1];
    }
    if (gwg!=null) { gw.pGroup=gwg; gw.setGroup(gwg.label); }
    widget[i] = gw;
    gw.setTheme(MW.theme);
    gw.setWidgetPanel(this);
    if (scp!=null && i<=ncp) {
      int ioff = (i-1)*3;
      int x=scp.getL(ioff+0);
      int y=scp.getL(ioff+1);
      gw.pos.setLocation(x,y);
    } else {
      gw.rx=-1;
    }
    if (gw.callback<=0 && M.macro!=null) {
      int index = M.macro.lookupIndex("START"+nwidget);
      if (index>0) gw.callback = index+1;
    }
    gw.parent=gw.MW=MW;
    if (headless || (gw.flags&GWidget.HEADLESS)!=0) return gw;
    gw.resize(1);
    MW.addOn(gw.panel);
    return gw;
  }

  public void layoutWidget (GWidget gw) {}

  public boolean accept (Object entry) {
    boolean rmif = entry instanceof nxm.sys.prim.rmif;
    boolean remote = entry instanceof nxm.sys.net.Rmif.Remote;
    boolean command = entry instanceof nxm.sys.lib.Command;
    if (filterMode==1 && command) return true;
    if (filterMode==2 && rmif) return true;
    if (filterMode==2 && remote) return true;
    return false;
  }

  /** Indicates if the panel is running in headless mode.
      @return <code>true</code> if in headless mode, <code>false</code> otherwise.
   */
  public boolean isHeadless () { return headless; }

}