import java.awt.*;
import java.awt.image.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.image.*;

/** An instance is a JFrame that contains an image with a title and
 buttons to cause alteration of the image.
 When no image is in the JFrame, it is hidden.
 When an image is placed in it, it becomes visible. */
public class ImageGUI extends JFrame implements ActionListener {
    
    // server contains the original and current ImageMaps and
    // methods that manipulate them.
    private ImageServer server; 
    
    // Buttons
    private JButton buttonrestore= new JButton("restore");
    private JButton buttoninvert= new JButton("invert");
    private JButton buttontranspose= new JButton("transpose");
    private JButton buttonhreflect= new JButton("hor reflect");
    private JButton buttonvreflect= new JButton("ver reflect");
    private JButton buttonfilter= new JButton("filter");
    private JButton buttonhide= new JButton("hide message");
    private JButton buttonreveal= new JButton("reveal message");
    private Box buttonBox= new Box(BoxLayout.Y_AXIS);
    
    // Three radio buttons
    private JRadioButton greyButton= new JRadioButton("grey", true);
    private JRadioButton redButton= new JRadioButton("red", false);
    private JRadioButton greenButton= new JRadioButton("green", false);
    private JRadioButton blueButton= new JRadioButton("blue", false);
    private Box checkboxBox= new Box(BoxLayout.X_AXIS);
    
    private ButtonGroup group= new ButtonGroup();
    
    
    /** The panel with the original image, the panel with the current image,
     and the box that contains both. */
    private ImagePanel originalPanel;
    private ImagePanel currentPanel;
    Box inputBox= new Box(BoxLayout.Y_AXIS);
    
    // The text area for the user to give a message
    private JTextArea messageArea= new JTextArea(4, 20);
    private JScrollPane scrollPane= new JScrollPane(messageArea);
    private JLabel jlabel= new JLabel("Type the message to be hidden in this text area:");
    Box areaBox= new Box(BoxLayout.Y_AXIS);
    
    // imageBox contains the original image and the current one
    Box imagebox= new Box(BoxLayout.X_AXIS);
    
    /** = the current panel */
    public ImagePanel getCurrentPanel() {
        return currentPanel;
    }
    
    /** = the original panel */
    public ImagePanel getOriginalPanel() {
        return originalPanel;
    }
    
    /** = the ImageServer for the image*/
    public ImageServer getserver() {
        return server;
    }
    
    /** A jframe with a picture in it and the title
     "picture". The picture is obtained from the user
     using a dialog window. */
    public static void main(String[] pars) {
        ImageGUI ij;
        ij= new ImageGUI();
    }
    
    /** Constructor: an instance for Image im.
     If im is null, the window is not shown. */
    public ImageGUI(Image im) {
        super();
        setUp(im, "An image");
    }
    
    
    /** Constructor: an instance for an Image that is found using a file dialog
     window. If no Image is produced using the file dialog,
     use null as the Image*/
    public ImageGUI() {
        String f= getImageName();
        Image im= getImage(f, this);
        setUp(im, "image: " + f); 
    }
    
    /** Set up JFrame with i, with title t. This includes creating the
     ImageServer, adding buttons and checkboxes to the GUI, 
     performing a few other minor operations to make the GUI
     work properly, and placing the image in the JFrame.*/
    private void setUp(Image im, String t) {
        setTitle(t);
        
        // Build box buttonBox of buttons.
        buttonBox.add(buttonrestore);
        buttonBox.add(buttoninvert);
        buttonBox.add(buttontranspose);
        buttonBox.add(buttonhreflect);
        buttonBox.add(buttonfilter);
        getContentPane().add(BorderLayout.WEST, buttonBox);
        
        // Register this instance as a listener for all buttons.
        buttonrestore.addActionListener(this);
        buttoninvert.addActionListener(this);
        buttontranspose.addActionListener(this);
        buttonhreflect.addActionListener(this);
        buttonfilter.addActionListener(this);
        
        // Build box inputBox of the color buttons.
        checkboxBox.add(greyButton);
        checkboxBox.add(redButton);
        checkboxBox.add(greenButton);
        checkboxBox.add(blueButton);
        inputBox.add(checkboxBox);
        
        // Add the color buttons to group.
        group.add(greyButton);
        group.add(redButton);
        group.add(blueButton);
        group.add(greenButton);
        
        getContentPane().add(BorderLayout.NORTH, inputBox);
        
        // Add a text area with label --for the next assignment
        areaBox.add(jlabel);
        areaBox.add(scrollPane);
        getContentPane().add(BorderLayout.SOUTH, areaBox);
        
        // If there is no image, make JFrame invisible and return
        if (im == null) {
            setVisible(false);
            return;
        }
        
        // Create the two panels and the ImageServer server.
        originalPanel= new ImagePanel(im);
        currentPanel= new ImagePanel(im);
        
        // Add the panels to the GUI, in imagebox.
        imagebox= new Box(BoxLayout.X_AXIS);
        imagebox.add(originalPanel);
        imagebox.add(currentPanel);
        getContentPane().add(BorderLayout.EAST, imagebox);
        
        // Create an instance of ImageServer to manipulate the image.
        server= new ImageServer(new ImageMap(im,
                            im.getHeight(originalPanel), im.getWidth(originalPanel)));
        
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocation(200,100);
        pack();
        setVisible(true);
        repaint();
    }
    
    /** Pause the program for d microseconds */
    public void pause(int d) {
        try { Thread.currentThread().sleep(d); }
        catch (InterruptedException e) { }
    }
    
    /** = the grey check box in the GUI is selected */
    private boolean greyIsChecked() {
        return greyButton.isSelected();
    }
    /** = the red check box in the GUI is selected */
    private boolean redIsChecked() {
        return redButton.isSelected();
    }
    
    /** = the green check box in the GUI is selected */
    private boolean greenIsChecked() {
        return greenButton.isSelected();
    }
    
    /** = the red check box in the GUI is selected */
    private boolean blueIsChecked() {
        return blueButton.isSelected();
    }
    
    /** Change current image to the map given by 
        server.getCurrentMap(). */
    private void changeCurrentImage() {
        currentPanel.formImage(server.getCurrentMap());
        repaint();
    }
    
    /** = the file name of an image loaded by the user using a dialog window */
    public static String getImageName() {
        FileDialog fd = new FileDialog(new Frame(), "Open File", FileDialog.LOAD);
        fd.setVisible(true);
        if (fd.getFile() == null) 
            return null;
        return fd.getDirectory() + fd.getFile();
    }
    
    /** = the image for file name f, using the toolkit for jframe */
    public static Image getImage(String f, JFrame jframe) {
        Image image= null;
        try {
            image= jframe.getToolkit().getImage(new URL("file:" + f));
            
        } 
        catch (MalformedURLException e) {
            System.err.println("Bad URL!");
            return null;
        }
        
        // set media tracker to wait for image to load
        MediaTracker tracker= new MediaTracker(jframe);
        tracker.addImage(image,0);    
        
        // wait for image to load
        try { tracker.waitForID(0); 
        }
        catch (InterruptedException e) {
            // handler.flashMessage(ImageHandler.LOAD_INTERRUPTED);
            return null;
        }
        return image;
    }
    
    /** Process a click of one of the buttons */
    public void actionPerformed(ActionEvent e) {
        
        if (e.getSource() == buttonrestore) {
            server.restore();
            changeCurrentImage();
            return;
        }
        if (e.getSource() == buttoninvert) {
            server.invert();
            changeCurrentImage();
            return;
        }
        if (e.getSource() == buttontranspose) {
            server.transpose();
            changeCurrentImage();
            return;
        }
        if (e.getSource() == buttonhreflect) {
            server.hreflect();
            changeCurrentImage();
            return;
        }
        if (e.getSource() == buttonvreflect) {
            server.vreflect();
            changeCurrentImage();
            return;
        }
        
        if (e.getSource() == buttonfilter) {
            if (greyIsChecked()) {
                server.filter(ImageServer.GRAY);
                changeCurrentImage();
                return;
            }
            if (redIsChecked()) {
                server.filter(ImageServer.RED);
                changeCurrentImage();
                return;
            }
            if (greenIsChecked()) {
                server.filter(ImageServer.GREEN);
                changeCurrentImage();
                return;
            }
            if (blueIsChecked()) {
                server.filter(ImageServer.BLUE);
                changeCurrentImage();
                return;
            }
        }
        if (e.getSource() == buttonhide) {
            String m= messageArea.getText();
            boolean b= server.hide(m);
            if (b) {
                messageArea.setText("Message was hidden.\n");
                changeCurrentImage();
            } else {
                messageArea.setText("Message too long to be hidden:\n" + m);
            }
            
            return;
        }
        if (e.getSource() == buttonreveal) {
            String m= server.reveal();
            if (m == null) {
                messageArea.setText("No message found to reveal.");
            } else {
                messageArea.setText(m);
            }
            return;
        }
        
    }
    
    
    /** Invert the image */
    public void invert() {
        server.invert();
        changeCurrentImage();
    }
    
    /** Reveal the message that is hidden in this picture --give
        a message stating that there is none if there is none. */
    public void reveal() {
        
    }
    
    /** Hide message m in the image */
    public void hide(String m) {
        boolean successful= server.hide(m);
        if (successful) {
            System.out.println("Message was hidden.");
            changeCurrentImage();
        } else {
            System.out.println("Message too long to be hidden." + m); 
        }
    }
    
    /** Transpose the image */
    public void transpose() {
        server.transpose();
        changeCurrentImage();
    }
    
    /** Reflect the image around the horizontal middle */
    public void hreflect() {
        server.hreflect();
        changeCurrentImage();
    }
    
    /** Reflect the image around the vertical middle */
    public void vreflect() {
        server.vreflect();
        changeCurrentImage();
    }
    
    /** Restore the original image */
    public void restore() {
        server.restore();
        changeCurrentImage();
    }
    
    /** Filter the image according to the grey-red-blue-green buttons */
    public void filter() {
        if (greyIsChecked()) {
            server.filter(ImageServer.GRAY);
            changeCurrentImage(); 
            return;
        }
        if (redIsChecked()) {
            server.filter(ImageServer.RED);
            changeCurrentImage();
            return;
        }
        if (greenIsChecked()) {
            server.filter(ImageServer.GREEN);
            changeCurrentImage();
            return;
        }
        if (blueIsChecked()) {
            server.filter(ImageServer.BLUE);
            changeCurrentImage();
            return;
        }
    }
    
    
    /** Provided the file does not yet exist, write the image with file name fileName.
        It is assumed that it is a jpeg file. Include the extension. e.g. write("pic.jpg"); 
        Put a message on the console indicating whether or not it has been written.
        */
    public void write(String fileName) throws java.io.IOException {
        server.write(fileName, "jpg");
    }
    
}