import java.awt.*;
import java.awt.event.*;

/**
 * GUI for the Animals game. Not a very nice GUI--uses generated
 * code, rather than hand-written code. I've cleaned it up some,
 * but it needs a lot more work.
 * 
 * @author  David Matuszek
 * @version October 11, 2006
 */
public class AnimalsGui extends Frame {

    private Panel panel1;
    private TextArea inputTextArea;
    private Label spacerLabel;
    private Label enterQuestionLabel;
    private Panel buttonPanel;
    private Button yesButton;
    private Button noButton;
    private TextArea mainTextArea;

    private boolean available = false;
    private String response;
    private boolean demandQuestionMark;
    
    /** 
     * Creates a new AnimalsGui for the given game.
     * */
    public AnimalsGui() {
        initComponents();
        setSize(400, 250);
    }

    /** 
     * initialize the GUI components.
     */
    private void initComponents() {
        panel1 = new Panel();
        inputTextArea = new TextArea("", 3, 50, TextArea.SCROLLBARS_NONE);
        spacerLabel = new Label();
        enterQuestionLabel = new Label();
        buttonPanel = new Panel();
        yesButton = new Button();
        noButton = new Button();
        mainTextArea = new TextArea("", 3, 80, TextArea.SCROLLBARS_NONE);
        mainTextArea.setEditable(false);
        
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent evt) {
                quit();
            }
        });
        
        panel1.setLayout(new BorderLayout());
        
        inputTextArea.addTextListener(new TextListener() {
            public void textValueChanged(TextEvent evt) {
                inputTextAreaTextValueChanged();
            }
        });
        
        panel1.add(inputTextArea, BorderLayout.CENTER);
        
        spacerLabel.setFont(new Font("Dialog", 0, 10));
        spacerLabel.setText(" ");
        panel1.add(spacerLabel, BorderLayout.SOUTH);
        panel1.add(spacerLabel, BorderLayout.WEST);
        
        enterQuestionLabel.setFont(new Font("Dialog", 0, 14));
        enterQuestionLabel.setText("Please enter your question here:");
        panel1.add(enterQuestionLabel, BorderLayout.NORTH);
        
        yesButton.setLabel("Yes");
        yesButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                yesButtonActionPerformed(evt);
            }
        });
        
        buttonPanel.add(yesButton);
        
        noButton.setLabel("No");
        noButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                noButtonActionPerformed(evt);
            }
        });
        
        buttonPanel.add(noButton);
        
        panel1.add(buttonPanel, BorderLayout.EAST);
        
        add(panel1, BorderLayout.SOUTH);
        
        mainTextArea.setFont(new Font("Serif", 0, 18));
        add(mainTextArea, BorderLayout.CENTER);
        
        pack();
    }

    private void inputTextAreaTextValueChanged() {
        String input = inputTextArea.getText();
        if (input.endsWith("\n")) {
            if (demandQuestionMark && input.indexOf('?') < 0) {
                mainTextArea.setText("Don't forget to end with a question mark.");
            }
            else {
                put(input.substring(0, input.length() - 1));
            }
        }
    }

    /**
     * Makes the message "No" available.
     */
    private void noButtonActionPerformed(ActionEvent evt) {
        put("No");
    }

    /**
     * Makes the message "Yes" available.
     */
    private void yesButtonActionPerformed(ActionEvent evt) {
        put("Yes");
    }

    /**
     * Exits the application.
     */
    public void quit() {
        System.exit(0);
    }
    
    /**
     * Puts the message in the main text area.
     *
     * @param message the message to display.
     */
    public void display(String message) {
        mainTextArea.setText(message);
    }
    
    /**
     * Ensures that one of the buttons is labeled "No", displays
     * the given question to the user, and returns <code>true</code>
     * if the user responds by clicking the "Yes" button, or returns
     * <code>false</code> if the user responds by clicking the
     * "No" button.
     *
     * @param question the question that is displayed to the user.
     * @return the answer given by the user (true == Yes).
     */
    public boolean yesOrNo(String question) {
        return yesOrNo(question, "No");
    }
    
    /**
     * Sets the label on one of the buttons (the one that isn't
     * labeled "Yes") to the given label, displays the given
     * question to the user, and returns <code>true</code>
     * if the user responds by clicking the "Yes" button, or returns
     * <code>false</code> if the user responds by clicking the
     * "No" button.
     *
     * @param question the question that is displayed to the user.
     * @param label the label to put on the No/Quit button.
     * @return the answer given by the user (true == Yes).
     */
    public boolean yesOrNo(String question, String label) {
        display(question);
        yesButton.setEnabled(true);
        noButton.setLabel(label);
        noButton.setEnabled(true);
        enterQuestionLabel.setText("");
        inputTextArea.setEditable(false);
        if (label == "Quit") inputTextArea.setText("");
        return get().equals("Yes");
    }
    
    /**
     * Displays a question to the user, and returns the String that
     * the user enters in response; if <code>demandQuestionMark</code>
     * is true, the response is only accepted if it contains a
     * question mark. In either case, the user must hit the Enter
     * key after typing in the response.
     *
     * @param question the question that is displayed to the user.
     * @param demandQuestionMark if true, the answer is taken to be
     *        complete only if it contains a question mark.
     * @return the answer given by the user (true == Yes).
     */
    public String getText(String question, boolean demandQuestionMark) {
        this.demandQuestionMark = demandQuestionMark;
        display(question);
        yesButton.setEnabled(false);
        noButton.setEnabled(false);
        inputTextArea.setText("");
        inputTextArea.setEditable(true);
        if (demandQuestionMark) {
            enterQuestionLabel.setText("Please enter your question here:");
        }
        else {
            enterQuestionLabel.setText("Please enter your animal here:");
        }
        enterQuestionLabel.setVisible(true);
        inputTextArea.setVisible(true);
        return get();
    }
    
    /**
     * Waits for and returns input from the user. This method depends on
     * the existence of two instance variables, <code>boolean available</code>
     * and <code>String message</code>, which should be used <i>only</i> by
     * this method and by <code>put(String)</code>. The <code>available</code>
     * variable should be initialized to <code>false</code>.
     *
     * @return the String entered by the user.
     */
    public synchronized String get() {
        while (! available) {
            try { wait(); }
            catch (InterruptedException e) {}
        }
        available = false;
        notifyAll();
        //        display(message);
        return response;
    }
    
    /**
     * Makes input from the user available. This method should be called
     * <i>only</i> from within an event handler, and <i>only</i> when the
     * event handler determines that the input is complete.
     * <p>This method depends on the existence of two instance variables,
     * <code>boolean available</code>  and <code>String message</code>, which
     * should be used <i>only</i> by this method and by <code>get()</code>. The
     * <code>available</code> variable should be initialized to <code>false</code>.
     * @param s 
     */
    public synchronized void put(String s) {
        while (available) {
            try { wait(); }
            catch (InterruptedException e) {}
        }
        response = s;
        available = true;
        notifyAll();
    }
        }
