package org.jcon.ui;

import org.jcon.ui.easylayout.EasyLayout;
import org.jcon.ui.WindowLib;
import org.jcon.util.GenLib;
//import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JPasswordField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

/**
 * This reusable class provides a window with "fields" and
 * buttons. Each field has a label and a TextField. The
 * buttons are displayed in a row on the bottom. The
 * window may be a Frame or Dialog.
 * <P>
 * A typical use of this class would be collecting a small,
 * simple amount of data, such as a logon or wizard.
 * <P>
 * To use this class: <PRE>
 * - Configure it with the set and add methods.
 * - Call start() to reveal the window.
 * - Call getFieldText() to get a field's text in the
 *      listener's actionPerformed() behavior.
 * - Call close() when done. </PRE>
 * <P>
 * See main() for a use example.
 * Test: java org.jcon.core.ui.FieldWindow
 *
 * @author Jack Harich
 */
public class FieldWindow extends PrimeWindow
    implements java.io.Serializable, DocumentListener {

//---------- Private Fields ------------------------------
private Vector  fields = new Vector();
private Vector  buttons = new Vector();

//---------- Initialization ------------------------------
/**
 * Provides a simple unit test and coding example.
 *
 * @param String args[] - This are ignored.
 */
public static void main(String args[]) {
    FieldWindow testWindow = new FieldWindow();
    testWindow.setTitle("Logon");
    testWindow.setAutoDispose(true);

    testWindow.addTextField("User Name", "UserName", 15);
    testWindow.addTextField("Password", "Password", 15);

    testWindow.addButton("Okay", "LogonOkay");
    testWindow.addButton("Cancel", "LogonCancel");

    testWindow.start();
}
//---------- DocumentListener Implementation -----------------
public void textValueChanged(TextEvent evt) {
    // Called only if auto upper case
    // See df.edit.control.TextFieldControl for DUPE CODE
    // Must save and restore caret position for usability
    JTextField textField = (JTextField)evt.getSource();
    String currentText = textField.getText();
    Field field = getField(textField.getName());
    
    if (! currentText.equals(field.previousText)) {
        int caretPosition = textField.getCaretPosition();
        // setText() will trigger TextEvent <-----<<<
        textField.setText(textField.getText().toUpperCase());
        textField.setCaretPosition(caretPosition);
        field.previousText = currentText;     
    }
}
public void changedUpdate(DocumentEvent evt) {
    // Called only if auto upper case
    // See df.edit.control.TextFieldControl for DUPE CODE
    // Must save and restore caret position for usability

    //TextField textField = (TextField)evt.getSource();
    JTextField textField = (JTextField)evt.getDocument();
    String currentText = textField.getText();
    Field field = getField(textField.getName());
    
    if (! currentText.equals(field.previousText)) {
        int caretPosition = textField.getCaretPosition();
        // setText() will trigger TextEvent <-----<<<
        textField.setText(textField.getText().toUpperCase());
        textField.setCaretPosition(caretPosition);
        field.previousText = currentText;     
    }
}
public void insertUpdate(DocumentEvent evt) {}
public void removeUpdate(DocumentEvent evt) {}
//---------- Public Methods ------------------------------
/**
 * Adds a named, labeled TextField using the arguments.
 *
 * @param String text - The field's label.
 * @param String fieldName - The field's name, useful to
 *   later get the field's value.
 *   If fieldName is "Password" then the field will echo "*".
 * @param int columns - The number of columns to use for the TextField.
 */
public void addTextField(String text, String fieldName,
        int columns) {
    Field field = new Field(columns, fieldName);
    field.setName(fieldName);
    field.label = text;
    if (fieldName.equals("Password")) 
    	((JPasswordField)field.textField).setEchoChar('*');

    fields.addElement(field);
}
/*
 * Sets the fieldName's text field to automatic uppercase.
 * The field must have already been added.
 */
public void setTextFieldUpperCase(String fieldName) {
    Field field = getField(fieldName);
    if (field == null) {
         GenLib.error("FieldWindow.setTextFieldUpperCase()",
             "FieldName '" + fieldName + "' not found, must be added first.");  
    } else {
         field.setUpperCase(true, this);   
    }    
}    
/**
 * Adds a Button to the row of buttons in the window.
 * There is no minimum or maximum enforced, but we expect
 * at least one and no more than about four.
 *
 * @param String text - The button's label.
 * @param String command - The button's action command.
 */
public void addButton(String text, String command) {
    JButton button = new JButton(text);
    button.setActionCommand(command);
    buttons.addElement(button);
}
/**
 * Removes all buttons. Useful for window reuse.
 */
/** public void removeAllButtons() {
    buttons.removeAllElements();
} */
/**
 * This starts the window. It will initialize itself using
 * the addTextField() and other confguration data,
 * and then reveal the window. The window is centered.
 */
public void start() {

    JPanel mainPanel = getMainPanel();
    addFields(mainPanel);
    initButtonBar(mainPanel);
    initWindow(); // Must be after components added
    packWindow();
    centerWindow();
    setVisible(true);
}
/**
 * This returns the text in the named field. If not found
 * then throws an IllegalArgumentException.
 *
 * @param String fieldName - The name of the field.
 * @param String text - The text to display in the field.
 * @return String - The text in the named field.
 */
public void setFieldText(String fieldName, String text) {
    JTextField field = getTextField(fieldName);
    field.setText(text);
}
/**
 * This returns the text in the named field. If not found
 * then throws an IllegalArgumentException.
 *
 * @param String fieldName - The name of the field.
 * @return String - The text in the named field.
 */
public String getFieldText(String fieldName) {
    JTextField field = getTextField(fieldName);
    if (field != null) {
        return field.getText();
    } else {
        throw new IllegalArgumentException("fieldName '" +
            fieldName + "' not found.");
    }
}
/**
* Useful for returning the focus to the first field.
*/
public void requestFocusFirstField() {
    if (fields.isEmpty()) return;
    
    Field field = (Field)fields.firstElement();
    myWindow.requestFocus();
    field.textField.requestFocus();
}    
//---------- Private Methods -----------------------------
// Returns null if not found
private JTextField getTextField(String fieldName) {
    Field field = getField(fieldName);
    if (field == null) {
        return null;
    } else {
        return field.textField;
    }
}
// Returns null if not found
private Field getField(String fieldName) {
    for (int i = 0; i < fields.size(); i++) {
        Field field = (Field)fields.elementAt(i);
        if (field.getName().equals(fieldName)) return field;
    }
    return null;
}
private void initButtonBar(JPanel mainPanel) {
    if (getActionListener() == null) setActionListener(this);
    // Add buttons
    JPanel buttonBar = new JPanel();
    mainPanel.add("South", buttonBar);
    for (int i = 0; i < buttons.size(); i++) {
        JButton button = (JButton)buttons.elementAt(i);
        button.addActionListener(getActionListener());
        buttonBar.add(button);
    }
}
private void addFields(JPanel mainPanel) {
    // Prepare styles
    EasyLayout layout = new EasyLayout();
    layout.setAlignment("Left");

    layout.setInsets(5, 5, 5, 5);
    layout.setInsetRight(0);
    layout.storeCurrentStyle("Column1");

    layout.setInsets(5, 5, 5, 5);
    layout.setInsetLeft(0);
    layout.storeCurrentStyle("Column2");

    // Add fieldPanel to mainPanel, install layout
    JPanel fieldPanel = new JPanel();
    mainPanel.add("Center", fieldPanel);
    layout.setTopContainer(fieldPanel);

    // Add fields
    for (int i = 0; i < fields.size(); i++) {
        // Prepare label and field
        Field field = (Field)fields.elementAt(i);

        //field.textField.setText(null);
        // Add using easy layout
        layout.add(new JLabel(field.label), "Column1", null);
        layout.add(field.textField, "Column2", "EndRow");
    }
}
//--- Std
private static void print(String text) {
    System.out.println("FieldWindow" + text);
}
//========== Inner Classes ===============================
class Field {
    JTextField  textField;
    String     label;
    String     previousText;
    private String     name;
    private boolean    isUpperCase;
    
    Field(int columns) {
        textField = new JTextField(columns);
    }

/**
 * Constructor used to create a password field.  This constructor 
 * is necessary because swing JTextField does not support echo characters.
 * The single parameter constructor has been retained for backwards
 * compatibilty.
 *
 * @param int columns - The number of chars in the field.
 * @param String fieldName - if Password, creates a JPasswordField
 * otherwise creates JTextField.
 */
    Field(int columns, String fieldName) {
	if (fieldName.equals("Password")) {
          textField = new JPasswordField(columns);
	} 
	else {
          textField = new JTextField(columns);
	}

    }

    public void setName(String name) {
        this.name = name;
        textField.setName(name);   
    }
    public String getName() {
        return name;   
    }
    public void setUpperCase(boolean isUpperCase, DocumentListener listener) {
        if (this.isUpperCase == isUpperCase) return;
        
        this.isUpperCase = isUpperCase;   
        if (isUpperCase) {
            textField.getDocument().addDocumentListener(listener);
        } else {
            textField.getDocument().removeDocumentListener(listener);
        }    
    }
} // End inner class

} // End outer class
