import  java.awt.*;
import  java.awt.event.*;
import  javax.swing.*;
import  javax.swing.border.*;

/**
 * A GUI application that demos several additional
 * components
 * 
 * @author Sharon Tuttle
 * @version 2015-10-28
 */

public class ComponentPlay
{
    /**
     * creates a ComponentPlayFrame
     * 
     * @param args not used here
     */
    
    public static void main(String args[])
    { 
        EventQueue.invokeLater(
            new Runnable()
            {
                public void run()
                {
                    ComponentPlayFrame mainFrame = new ComponentPlayFrame();
                    mainFrame.setDefaultCloseOperation( 
                        JFrame.EXIT_ON_CLOSE );    
                    mainFrame.setVisible(true); 
                }
            });
    }
}

/** 
 * A frame with a menu bar AND a panel with a variety of components
 */

class ComponentPlayFrame extends JFrame
{
    // data fields
    
    private final static int DEFAULT_WIDTH = 950;
    private final static int DEFAULT_HEIGHT = 310;
    
    /**
     * constructs a ComponentPlayFrame instance
     */
    
    public ComponentPlayFrame()
    {    
        this.setTitle("ComponentPlay");
        this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        
        // a JMenuBar cannot be placed on a JPanel --
        //    it CAN be placed on a JFrame,
        //    using its setJMenuBar method
        
        JMenuBar menuBar = new JMenuBar();
        this.setJMenuBar(menuBar);

        // add ComponentPlay panel to frame
        //    (note that I am passing the menuBar
        //    as an argument to the panel constructor
        //    so it can set the menu bar up)
        
        ComponentPlayPanel panel = new ComponentPlayPanel(menuBar);
        this.add(panel);
    }
}

/**
 * a JPanel subclass with several component examples
 */

class ComponentPlayPanel extends JPanel
{
    //-----
    // data fields
    //-----
    
    // you can select zero or more taco toppings
    
    private JPanel toppingsPanel;
    private JCheckBox[] tacoToppings;
    private static final String[] TOPPINGS
        = {"Sour cream", "Cheese", "Cilantro",
           "Lettuce", "Salsa", "Pico de Gallo",
           "Guacamole", "Pepperoni", "Onion",
           "Greek yogurt"};
    private JTextField tacoToppingsSummary;
    
    // you can select exactly one taco protein, and specify its
    //     heat level 
    
    private JPanel proteinAndHeatPanel;
    
    private JRadioButton[] tacoProteins;
    private static final String[] PROTEINS =
        {"Lean beef", "Steak", "Chicken",
         "Greasy Pork", "Pepperoni", "Tofu",
         "Nothing"};    
    
    // cheesy: maintain current taco protein choice and
    //    current heat choice as separate values, so
    //    easier to update "separately"
    
    private String currentProtein;
    private int currentHeat;
    
    private JTextField currentProteinAndHeat;
    
    // you can specify HOW hot you'd like your protein, on
    //    a scale of 0 to HEAT_MAX
    
    private JScrollBar heatBar;
    private int HEAT_MAX = 6;
    
    // you can select exactly one taco shell
    
    private JPanel shellPanel;
    private JComboBox<String> shellComboBox;
    private static final String[] SHELLS =
        {"Hard corn", "Soft flour", "Soft corn",
         "Pita", "Waffle", "Lettuce", "White corn",
         "Dorito Red", "Dorito Blue", "Dorito Purple",
         "Burrito", "Giant", "Super", "Mini"};
    private JTextField currentShell;
    
    /**
     * construct a ComponentPlayPanel instance
     * 
     * @param mBar the menu bar from the containing
     *     frame, ready to be set up in this constructor
     */
    
    public ComponentPlayPanel(JMenuBar mBar)
    {
        // making this a GridLayout -- one row, three columns
        
        this.setLayout(new GridLayout(1, 3));
        
        // set up a File menu on the passed menu bar with a few options
        
        setUpFileMenu(mBar);
                
        // create a panel for selecting 0 or more taco toppings

        toppingsPanel = setUpToppingsPanel();        
        this.add(toppingsPanel);
                
        // create a panel for selecting exactly one protein, and
        //     how hot that protein should be
                
        proteinAndHeatPanel = setUpProteinAndHeatPanel();
        this.add(proteinAndHeatPanel);
        
        // allow use to select a shell type for their taco
        
        shellPanel = setUpShellPanel();
        this.add(shellPanel);
    }
    
    /**
     * set up a File menu with two options
     * 
     * @param currMenuBar the current menu bar 
     */
        
    private void setUpFileMenu(JMenuBar currMenuBar)
    { 
        // add a File menu to the given menu bar
        
        JMenu fileMenu = new JMenu("File");
        currMenuBar.add(fileMenu);
        
        // now, add a Wake Up menu action to the File menu
        
        JMenuItem wakeUpMenuItem = new JMenuItem("Wake UP");
        wakeUpMenuItem.addActionListener(new WakeUpAction());
        wakeUpMenuItem.setActionCommand("Wake UP");
        fileMenu.add(wakeUpMenuItem);
        
        // and, add a convenient way to Quit at the end of the File menu
        
        JMenuItem quitMenuItem = new JMenuItem("Quit");
        quitMenuItem.addActionListener(new QuitAction());
        quitMenuItem.setActionCommand("Quit");
        fileMenu.add(quitMenuItem);
    }
    
    /**
     * an action listener to quit the application
     */
    
    private class QuitAction implements ActionListener
    {
        /**
         * quit the application
         * 
         * @param event selection of the Quit menu item
         */
        
        public void actionPerformed(ActionEvent event)
        {
            System.exit(0);
        }
    }  
    
    /**
     * an action listener to "wake up" the application with
     *     a splash of yellow
     */
    
    private class WakeUpAction implements ActionListener
    {
        /**
         * "wake up" the application with a splash of yellow
         * 
         * @param event selection of the Wake UP menu item
         */
        
        public void actionPerformed(ActionEvent event)
        {
            toppingsPanel.setBackground(Color.YELLOW);
            proteinAndHeatPanel.setBackground(Color.YELLOW);
            shellPanel.setBackground(Color.YELLOW);
        }
    }  
    
    /**
     * set up a sub-panel with checkboxes for selecting 0 or more
     *     taco toppings and a textfield for showing which are
     *     currently selected
     * 
     * @return a JPanel with taco toppings checkboxes and a 
     *         results text field
     */
        
    private JPanel setUpToppingsPanel()
    {
        JPanel newToppingsPanel = new JPanel();
        
        newToppingsPanel.setLayout(new BorderLayout());
        newToppingsPanel.setBorder(new EtchedBorder());
        
        // create a vertical box with the toppings checkboxes
        
        Box tacoToppingsBox = Box.createVerticalBox();
        
        // create a checkbox for each taco topping
        
        tacoToppings = new JCheckBox[TOPPINGS.length];
        
        for (int i=0; i < tacoToppings.length; i++)
        {
            tacoToppings[i] = new JCheckBox(TOPPINGS[i]);
            tacoToppings[i].addItemListener(new TacoToppingChoice());
            
            tacoToppingsBox.add(tacoToppings[i]);
        }
    
        newToppingsPanel.add(tacoToppingsBox, BorderLayout.CENTER);
        
        // summary of taco toppings should appear here
        
        tacoToppingsSummary = new JTextField(40);
        tacoToppingsSummary.setEditable(false);
        
        newToppingsPanel.add(tacoToppingsSummary, 
                       BorderLayout.PAGE_END);
        
        return newToppingsPanel;
    }
    
    /**
     * I'd like to re-display (and update) the taco
     * toppings summary every time the user
     * checks OR unchecks a taco topping
     */
    
    private class TacoToppingChoice implements ItemListener
    {
        /**
         * re-populate the taco toppings summary
         * textfield every time the state of a
         * taco topping changes
         *
         * @param event a taco topping check or uncheck
         */
        
        public void itemStateChanged(ItemEvent event)
        {
            String tacoToppingsResponse =
                "toppings: ";
            
            for (int i=0; i<TOPPINGS.length; i++)
            {
                if (tacoToppings[i].isSelected())
                {
                    tacoToppingsResponse +=
                        tacoToppings[i].getText() + " ";
                }
            }
            
            tacoToppingsSummary.setText(tacoToppingsResponse);
        }
    }
    
    /**
     * create a panel with grouped radio buttons allowing 
     *     the user to select exactly one protein, and a scrollbar
     *     to indicate how "hot" to make the protein selected
     * 
     * @return a panel with grouped radio buttons allowing the
     *         user to select a taco protein preference and a scrollbar
     *         to select the protein's desired heat level
     */
        
    private JPanel setUpProteinAndHeatPanel()
    {
        JPanel newProteinAndHeatPanel = new JPanel();
        
        newProteinAndHeatPanel.setLayout(new BorderLayout());
        newProteinAndHeatPanel.setBorder(new EtchedBorder());
        
        // set up a vertical box of taco protein radio buttons

        Box proteinBox = setUpProteinBox();
        
        // KLUGE alert: and, ah, add glue and a "choose heat" label
        //     to the bottom of the protein box -- so, ah, choose-heat
        //     label will be right before the choose-heat scrollbar in
        //     the PAGE_END of the overall panel...!
        
        proteinBox.add(Box.createVerticalGlue());
        proteinBox.add(new JLabel("Choose desired heat level: 0=mildest, " +
                                  HEAT_MAX + "=hottest"));
        
        newProteinAndHeatPanel.add(proteinBox, BorderLayout.CENTER);
        
        // let's add a HOW HOT scrollbar-panel to the bottom of
        //     our proteinAndHeatPanel
                
        // make it horizontal, initially with the bar to
        //    to right, with a 1-unit-wide bar,
        //    mininum 0, maximum HEAT_MAX+1 (so 1-unit-wide bar's
        //    "left" end can have the desired value HEAT_MAX)
        
        heatBar = new JScrollBar(JScrollBar.HORIZONTAL,
                                 HEAT_MAX, 1, 0, (HEAT_MAX+1));
        heatBar.addAdjustmentListener(new AdjustHeatAction());
        
        newProteinAndHeatPanel.add(heatBar, BorderLayout.PAGE_END);
        
        // make a textfield to show the current protein AND the current heat
        
        currentProtein = PROTEINS[0];
        currentHeat = heatBar.getValue();
        
        currentProteinAndHeat = new JTextField(
            "protein: " + currentProtein + " with heat level: " + currentHeat, 30);
        currentProteinAndHeat.setEditable(false);
        newProteinAndHeatPanel.add(currentProteinAndHeat, BorderLayout.PAGE_START);
        
        return newProteinAndHeatPanel;
    }
    
    /**
     * set up a vertical box of taco protein radio buttons
     */
        
    private Box setUpProteinBox()
    {
        Box newProteinBox = Box.createVerticalBox();
        
        // need to logically collect radio buttons in a ButtonGroup!
        
        ButtonGroup proteinGroup = new ButtonGroup();
        
        // create a radio button for each taco protein
        
        tacoProteins = new JRadioButton[PROTEINS.length];
        
        for (int i=0; i< PROTEINS.length; i++)
        {     
            tacoProteins[i] = new JRadioButton(PROTEINS[i]);
            
            tacoProteins[i].addActionListener(new ProteinChoiceAction());
                         
            // NOTICE we add each radio button to a logical ButtonGroup --
            //     so it can make sure ONLY ONE taco protein is
            //     selected at any one time
            
            proteinGroup.add(tacoProteins[i]);
            
            // (we need to set a radio button's action command to be able to grab
            // it from an ActionEvent)
            
            tacoProteins[i].setActionCommand(PROTEINS[i]);
            
            newProteinBox.add(tacoProteins[i]);
        }
        
        // set the first protein option as selected to start
        
        tacoProteins[0].setSelected(true);
        
        return newProteinBox;
    }
    
    /**
     * an action listener that displays the latest choice
     * of taco protein
     */
    
    private class ProteinChoiceAction implements ActionListener
    {
        /** 
         * display the current choice of taco protein
         * 
         * @param event a taco protein radio button click
         */
        
        public void actionPerformed(ActionEvent event)
        {
            // I can get the action command for the selected
            //     radio button (since I set its action
            //     command when I created it)
            
            currentProtein = event.getActionCommand();
            
            currentProteinAndHeat.setText("protein: " +
                currentProtein + " with heat level: " + currentHeat);
        }
    }
    
    /**
     * indicate current heat in the protein text field
     */
    
    private class AdjustHeatAction implements AdjustmentListener
    {
        /**
         * change the protein's displayed desired heat
         * when the user adjusts the heat bar
         *
         * @param event an adjustment of the heat scrollbar
         */
        
        public void adjustmentValueChanged(AdjustmentEvent event)
        {
            currentHeat = heatBar.getValue();
            
            currentProteinAndHeat.setText("protein: " +
                currentProtein + " with heat level: " + currentHeat);            
        }
    }
    
    /**
     * set up a panel with a combo box to specify the desired
     *     taco shell type, and show the current selection
     * 
     * @return a JPanel with a JComboBox of taco shell choices
     *         and a summarizing textfield
     */
        
    private JPanel setUpShellPanel()
    {
        JPanel newShellPanel = new JPanel();
        
        // ONE of JComboBox's constructors conveniently
        //     accepts an array of desired items for that
        //     combo box -- here I want to use an array
        //     of String instances
        
        shellComboBox = new JComboBox<String>(SHELLS);
        
        // COMMENT this out if you want the default,
        //     which is UNeditable
        
        shellComboBox.setEditable(true);
        
        // if you want to SAY how many rows show when
        //     this is selected 
        
        shellComboBox.setMaximumRowCount(SHELLS.length);
        
        shellComboBox.addActionListener(new ShellChoiceAction());
        
        newShellPanel.add(shellComboBox);
        
        // now add a summarizing textfield of the current shell choice
        
        currentShell = new JTextField(
                "shell: " + SHELLS[0], 20);
        currentShell.setEditable(false);
        newShellPanel.add(currentShell);
        
        return newShellPanel;
    }
    
    /**
     * an action listener that displays the latest choice
     * of taco shell
     */
    
    private class ShellChoiceAction implements ActionListener
    {
        /** 
         * display the current choice of taco shell
         * 
         * @param event a shell combo box selection
         */
        
        public void actionPerformed(ActionEvent event)
        {
            // I can get the currently-selected item
            //     in a JComboBox with its getSelectedItem
            //     method
            
            currentShell.setText("shell: " +
                shellComboBox.getSelectedItem() );
        }
    }
}