package nxm.sys.libg;

import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.util.Vector;

import nxm.sys.inc.Installation.ApplyBugFix;
import nxm.sys.inc.MessageHandler;
import nxm.sys.inc.ProvisionalUseOnly;
import nxm.sys.lib.Convert;
import nxm.sys.lib.Message;

/**
  A class to implement a graphical alert with confirmation menu.

  @author Jeff Schoen
*/
public class GAlert extends GWidget {

  private Vector<Object> itemv = new Vector<>(8,8);
  private int pw, items, maxwidth=0;
  private int defitem=0;
  private String list,prompt;
  private MBox bp,bt,bc;
  private ActionListener    timeoutHandler; // Handles timeouts
  private javax.swing.Timer timeoutTimer;   // Calls timeoutHandler as needed.

  /** list of available flags */
  public final static String flagsList = GWidget.flagsList+",List";
  /** LIST flag */
  public final int LIST = 0x100;

  /**
     Construct a new GAlert and initialize parameters.
     @param parent the parent object of this GAlert
     @param name   the window name
     @param text   the text to display
     @param list   the button list
     @param item   the default item
     @param flags  the widget flags
     @param mh     the Message Handler
  */
  public GAlert (Object parent, String name, String text, String list, int item,
                int flags, MessageHandler mh) {
    this(parent, name, text, list, item, flags, mh, -1);
  }

  /**
     Construct a new GAlert and initialize parameters. This instance can be set
     to automatically close after a set number of seconds.
     @param parent  the parent object of this GAlert
     @param name    the window name
     @param text    the text to display
     @param list    the button list
     @param item    the default item
     @param flags   the widget flags
     @param mh      the Message Handler
     @param timeout the number os seconds to wait until automatically closing
                    the GAlert (disabled is less than or equal to zero).
   */
  public GAlert (Object parent, String name, String text, String list, int item,
                 int flags, MessageHandler mh, int timeout) {
    super("GAlert",parent,name,flags,mh);
    open (name, text, list, item);
    addTo (parent);

    /* Added per DR 505441-1 */
    if (timeout > 0) {
      timeoutHandler = (e) -> {  // Updated in 3.9.0 for NXM-3213
        close();
        if (timeoutTimer != null) {
          timeoutTimer.removeActionListener(timeoutHandler);
          timeoutTimer = null;
        }
      };
      timeoutTimer = new javax.swing.Timer((timeout * 1000), timeoutHandler);
      timeoutTimer.start();
    }
  }

  /**
     Opens the graphics window with the given name and displays the
     given text. Displays a group of buttons as defined in list with
     the default item provided.
     @param name the window name
     @param text the text to display
     @param list the list of button names
     @param item the default item
   */
  public void open (String name, String text, String list, int item) {
    super.open();
    int i,j,k,w;
    prompt = text;
    this.list = list;
    defitem = item;
    itemv.addElement(title);
    for (i=j=0,k=list.length(); i<k; ) {
      j = list.indexOf(',',i);
      if (j == -1) j = k;
      String tmpstr = list.substring(i,j);
      itemv.addElement(tmpstr);
      w = stringWidth(tmpstr)+tw;
      if (is(LIST)) maxwidth += w;
      else if (w>maxwidth) maxwidth = w;
      i = j+1;
    }
    items = itemv.size()-1;
    pw = stringWidth(prompt);
    setup();
  }

  @Override
  public void setup () {
    int h = th+ta;
    if (is(INLINE)) bw=0; else bw=DEFBW;
    bp = new MBox (tw/2, bw, pw, h);
    bc = new MBox (bp.x+bp.w, bw, th+tw, h);
    bt = new MBox (bc.x+bc.w, bw/2, maxwidth, h+bw);
    pos.w = bt.x+bt.w+bw;
    pos.h = bw+h+bw;
    if (is(INLINE)) { bt.h=pos.h; bt.y=0; }
    layout();
  }

  /**
   *  @deprecated Since NeXtMidas 3.9.0 to avoid graphical timing issues
   *  use {@link #paintComponent(Graphics)}
   */
  @Deprecated
  public void paint () {
    refresh();
  }

  @ProvisionalUseOnly("Treat this as protected and should only be called by subclass paintComponent methods")
  @Override
  public void paintComponent (Graphics g) {
    super.paintComponent(g);
    if (useSwing || ApplyBugFix.GCONTROL_WTHEME_OVERRIDES_THEME) { // since 3.1.1 (fill bg default) for BUG 2543 and BUG 2018)
      g.setColor(theme.cwbg);
      g.fillRect(0,0,pos.w,pos.h);
    }
    // TODO: Ask Jeff, why does draw shadowbox(...,SB_ALERT) not fill background?, so we don't have to put above workaround for BUG 2018
    shadowbox(g,0,0,pos.w,pos.h,SB_ALERT); // updated to use g in 3.9.0 for NXM-3213
    int aw = tw*2/3;
    int ty = pos.h/2 + th/3;
    g.setColor(theme.getWidgetTitle());
    g.drawString(prompt,bp.x,ty);
    shadowarrow(g, bc.x+bc.w/2, bc.y+bc.h/2, aw, 'B'); // updated to use g in 3.9.0 for NXM-3213
    for (int i=1,j=0; i<=items; i++) {
      String value = (String)itemv.elementAt(i);
      g.setColor((i==defitem&&items>1)?theme.cwfh:theme.cwfg);  // added the 'items>1' in 3.1.1 to retain color if only one item
      if ((i==defitem) || is(LIST)) g.drawString(value,bt.x+j,ty);
      if (is(LIST)) j += (value.length()+1)*tw;
    }
  }

  @Override
  public int processEventMessage (String name, int info, Object data) {
    if (!name.equals("BUTTON")) return -1;
    if (info==1 && px > bt.x) {
      if (!is(LIST) || items<=1) select (defitem,1);
      else for (int i=1,j=bt.x; i<=items; i++) {
        String value = (String)itemv.elementAt(i);
        j += (value.length()+1)*tw;
        if (px<j) { select(i,1); break; }
      }
    }
    else if (info==2 && px > bt.x) {
       new GMenu (parent,"",list,defitem,0,this);
    }
    else if (px >= bc.x && px <= bc.x+bc.w) {
      int item = defitem;
      if (info==1) item = Math.min(defitem+1,items);
      if (info==3) item = Math.max(defitem-1,1);
      if (item!=defitem) select(item,0);
    }
    return 1;
  }

  @Override
  public int processMessage (Message msg) {
    if (msg.name.isEmpty()) {
      select(msg.info,1);
      return 1;
    }
    return super.processMessage(msg);
  }

  private void select (int item, int mode) {
    defitem = item;
    String data = ((String)itemv.elementAt(item)).toUpperCase();
    if (mode==1) { sendWidgetMessage (label,item,data); close(); }
    else refresh();
  }

  /**
     Sets the text of the prompt displayed by this GAlert
     @param text The new prompt text
   */
  public void setText (String text) {
    prompt = text;
    pw = stringWidth(prompt);
    setup();
    panel.setSize(pos.w,pos.h);
    refresh();
  }

  /**
     Sets the value of this GAlert by String value
     @param text the text value
     @param button if <CODE>button &gt; 0</CODE>, a widget message is sent
   */
  public void setValue (String text, int button) {
    for (int i=1; i<=items; i++) {
      String value = ((String)itemv.elementAt(i)).toUpperCase();
      if (value.startsWith(text)) {
        value = ((String)itemv.elementAt(i)).toUpperCase();
        if (button>0) sendWidgetMessage (label,i,value);
        setValue(i);
        return;
      }
    }
  }

  /**
     Sets the value of this GAlert by item number
     @param item the item number
   */
  public void setValue (int item) {
    defitem = item;
    refresh();
  }

  public Object setKey (String key, Object value) {
         if (key.equals("ACTION")) setValue((String)value,1);
    else if (key.equals("VALUE")) setValue((String)value,0);
    else if (key.equals("TEXT")) setText((String)value);
    else if (key.equals("ITEM")) setValue(Convert.o2l(value));
    else value = super.setKey(key,value);
    return value;
  }

  public Object getKey (String key) {
    Object value;
         if (key.equals("VALUE")) value = itemv.elementAt(defitem);
    else if (key.equals("TEXT")) value = prompt;
    else if (key.equals("ITEM")) value = Convert.l2o(defitem);
    else value = super.getKey(key);
    return value;
  }

}
