import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.event.*;


class ColorGamePanel extends JPanel {

    JRadioButton easy,medium,difficult;    // Game level
    JSlider red,green,blue;                // Color controls
    JPanel goalPanel;                    // Where goal color appears
    JPanel guessPanel;                    // Where guess color appears
    JLabel winLabel;                    // Used to indicate winning
    JLabel messageLabel;                // Where messages appear
    ColorGame game;                        // Current color game

public ColorGamePanel () {
    this.setLayout(new BorderLayout());
    
    // Prepare the win label
    winLabel = new JLabel("Winner!");
    winLabel.setForeground(Color.black);
    winLabel.setOpaque(true);
    winLabel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
    
    // Layout the radio buttons
    easy = new JRadioButton("easy");
    medium = new JRadioButton("medium");
    difficult = new JRadioButton("difficult");
    JPanel buttonPanel = new JPanel();
    buttonPanel.add(easy);
    buttonPanel.add(medium);
    buttonPanel.add(difficult);
    this.add(buttonPanel,BorderLayout.NORTH);
    
    // Place the buttons in a ButtonGroup (only one at a time is on)
    ButtonGroup group = new ButtonGroup();
    group.add(easy);
    group.add(medium);
    group.add(difficult);
        
    // Prepare and layout the sliders
    red = makeSlider(Color.red);
    green = makeSlider(Color.green);
    blue = makeSlider(Color.blue);
    JPanel sliderPanel = new JPanel();
    // Using a GridLayout makes the sliders fill up the area
    sliderPanel.setLayout(new GridLayout(1,3));
    sliderPanel.add(red);
    sliderPanel.add(green);
    sliderPanel.add(blue);
    this.add(sliderPanel,BorderLayout.WEST);
    
    // Layout the color panels
    goalPanel = new JPanel();
    guessPanel = new JPanel();
    this.add(goalPanel,BorderLayout.CENTER);
    // The goal panel is a 3-by-3 grid
    goalPanel.setLayout(new GridLayout(3,3));
    // All the grid is empty except for the center
    goalPanel.add(new JLabel());
    goalPanel.add(new JLabel());
    goalPanel.add(new JLabel());
    goalPanel.add(new JLabel());
    goalPanel.add(guessPanel);
    goalPanel.add(new JLabel());
    goalPanel.add(new JLabel());
    goalPanel.add(new JLabel());
    goalPanel.add(new JLabel());
    
    // Place the message label
    messageLabel = new JLabel();
    messageLabel.setForeground(Color.black);
    this.add(messageLabel, BorderLayout.SOUTH);
    
    // Add appropriate listeners
    MyListener listener = new MyListener();
    easy.addActionListener(listener);
    medium.addActionListener(listener);
    difficult.addActionListener(listener);
    red.addChangeListener(listener);
    green.addChangeListener(listener);
    blue.addChangeListener(listener);
    
    // Listen for mouse clicks on the guess panel (cheating)
    guessPanel.addMouseListener(new MouseAdapter () {
            public void mousePressed (MouseEvent e) {
                messageLabel.setText("Guess: " + game.guessColor 
                    + "     Goal: " + game.goalColor);
                }
            public void mouseReleased (MouseEvent e) {
                messageLabel.setText("You cheated!");
                }
            });

    // Initialize as if user picked the easy button
    easy.doClick();    
    }

/**
 * Prepare a single slider.
 * All the color sliders look the same so a single method can
 * prepare each of them.
 * @param color the background color for the slider
 * @return a newly created color slider
 */
private JSlider makeSlider (Color color) {
    JSlider slider = new JSlider(JSlider.VERTICAL,0,1,0);
    slider.setMajorTickSpacing(1);
    slider.setPaintTicks(true);
    slider.setSnapToTicks(true);
    slider.setBackground(color);
    slider.setBorder(
        BorderFactory.createLineBorder(this.getBackground(),5));
    return slider;
    }

/**
 * This class implements ActionListener (listen for button pushes)
 * and ChangeListener (listen for slider changes).  An instance
 * of this class is added to each button and slider.
 * This class is nonstatic; thus it has access to the fieds
 * of ColorGamePanel.
 */
class MyListener implements ActionListener, ChangeListener {

    /**
     * A radio button has been pushed.
     * This action restarts the game so everything must be
     * initialized again.  Some care is requred since the order
     * in which things are done can lead to problems.
     */
    public void actionPerformed (ActionEvent e) {
        JRadioButton button = (JRadioButton) e.getSource();
        
        // Prepare for a new game by setting game to null
        game = null;
        
        // Determine color range for new game
        int range = 4;
        if (button == easy) range = 4;
        else if (button == medium) range = 8;
        else if (button == difficult) range = 16;
        
        // Set the sliders appropriately
        red.setMaximum(range-1);
        green.setMaximum(range-1);
        blue.setMaximum(range-1);
        red.setValue(0);
        green.setValue(0);
        blue.setValue(0);
        
        // Create the game and display current goal and guess colors
        game = new ColorGame(range);
        goalPanel.setBackground(game.goalColor);
        guessPanel.setBackground(game.guessColor);
        
        // Update the message and remove the win label
        messageLabel.setText("Move sliders to make colors match. " +
            " (Click mouse in center square to cheat.)");
        guessPanel.remove(winLabel);
        }
    
    /**
     * A slider has been altered.
     * This action creates a new guess which is tested against the
     * goalColor.  If a match occurs then information about the win
     * is displayed.
     */
    public void stateChanged (ChangeEvent e) {
        // Ignore events that occur before the game is created
        if (game == null) return;
        
        // Get the colors, test for winning, and display the guess
        boolean isWin = game.isMatch(red.getValue(),green.getValue(),blue.getValue());
        guessPanel.setBackground(game.guessColor);
        
        // If done moving slider...
        JSlider slider = (JSlider) e.getSource();
        if (!slider.getValueIsAdjusting() && isWin) {
            messageLabel.setText(
            "You Win!  Start a new game by choosing a difficulty level.");
            guessPanel.add(winLabel);
            }
        }
        
    }
    
    
/**
 * Main program for playing the color game.
 * Creates a window (a JFrame) and loads it with a ColorGamePanel.
 * The window is closeable.
 */
public static void main (String[] args) {
    JFrame frame = new JFrame("Color Matching Game");
    frame.addWindowListener(new WindowAdapter () {
            public void windowClosing (WindowEvent e) {System.exit(0);}
            });
    frame.setSize(500,400);
    frame.getContentPane().add(new ColorGamePanel());
    frame.setVisible(true);
    }
    
}
