/*Note: still incomplete.  Needs graphical view of the tree implemented. */

import java.awt.*;
import java.awt.event.*;

/**
 * An applet to sort and store DictionaryEntries using a BinarySearchTree
 *
 * @author Zach Tomaszewski
 * @version 24 November
 */
public class BSTApplet extends java.applet.Applet implements ActionListener {

  private BinarySearchTree bst = new BinarySearchTree();
  private TextArea displayArea;
  private Panel displayPanel;
  private Button add;
  private Button remove;
  private Button clearList;
  private Button display;
  private Button statusOK;
  private TextField statusLine;
  private TextField wordEntry;
  private TextField defEntry;

  private final static Color BACKGROUND = new Color(00,00,65);
  private final static Color FOREGROUND = Color.white;
  

  /**
   * Initializes the applet by creating the GUI.
   */
  public void init() {
    this.setLayout(new BorderLayout());
    this.add(this.getGUI(), BorderLayout.CENTER);  
    this.setStatusLine(null);
  }
  

  /**
   * Returns a panel containing the graphical interface
   * components for this applet.  Includes a brief intro
   * message explaining the use of the applet.
   */
  protected Panel getGUI() {
    
    Panel gui = new Panel(new BorderLayout());
    Panel north = new Panel(new FlowLayout(FlowLayout.LEFT));
    
    String welcome = "Dictionary/BST Applet.\n";
    welcome = welcome + "\nYou can Add and Remove dictionary entries below, ";
    welcome = welcome + "and you will see them displayed here.\n";
    welcome = welcome + "\nDuplicate entries or the empty string (\"\") are " +
                        "not supported.  You need to enter only the word to " +
                        "remove an entry from the list.";
    displayArea = new TextArea(welcome, 10, 40, TextArea.SCROLLBARS_VERTICAL_ONLY);
    displayArea.setEditable(false);
    displayArea.setBackground(FOREGROUND);
    
    displayPanel = new Panel(new FlowLayout());
    displayPanel.add(displayArea);
    north.add(displayPanel);
    
    Panel northEast = new Panel(new GridLayout(2, 1));   
    display = new Button("Display Tree");
    display.setActionCommand("display");
    display.addActionListener(this);
    display.setEnabled(false);

    clearList = new Button("Clear List");
    clearList.setActionCommand("clearList");
    clearList.addActionListener(this);
    clearList.setEnabled(false);
    
    northEast.add(display);
    northEast.add(clearList);
    north.add(northEast);
    gui.add(north, BorderLayout.NORTH);
    
    Panel center = new Panel(new FlowLayout(FlowLayout.LEFT));
    Panel centerGrid = new Panel(new GridLayout(3,1));

    Panel row1 = new Panel(new FlowLayout(FlowLayout.RIGHT));
    Label word = new Label("Word: ", Label.RIGHT);
    word.setForeground(FOREGROUND);
    row1.add(word);
    wordEntry = new TextField("", 16);
    wordEntry.setBackground(Color.white);
    row1.add(wordEntry);
    centerGrid.add(row1);

    Panel row2 = new Panel(new FlowLayout(FlowLayout.RIGHT));
    Label def = new Label("Definition: ", Label.RIGHT);
    def.setForeground(FOREGROUND);
    row2.add(def);
    defEntry = new TextField("", 16);
    defEntry.setBackground(Color.white);
    row2.add(defEntry);
    centerGrid.add(row2);

    Panel row3 = new Panel(new FlowLayout(FlowLayout.CENTER));
    add = new Button("Add");
    add.setActionCommand("add");
    add.addActionListener(this);
    row3.add(add);

    remove = new Button("Remove");
    remove.setActionCommand("remove");
    remove.addActionListener(this);
    remove.setEnabled(false);
    row3.add(remove);
    centerGrid.add(row3);
    center.add(centerGrid);
    gui.add(center, BorderLayout.CENTER);
  
    GridBagLayout southGridBag = new GridBagLayout();
    GridBagConstraints constr = new GridBagConstraints();
    Panel south = new Panel(southGridBag);
        
    statusLine = new TextField("");
    statusLine.setEnabled(false);
    constr.anchor = constr.WEST;
    constr.fill = constr.HORIZONTAL;
    constr.weightx = 1;
    southGridBag.setConstraints(statusLine, constr);
    south.add(statusLine);
    
    constr = new GridBagConstraints();
    statusOK = new Button("OK");
    statusOK.setActionCommand("statusOK");
    statusOK.addActionListener(this);
    southGridBag.setConstraints(statusOK, constr);
    south.add(statusOK);
    gui.add(south, BorderLayout.SOUTH);
  
    gui.setBackground(BACKGROUND);  
  
    return gui;
  }
  
  
  /* action listener's method; handles all buttons in the applet;
     docs inherited from ActionListener*/
  public void actionPerformed (ActionEvent ae) {
    String command = ae.getActionCommand();
    
    if (command.equals("statusOK")) { //cleaning up after an error
      this.setStatusLine(null);
    }

    if (command.equals("add") ) {
      String word = wordEntry.getText();
      String def = defEntry.getText();
      try {
        if (!word.equals("")) {
          bst.insert(new DictionaryEntry(word,def));
          this.updateDisplay();
          this.updateButtonStates();
        }else {
          this.setStatusLine("Error: can't add empty string.");
        }
      }catch (BSTException bst) {
        this.setStatusLine("Error: could not add your entry. "+
                           "Perhaps it is already in the list.");
      }
    }    

    if (command.equals("remove") ) {
      String word = wordEntry.getText();
      try {  
        bst.remove(new DictionaryEntry(word, ""));
        this.updateDisplay();
        this.updateButtonStates();          
      }catch (BSTException bst) {
        this.setStatusLine("Error: could not find/remove your entry.");
      }
    }    

    if (command.equals("clearList") ) {
      bst.removeAll();
      this.updateDisplay();
      this.updateButtonStates();          
    }    

    if (command.equals("display") ) {
      if (display.getLabel().equals("Display Tree")) { //switch view
        display.setLabel("Display List");
        this.updateDisplay();
      }else {
        display.setLabel("Display Tree");
        this.updateDisplay();
      }
    }
  }
  
  
  /**
   * Displays the given message in the status line, reveals statusOK button,
   * and disables all other controls.  
   * If the given status is null, will reenable all controls 
   * (using updateButtonStates) and hide statusOK.
   *
   * @param status   the message to display, or else null
   */
  protected void setStatusLine(String status) {
    if (status == null) {  //no error message to display
      statusLine.setText("");
      statusLine.setBackground(BACKGROUND); //blur out
      statusOK.setVisible(false);
      wordEntry.setBackground(FOREGROUND); //can be seen
      wordEntry.setEnabled(true); //ready for input
      defEntry.setBackground(FOREGROUND); //can be seen
      defEntry.setEnabled(true); //ready for input
      this.updateButtonStates(); //turn everything back on
    }else {
      statusLine.setText(status);
      statusLine.setBackground(FOREGROUND); //blur in
      wordEntry.setBackground(BACKGROUND);  //blur out
      defEntry.setBackground(BACKGROUND);  //blur out
      statusOK.setVisible(true);
      display.setEnabled(false);
      clearList.setEnabled(false);
      remove.setEnabled(false);
      add.setEnabled(false);
    }
    //to get statusOK to actually show up
    Container panel = statusOK.getParent();
    panel.validate();
  }


  /**
   * Updates all control buttons to their appropriate "enabled" state, based on the
   * contents of the list.  If there are no contents of the list, all buttons
   * but Add are disabled.  Otherwise, all are enabled.
   * Does not affect the statusOK button one way or the other.
   */
  protected void updateButtonStates () {

    boolean canRemove = !bst.isEmpty();

    //FIX: display disabled until view change is written
    display.setEnabled(false);  //canRemove;
    clearList.setEnabled(canRemove);
    remove.setEnabled(canRemove);
    add.setEnabled(true);    
  }


  /**
   * Refreshes the display of the list to display area 
   * and clears the input text fields.
   */
  protected void updateDisplay() {
    displayArea.setText(bst.toString());
    wordEntry.setText("");
    defEntry.setText("");
  }

}//end class
