package nxm.sys.libg;

import nxm.sys.inc.MessageHandler;
import nxm.sys.lib.Message;
import nxm.sys.lib.Midas;
import nxm.sys.lib.Parser;
import nxm.sys.lib.Shell;
import nxm.sys.lib.Table;

/** A class to implement a graphical file selection widget.

  @author Jeff Schoen
*/
public class GFiles extends GDialog {

  Midas   M;          // Midas Context
  String  raux;       // list of Auxes to display files from
  GPrompt nfilt;      // file listing filter (e.g. *.tmp|prm)
  GPrompt fname;      // current filename widget
  GList   nlist;      // files listing widget
  GMenu   amenu;      // Aux list menu (see auxList and auxMask)
  GMenu   omenu;      // filename Options menu (see optList and optMask)
  String  auxList;    // list of all configured Auxes
  String  selectName; // current selected file in files listing (nlist)
  int     auxMask;    // Aux list mask to use with Aux list menu
  int     optMask;    // filename options mask (see optList and omenu)

  /** File chooser AUX/filename options that can be chosen (exclusive except for 'Ext'). */
  public static final String optList = "Path,AuxID,Qual,Ext,SingleAux,HideOpts";
  /** include full path in filename (eg. /path/to/dat/aux/filename) */
  public static final int O_PATH =  0x1000;
  /** include &lt;AUX ID&gt;/filename (e.g. DAT/filename) */
  public static final int O_APID =  0x2000;
  /** include filename with AUX as a qualifier (e.g. filename{AUX=dat} */
  public static final int O_QUAL =  0x4000;
  /** include filename extension (works with any of the above options) */
  public static final int O_EXT  =  0x8000;
  /** Only allow selecting a single AUX  */
  public static final int SINGLE_AUX = 0x10000;  // since 3.3.2 - Bug 2729
  /** Hide the Options menu so user cannot change it */
  public static final int HIDE_OPTS  = 0x20000; // since 3.3.2 - Bug 2729

  /** This widgets flags. */
  public static final String flagsList = GPrompt.flagsList+",,"+optList;

  /** Instantiate a new List, initialize the parameters, and open the graphics panel.
     @param parent the parent object
     @param name   the name of this List
     @param seed   the default file name
     @param filt   the filename filter
     @param raux   the read aux list
     @param M      the Midas context reference
     @param aw     the width in characters
     @param ah     the height in lines
     @param flags  the widget flags (to set the filename options (see {@link #optList}),
                   and use {@link Parser#mask(String,String,int)}.
                   e.x. <code>Parser.mask(GFiles.flagsList,"PATH|EXT",0)</code>
     @param mh the MessageHandler
   */
  public GFiles (Object parent, String name, String seed, String filt, String raux, Midas M,
        int aw, int ah, int flags, MessageHandler mh) {
    super(null,name,-(aw==0?50:aw),-(ah==0?15:ah), (((flags&HIDE_OPTS)!=0)?"":"Cfg,")+"Apply,Submit,Cancel","Cfg,Apply",flags,mh);
    // Since NXM 3.8.1 This is used to increment the amount of popups contained inside of MPLot.
    // Usually done in the super, done here because we send in null parent
    if( parent instanceof MPlot) ((MPlot)parent).popupCount++;
    open (name, seed, filt, raux, M);
    addTo(parent);
  }

  /** Forms the GFile
   *  @param name the name of this List
   *  @param seed the default file name
   *  @param filt the filename filter
   *  @param raux the read aux list
   *  @param M    the Midas context reference
   */
  public void open (String name, String seed, String filt, String raux, Midas M) {
    this.M = M;
    if (seed==null) seed = "";
    if (filt==null) filt = "*.tmp|prm";
    if (raux==null) raux = M.results.getString("AUX.WRITE");
    this.raux = raux;
    formAuxList();
    // fill out dialog
    int sflags = GWidget.VBOXMO;
    int oflags = sflags|GMenu.TLEFT|GMenu.ONEROW|GMenu.CHKBOX|GMenu.TOGGLE;
    int aflags = sflags|GMenu.CHOICE;
    if (!is(SINGLE_AUX)) aflags |= GMenu.TOGGLELIST;  // since 3.3.2 - Bug 2729

    fname = new GPrompt(this,"File ",seed,sflags,this);
    nfilt = new GPrompt(this,"Filter",filt,sflags,this);
    amenu = new GMenu  (this,"AuxList",auxList,auxMask,aflags,this);
    nlist = new GList  (this,"Names","FileList",40,10,GList.COLS,this);
    formNameList();
  }

  private void formAuxList() {
    auxList = null;
    auxMask = 0;
    int auxIndex = 0;
    String rauxm = "|"+raux+"|";
    String nrauxm = "|READ|WRITE|HOMEPATH|";
    Table t = M.results.getTable("AUX");
    for (Table.Iterator ti=t.iterator(); ti.getNext(); ) {
      String aux = ti.key;
      String auxm = "|"+aux+"|";
      if (nrauxm.indexOf(auxm)>=0) continue;
      if (rauxm.indexOf(auxm)>=0) auxMask |= (0x1<<auxIndex);
      if (auxList==null) auxList=aux;
      else auxList += ","+aux;
      auxIndex++;
    }
    if (amenu != null) {
      amenu.setItems(auxList);
      amenu.setValue(auxMask);
    }
  }

  /** Forms the list of of files */
  public void formNameList() {
    nlist.removeItems();
    String filter = (String)nfilt.getValue();
    int ip = filter.indexOf('.');
    String root = filter, ext = "tmp|prm";
    if (ip>=0) {
      root = filter.substring(0,ip);
      ext  = filter.substring(ip+1);
    }
    String toAux = "";                                  // BUG 2022: make aux list sticky
    for (int j=0; j<amenu.getItemCount(); j++) {
      if (((auxMask>>j)&0x1) == 0) continue;
      String aux = amenu.getItem(j+1);
      if (toAux.equals("")) toAux = aux;
      else toAux = toAux+"|"+aux;
      String path = M.io.getAuxPath(aux);
      String uext = aux.equals("RAM")? "" : ext;
      String[] files = M.io.listFiles(path,root,uext);
      if (files==null) continue;
      for (int i=0; i<files.length; i++) nlist.addItem( aux+"/"+files[i] );
    }
    raux = toAux;
  }

  @Override
  public Object getValue() {
    return fname.getValue();
  }

  @Override
  public int processMessage (Message msg) {
    if (msg.name.equals("DIALOG")) {
      String action = (String)msg.data;
      if (action.equals("SUBMIT") || action.equals("APPLY")) {
        // check to add write (output) aux added in 3.3.2 for Bug 2729
        String val = (is(O_QUAL)||is(SINGLE_AUX)) ? addWriteAux() : getValueString();
        sendWidgetMessage (label,0,val);
      }
      else if (action.equals("VIEW")) {
        String name = parseName(O_PATH);
        if (name!=null && name.length()>0) Shell.runCommand(M,"VIEW/BG,"+name);
      }
      else if (action.equals("CFG")) {
        new GMenu (parent,"GFiles.cfg",optList,(flags>>8),GMenu.TOGGLE,this);
      }
      if (!is(PERM) && isCloseButton(action)) close();
    }
    else if (msg.name.equals("GFILES.CFG")) {
      setOptions(msg.info);
    }
    else if (msg.name.equals("AUXLIST")) {
      // for single selection, convert to MASK value (since 3.3.2 - Bug 2729)
      if (is(SINGLE_AUX)) auxMask = Parser.mask(auxList, Parser.get(this.auxList,msg.info), 0);
      else auxMask = msg.info;
      formNameList();
    }
    else if (msg.name.equals("FILTER")) {
      formNameList();
    }
    else if (msg.name.equals("NAMES")) {
      selectName = (String)msg.data;
      parseName();
    }
    return 0;
  }

  private void setOptions (int mask) {
    flags = ((mask&0xF)<<8) | (flags&0xF0FF);
    // enforce exclusive modes
    if (is(O_PATH)) flags &= ~(O_QUAL|O_APID);
    if (is(O_APID)) flags &= ~(O_PATH|O_QUAL);
    if (is(O_QUAL)) flags &= ~(O_PATH|O_APID);
    if (selectName!=null) parseName();
  }

  private void parseName() {
    fname.setValue(parseName(flags));
  }

  private String parseName (int mask) {
    String pname = selectName;
    int j = pname.indexOf("/");
    String aux = pname.substring(0,j);
    String name = pname.substring(j+1);
    int k = name.indexOf(".");
    if ((mask&O_EXT)==0 && k>0) name = name.substring(0,k);
    pname = name;
    if ((mask&O_QUAL)!=0) pname = name+"{AUX="+aux+"}";
    if ((mask&O_APID)!=0) pname = aux+"/"+name;
    if ((mask&O_PATH)!=0) pname = M.io.getAuxPath(aux)+name;
    return pname;
  }

  /** Add the AUX=<aux> qualifier to the end of the file name, if not already there   */
  private String addWriteAux () {  // added in 3.3.2 for Bug 2729
    String base = getValueString();
    if (base.contains("AUX=")) return base;
    else                       return base+"{AUX="+raux+"}";
  }

  /** Get the value of the listing filter
      @return The value of the listing filter
      @since NeXtMidas 2.7.3
   */
  public String getFilter () { return ""+nfilt.getValue(); }

  /** Get the list of aux's to display files from
      @return The list of aux's to display files from
      @since NeXtMidas 2.7.3
   */
  public String getAuxList () { return raux; }
}
