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

import java.io.File;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * ImageViewer is the main class of the image viewer application. It builds and
 * displays the application GUI and initialises all other components.
 * 
 * To start the application, create an object of this class.
 * 
 * @author Michael Kolling and David J Barnes
 * @updates and changes by Michael Rivers
 * @version 2.0 May 16th, 2006
 */
public class ImageViewer
{
    // constants:
    private static final String VERSION = "Michael Rivers";
    private static JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir"));

    // fields:
    private JFrame frame;
    private ImagePanel imagePanel;
    private JLabel filenameLabel;
    private JLabel statusLabel;
    private OFImage currentImage;
    
    private List filters;
        
    /**
     * Create an ImageViewer show it on screen.
     */
    public ImageViewer()
    {
        filters = createFilters();
        makeFrame();
        currentImage = imagePanel.panelImage;
    }


    // ---- implementation of menu functions ----
    // file menu functions
    /**
     * Open function: open a file chooser to select a new image file.
     */
    private void openFile()
    {
        int returnVal = fileChooser.showOpenDialog(frame);

            if(returnVal != JFileChooser.APPROVE_OPTION) {
                return;  // cancelled
            }
            File selectedFile = fileChooser.getSelectedFile();
            currentImage = ImageFileManager.loadImage(selectedFile);

        if(currentImage == null) {   // image file was not a valid image
            JOptionPane.showMessageDialog(frame,
                    "The file was not in a recognized image file format.",
                    "Image Load Error",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }
        imagePanel.setImage(currentImage);
        showFilename(selectedFile.getPath());
        showStatus("File loaded.");
        frame.pack();
    }
    
    /**
     * Close function: clase the current image.
     */
    private void close()
    {
        currentImage = null;
        imagePanel.clearImage();
        showFilename(null);
    }
    
    /**
     * Restart funcion: restart the applet.
     */
    private void restart()
    {
        imagePanel.panelImage = new OFImage(360, 240);
        imagePanel.drawDefualtImage();
        currentImage = imagePanel.panelImage;
        frame.repaint();
    }        
    
    /**
     * Quit function: quit the application.
     */
    private void quit()
    {
        System.exit(0);
    }
    
    // filter menu functions
    /**
     * Apply a given filter to the current image.
     */
    private void applyFilter(Filter filter)
    {
        if(currentImage != null) {
            // filter is applied to the panel image because
            // the currentImage is not changed when you resize
            // to allow you to resize to various sizes without loss
            // of quality.
            filter.apply(imagePanel.panelImage);
            // currentImage is set to panelImage so that the resize
            // filter may resize the image with the filter's affect
            currentImage = imagePanel.panelImage;
            frame.repaint();
            showStatus("Applied: " + filter.getName());
        }
        else {
            showStatus("No image loaded.");
        }
    }
    
    // strip menu functions
    /**
     * Strip the image down to one specified color.
     */
    private void strip(int rgb)
    {
        if(rgb == StripFilter.RED){
            StripFilter stripFilter = new StripFilter ("Red", StripFilter.RED);
            stripFilter.apply(imagePanel.panelImage);
            currentImage = imagePanel.panelImage;
            frame.repaint();
        }
        
        if(rgb == StripFilter.GREEN){
            StripFilter stripFilter = new StripFilter ("Green", StripFilter.GREEN);
            stripFilter.apply(imagePanel.panelImage);
            currentImage = imagePanel.panelImage;
            frame.repaint();
        }
        
        if(rgb == StripFilter.BLUE){
            StripFilter stripFilter = new StripFilter ("Blue", StripFilter.BLUE);
            stripFilter.apply(imagePanel.panelImage);
            currentImage = imagePanel.panelImage;
            frame.repaint();
        }
    }
    // resize menu functions
    /**
     * Resize the image to a size specified by the user.
     * Current image is not changed so multiple resizes
     * may be applied without any loss of image quality.
     */
    private void resize()
    {
        // get the width from the user
        String width = (String)JOptionPane.showInputDialog(
            frame,
            "Resizing your image.\n"
            + "\"Please specify width:\"",
            "Resize Your Image",
            JOptionPane.PLAIN_MESSAGE);
        int xSize = Integer.parseInt(width);

        // get the height from the user
        String height = (String)JOptionPane.showInputDialog(
            frame,
            "Resizing your image.\n"
            + "\"Please specify height:\"",
            "Resize Your Image",
            JOptionPane.PLAIN_MESSAGE);
        int ySize = Integer.parseInt(height);
        
        // resize the image using the resize filter
        ResizeFilter myResizeFilter = new ResizeFilter("Resize",xSize,ySize);
        myResizeFilter.apply(currentImage);
        imagePanel.setImage(myResizeFilter.resizedImage);
        frame.repaint();
    }
    
    /**
     * This scales the image to the percent given by the int value of
     * the call method statement (80% for smaller and 125% for bigger).
     */
    private void resize(int scaleSize)
    {
        int width = imagePanel.panelImage.getWidth();
        int height = imagePanel.panelImage.getHeight();
        int xSize = Math.round(scaleSize*width/100);
        int ySize = Math.round(scaleSize*height/100);        
        ResizeFilter myResizeFilter = new ResizeFilter("Resize",xSize,ySize);
        myResizeFilter.apply(currentImage);
        imagePanel.setImage(myResizeFilter.resizedImage);
        frame.repaint();
    }
    
    // help menu functions
    /**
     * Show the version in an information dialog box.
     */
    private void showAbout()
    {
        JOptionPane.showMessageDialog(frame, 
                "ImageViewer\n" + VERSION,
                "About ImageViewer", 
                JOptionPane.INFORMATION_MESSAGE);
    }
    
    /**
     * Show some information about WOU in a dialog box.
     */
    private void showAboutWOU()
    {
        JOptionPane.showMessageDialog(frame, 
                "Western Oregon University\nUniversity of Liberal Arts",
                "About WOU", 
                JOptionPane.INFORMATION_MESSAGE);
    }
    
    // ---- support methods ----
    /**
     * Display a file name on the appropriate label.
     */
    private void showFilename(String filename)
    {
        if(filename == null) {
            filenameLabel.setText("No file displayed.");
        }
        else {
            filenameLabel.setText("File: " + filename);
        }
    }
    
    /**
     * Display a status message in the frame's status bar.
     */
    private void showStatus(String text)
    {
        statusLabel.setText(text);
    }
    
    /**
     * Create and return a list with all the known filters.
     */
    private List createFilters()
    {
        List filterList = new ArrayList();
        filterList.add(new DarkerFilter("Darker"));
        filterList.add(new LighterFilter("Lighter"));
        filterList.add(new ThresholdFilter("Threshold"));
        filterList.add(new GrayscaleFilter("Grayscale"));
        filterList.add(new MikesFilter("Rainbow"));
        filterList.add(new InvertFilter("Invert"));
        filterList.add(new MirrorFilter("Mirror"));
        filterList.add(new QuadrantFilter("Quadrant"));
        filterList.add(new CircleFilter("Circle"));
        return filterList;
    }

    // ---- swing stuff to build the frame and all its components ----
    
    /**
     * Create the Swing frame and its content.
     */
    private void makeFrame()
    {
        frame = new JFrame("WOU Image Viewer");
        Container contentPane = frame.getContentPane();
        
        makeMenuBar(frame);
        
        // Specify the layout manager with nice spacing
        contentPane.setLayout(new BorderLayout(6, 6));
        
        filenameLabel = new JLabel();
        contentPane.add(filenameLabel, BorderLayout.NORTH);

        imagePanel = new ImagePanel();
        contentPane.add(imagePanel, BorderLayout.CENTER);

        statusLabel = new JLabel(VERSION);
        contentPane.add(statusLabel, BorderLayout.SOUTH);
        
        // building is done - arrange the components and show        
        showFilename(null);
        frame.pack();
        
        // center the frame on screen
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setLocation(d.width/2 - frame.getWidth()/2, d.height/2 - frame.getHeight()/2);
        frame.setVisible(true);
    }
    
    /**
     * Create the main frame's menu bar.
     */
    private void makeMenuBar(JFrame frame)
    {
        final int SHORTCUT_MASK =
            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();


        JMenuBar menubar = new JMenuBar();
        frame.setJMenuBar(menubar);
        
        JMenu menu;
        JMenuItem item;
        
        // create the File menu
        menu = new JMenu("File");
        menubar.add(menu);
        
        item = new JMenuItem("Open");
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, SHORTCUT_MASK));
            item.addActionListener(new ActionListener() {
                               public void actionPerformed(ActionEvent e) { openFile(); }
                           });
        menu.add(item);

        item = new JMenuItem("Close");
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, SHORTCUT_MASK));
            item.addActionListener(new ActionListener() {
                               public void actionPerformed(ActionEvent e) { close(); }
                           });
        menu.add(item);
        
        item = new JMenuItem("Restart");
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, SHORTCUT_MASK));
            item.addActionListener(new ActionListener() {
                               public void actionPerformed(ActionEvent e) { restart(); }
                           });
        menu.add(item);
        
        menu.addSeparator();
        
        item = new JMenuItem("Quit");
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, SHORTCUT_MASK));
            item.addActionListener(new ActionListener() {
                               public void actionPerformed(ActionEvent e) { quit(); }
                           });
        menu.add(item);
        
        // create the Filter menu
        menu = new JMenu("Filter");
        menubar.add(menu);
        
        for(Iterator it=filters.iterator(); it.hasNext(); ) {
            final Filter filter = (Filter)it.next();
            
            item = new JMenuItem(filter.getName());
            item.addActionListener(new ActionListener() {
                                public void actionPerformed(ActionEvent e) { 
                                    applyFilter(filter);
                                }
                           });
             menu.add(item);
         }

        // create the Strip menu
        menu = new JMenu("Strip");
        menubar.add(menu);
        
        item = new JMenuItem("Red");
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {strip(StripFilter.RED); }
        });
        menu.add(item);

        item = new JMenuItem("Green");
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {strip(StripFilter.GREEN); }
        });
        menu.add(item);
        
        item = new JMenuItem("Blue");
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {strip(StripFilter.BLUE); }
        });
        menu.add(item);
        
        // create Resize menu
        
        menu = new JMenu("Resize");
        menubar.add(menu);
        
        item = new JMenuItem("Custom Size");
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, SHORTCUT_MASK));
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {resize(); }
        });
        menu.add(item);
        
        item = new JMenuItem("Bigger");
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, SHORTCUT_MASK));
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {resize(125); }
        });
        menu.add(item);
        
        item = new JMenuItem("Smaller");
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, SHORTCUT_MASK));
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {resize(80); }
        });
        menu.add(item);

        // put a spacer into the menubar, so the next menu appears to the right
        menubar.add(Box.createHorizontalGlue());

        // create the Help menu
        menu = new JMenu("Help");
        menubar.add(menu);
        
        item = new JMenuItem("About ImageViewer...");
            item.addActionListener(new ActionListener() {
                               public void actionPerformed(ActionEvent e) { showAbout(); }
                           });
        menu.add(item);
        
        item = new JMenuItem("About WOU...");
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, SHORTCUT_MASK));
            item.addActionListener(new ActionListener() {
                               public void actionPerformed(ActionEvent e) { showAboutWOU(); }
                           });
        menu.add(item);
    }
}

