package nxm.sys.libg;

import java.awt.Graphics;

import nxm.sys.inc.MessageHandler;
import nxm.sys.inc.ProvisionalUseOnly;
import nxm.sys.lib.Convert;
import nxm.sys.lib.Message;
import nxm.sys.lib.Parser;
import nxm.sys.lib.Shell;

/**
  A class to implement a graphical label widget.

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

  private int pw, active;

  /** List of valid states for this label. */
  public static final String activeList =
    "Collapsed,AlwaysClosed,Hidden,Closed,Open,AlwaysOpen,Collapsable,Toggle";

  /** Offset into the list of valid states for this label. */
  private static final int activeOffset = -4;

  /** GLabel state collapsed */
  public static final int aCOLLAPSED=-3;
  /** GLabel state always closed */
  public static final int aALWAYSCLOSED=-2;
  /** GLabel state hidden */
  public static final int aHIDDEN=-1;
  /** GLabel state closed */
  public static final int aCLOSED=0;
  /** GLabel state open */
  public static final int aOPEN=1;
  /** GLabel state always open */
  public static final int aALWAYSOPEN=2;
  /** GLabel state collapsable */
  public static final int aCOLLAPSABLE=3;
  /** GLabel state toggle */
  public static final int aTOGGLE=4;

  /** The last gwidget added to a widget group in a panel. */
  public GWidget lastWidget=null;

  /**
     Construct a new GLabel and initialize parameters
     @param parent this label's parent
     @param name the label name
     @param active the state of this label
     @param flags the widget flags
     @param mh the Message Handler
  */
  public GLabel (Object parent, String name, int active, int flags, MessageHandler mh) {
    super("GLabel",parent,name,flags,mh);
    open (name, active);
    addTo (parent);
  }

  /**
     Construct a new GLabel and initialize parameters
     @param parent this label's parent
     @param name the label name
     @param active the state of this label
     @param flags the widget flags
     @param mh the Message Handler
  */
  public GLabel (Object parent, String name, String active, int flags, MessageHandler mh) {
    super("GLabel",parent,name,flags,mh);
    open (name, getActiveID(active));
    addTo (parent);
  }

  /**
     Opens the graphics window for this label and sets the state
     @param name the label name
     @param active the state of this label
   */
  public void open (String name, int active) {
    super.open();
    this.active = active;
    pw = stringWidth(title);
    setup();
  }

  public void setup() {
    bw = is(INLINE)? 0:DEFBW;
    pos.w = bw+pw+bw;
    if (fixWidth>pos.w) pos.w=fixWidth;
    pos.h = bw+th+ta+bw-compression;
    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 (g==null) return;
    int bf=is(INLINE)? SB_SHADE:SB_DEF;
    boolean open = (active>0);
    shadowbox(g,0,0,pos.w,pos.h,bf); // Updated to use g in 3.9.0 for NXM-3213
    int tx = pos.w/2 - pw/2;
    int ty = pos.h/2 + ta/2;
    setColor(g, open? theme.cwfh : theme.cwfh.darker()); // Updated to use g in 3.9.0 for NXM-3213
    g.drawString(title,tx,ty);
    setColor(g,theme.cfg); // Updated to use g in 3.9.0 for NXM-3213
    if (!isFixed() && isEnabled()) {  // if disabled, do not draw arrow (Bug 2323)
      int aw=tw*2/3, yo=open?aw:-aw;
      if (pos.w > pw+10*aw) {
        shadowarrow(g,pos.w-3*aw,pos.h/2+yo,aw,open?'u':'d');  // Updated to use g in 3.9.0 for NXM-3213
      }
    }
  }

  public String getLegend() {
    return isFixed()? "(LM=Fixed)":"(LM=Open/Close)";
  }

  /** Is fixed (always open or always closed)
   *  @return true if fixed otherwise false */
  public boolean isFixed() {
    return (active==aALWAYSOPEN) || (active==aALWAYSCLOSED);
  }

  public void setTitle (String title) {
    pw = stringWidth(title);
    super.setTitle(title);
  }

  /** Process widget event messages locally.
   *  @return 1 after processing BUTTON messages, -1 otherwise
   */
  @Override
  public int processEventMessage (String name, int info, Object data) {
    if (name.equals("POINTER")) formatReadOut(info);
    if (name.equals("BUTTON")) {
           if (info==1) setActive(toggledActive(),1);
      else if (info==2) configure();
      else if (info==3) new GMenu (parent,"GLabel.active",activeList,active-activeOffset,0,this);
      formatReadOut(info);
      return 1;
    }
    else return -1;
  }

  @Override
  public int processMessage (Message msg) {
    if (msg.name.equals("GLABEL.CFG")) {
      flags = msg.info;
      setup();
      refresh();
    }
    else if (msg.name.equals("GLABEL.ACTIVE")) {
      setActive(msg.info+activeOffset);
    }
    return 1;
  }

  @Override
  public Object getValue () {
    return Parser.get(activeList,active-activeOffset);  // the .get needs to subtract offset since the .set adds it
  }

  @Override
  public void setValue (String value) {
    setActive( getActiveID(value), 0);
  }

  @Override
  public void setAction (String value) {
    setActionType(); // check whether the action was triggered by a mouse click
    setActive( getActiveID(value), 1);
  }

  /**
     Sets the active state of this label, and sends a widget message.
     This is the same as <CODE>setActive(value,1)</CODE>.
     @param value the new state
   */
  public void setActive (int value) { setActive(value,1); }

  /**
     Sets the active state of this label, and sends a widget message
     <CODE>if flag &gt; 0</CODE>.
     @param value the new state
     @param flag widget message flag
   */
  public void setActive (int value, int flag) {
    if (value==active) return;
    if (value==aTOGGLE) value = toggledActive();
    active=value;
    refresh();
    if (flag>0) sendWidgetMessage (label,active,getValue());
    layout(); // panel layout depends on GLabel state
  }

  private int toggledActive() {
    int tactive=active;
         if (active==aOPEN) tactive=aCLOSED;
    else if (active==aCLOSED) tactive=aOPEN;
    else if (active==aCOLLAPSED) tactive=aOPEN;
    else if (active==aCOLLAPSABLE) tactive=aCOLLAPSED;
    return tactive;
  }

  /**
     Returns the current state of this label
     @return the active state
   */
  public int getActive() { return active; }

  @Override
  public Object setKey (String key, Object value) {
    if (key.equals("VALUE")) setValue(Convert.o2s(value));
    else if (key.equals("ACTIVE")) setActive(Convert.o2l(value));
    else value = super.setKey(key,value);
    return value;
  }

  @Override
  public Object getKey (String key) {
    Object value;
    if (key.equals("VALUE")) value = getValue();
    else if (key.equals("ACTIVE")) value = Convert.l2o(active);
    else value = super.getKey(key);
    return value;
  }

  @Override
  public String toString() {
    return toList((String)getValue(),activeList);
  }

  /** Gets the ID for the active status name.
      This takes in the standard names and the old GControl names ("Hide,Off,On").
      @param value The name of the status.
      @return The id for the status.
   */
  private int getActiveID (String value) {
    int id = Parser.find(activeList,value,active,activeOffset);
    if (id <= activeOffset) {
      Shell.warning("GCONTROL LABEL: Unknown active state '"+value+"' using default.");
      id = aOPEN;
    }
    return id;
  }
}
