package nxm.xbc.intr;

import nxm.sys.inc.MessageHandler;
import nxm.sys.lib.Intrinsic;
import nxm.sys.lib.KeyVector;
import nxm.sys.lib.Parser;
import nxm.sys.libg.GFiles;
import nxm.sys.libg.GList;
import nxm.sys.libg.GMenu;
import nxm.sys.libg.GPrompt;
import nxm.sys.libg.GValue;
import nxm.sys.libg.GWidget;
import nxm.sys.libg.WidgetPanel;

/**
  Creates a graphical control widget for an X-Midas compatible user interface.

  @author Jeff Schoen
*/
public class Xcontrol extends Intrinsic {

  private String type,name;
  private GWidget widget;
  private Object parent;
  private MessageHandler owner;
  private boolean xcall,oneshot;
  private int flags;

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

  public int open() {

    // Get parameters
    type = MA.getU("TYPE");
    name = MA.getU("NAME");

    String panel = MA.getU("/PANEL","XPANEL");
    parent = M.registry.get(panel);
    if (parent==null) parent=this;
    xcall = this instanceof nxm.xbc.intr.Xcall;
    oneshot = xcall || (parent==this);

    int monitor = 0;
    int mi = 0; // match index

    flags = 0;
    if (oneshot) {
      owner = this;
    } else {
      owner = this;
      if (!MA.getState("/TEMP")) flags |= GWidget.PERM;
    }
    if (MA.getState("/NODISP")) flags |= GWidget.HEADLESS;

    if (type.startsWith("SETC")) {
      return FINISH;
    }
    else if (type.equals("MENU")) {
      String list = MA.getCS("P4","Item 1,Item 2,Item 3,Item 4");
      int semi = list.indexOf(';');
      String title = MA.getS("/NAME");
      if (semi>=0) { title = list.substring(0,semi); list = list.substring(semi+1); }
      if (title.length()==0) flags |= GMenu.TOFF;
      flags = getFlags(GMenu.flagsList,flags|GMenu.FLAT);
      GMenu menu = new GMenu(null,title,list,0,flags,owner);
      menu.setColumns(MA.getL("/NC",0));
      widget = menu;
      monitor = 5;
    }
    else if ((mi=type.indexOf("PROMPT")) >= 0) {
      char dt = (mi==1)? type.charAt(0) : 'S';
      String seed  = MA.getCS("INIT","default");
      String title = MA.getU("P4","Input");
      int digits   = MA.getL("P5",MA.getL("LEN",10));
      flags = getFlags(GPrompt.flagsList,flags);
      widget = (GWidget) new GPrompt (null,title,seed,digits,flags,owner);
      monitor = 2;
    }
    else if ((mi=type.indexOf("MON")) >= 0) {
      char dt = (mi==1)? type.charAt(0) : 'S';
      flags = getFlags(GPrompt.flagsList,flags|GWidget.HEADLESS);
      widget = (GWidget) new GPrompt (null,"Value","",10,flags,owner);
      monitor = 2;
    }
    else if (type.indexOf("VAL")==1) {
      char dt   = type.charAt(0);
      double v  = MA.getD("INIT");
      double v1 = MA.getD("P4",0.0);
      double v2 = MA.getD("P5",1.0);
      double vd = MA.getD("P6",(v2-v1)/20);
      flags = getFlags(GValue.flagsList,flags|GValue.SLIDER);
      String title = MA.getS("/NAME",MA.getS("NAME"));
      GValue valu  = new GValue (null,title,v,v1,v2,vd,dt,flags,owner);
      valu.setFormat(MA.getU("/FMT"),MA.getO("/MULT",null));
      widget = valu;
      monitor = 7;
    }
    else if (type.startsWith("LIST")) {
      String title = MA.getU("TITLE","Title");
      String text  = MA.getCS("P1","");
      int cols = MA.getL("P2",24);
      int rows = MA.getL("P3",1);
      flags = getFlags(GList.flagsList,flags);
      widget = (GWidget) new GList (null,title,text,cols,rows,flags,owner);
    }
    else if (type.startsWith("FILE")) {
      String title = MA.getU("TITLE","FileName");
      String seed  = MA.getCS("P1","");
      String filt  = MA.getCS("P2","*.tmp|prm");
      String raux = MA.getCS("P3",MR.getS("AUX.WRITE"));
      int cols = MA.getL("P4",50);
      int rows = MA.getL("P5",15);
      flags = getFlags(GFiles.flagsList,flags);
      if ((flags&GWidget.PERM)!=0)
        widget = (GWidget) new GPrompt (null,title,seed,filt,raux,M,cols,rows,flags,owner);
      else
        widget = (GWidget) new GFiles (null,title,seed,filt,raux,M,cols,rows,flags,owner);
    }
    else {
      M.warning ("Unknown widget type: "+type);
      return FINISH;
    }

    // parse result to monitor
    if (monitor>0) {
      String mlabel = MA.getU(monitor);
      if (mlabel==null || mlabel.length()==0);
      else if (mlabel.startsWith("T:")) mlabel = mlabel.substring(2);
      else if (mlabel.charAt(0)>='0' && mlabel.charAt(0)<='9') mlabel = "W_"+mlabel;
      widget.setMonitor(mlabel);
    }

    // finish stuff common to all widgets
    widget.setLabel(name);
    widget.setTheme(MA.getO("/THEME"));
    widget.setGroup(MA.getU("/GRP"));
    widget.setUnits(MA.getCS("/UNITS"));
    widget.fixHeight(MA.getL("/WH",0));
    widget.fixWidth(MA.getL("/WW",0));
    widget.setFontSize(MA.getL("/WFS",0));
    widget.setMidas(M);
    widget.setHandler((MessageHandler)parent);
    widget.setFrom(widget);

    // parse for callback routine
    String callback = MA.getS("/LAB");
    if (M.macro!=null && callback!=null && callback.length()>0) {
      int index = M.macro.lookupIndex(callback);
      if (index>0) widget.callback = index+1;
    }

    // provide handle in results table
    String handle = MA.getU("/HANDLE");
    MR.put(handle,widget);

    // run one-shot to completion
    if (oneshot) widget.addTo(parent);
    // attach to the control panel
    else if (parent instanceof WidgetPanel) ((WidgetPanel)parent).addWidget(widget);
    // attach to the other panel
    else  widget.addTo(parent);

    return NORMAL;
  }

  public int process() {
    if (oneshot && widget.status!=GWidget.EXIT) return NOOP;
    return FINISH;
  }

  public int processMessage (nxm.sys.lib.Message msg) {
    if (msg.name.equals(name)) {
      //M.info ("Got message: "+msg.name);
      MR.put(name,msg.data);
    }
    else if (msg.name.equals("EXIT")) return FINISH;
    else if (msg.name.equals("REFRESH")) widget.refresh();
    else if (msg.name.equals("SHOWN")) widget.refresh();
    else M.info ("Unhandled message: "+msg.name);
    return NORMAL;
  }

  /** convert any local switches that match widget flag names
      there are 8 common flags (below), plus any widget specific flags
      "Permanent,Sticky,Fixed,NoEdit,InLine,InBand,NoMsg,Monitor"
  */
  private int getFlags (String flagsList, int flags) {
    String vbox = MA.getU("/INPUTBORDER",MA.getU("/VBOX"));
    if (vbox.equalsIgnoreCase("PERM")) flags |= GWidget.VBOX;
    else if (vbox.equalsIgnoreCase("MO")) flags |= GWidget.VBOXMO;
    KeyVector kv = MA.getKV();
    if (MA.nargs+1>=kv.size()) return flags;	// quick out if no local switches
    flags |= MA.getOptionMask("/FLAGS",flagsList,0);
    Parser parser = new Parser(flagsList.toUpperCase());
    String[] list = parser.getArray(0);
    for (int i=MA.nargs+1; i<kv.size(); i++) {
      String key = kv.getKey(i);
      if (key.charAt(0)!='/') continue;	// only for switches
      String ykey = key.substring(1);
      String nkey = "NO"+ykey;
      for (int mask=1,j=0; j<list.length; j++,mask<<=1) {
        if (ykey.equals(list[j]) && MA.getState(key)) flags |= mask;
        if (nkey.equals(list[j]) && !MA.getState(key)) flags |= mask;
      }
    }
    // these flags do not show up in the flagsList field
    if (MA.getState("/TITLE")) flags |= GWidget.TITLE;
    return flags;
  }

}
