import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;

/**
 * Creates a GUI with an input text area, an output
 * text area, and a button panel containing four
 * buttons, "New code", "Encode", "Decode", and
 * "Quit." Each button (except Quit) calls a method
 * in a CodeMachine object, and displays the result
 * in the output area.
 *
 * @author David Matuszek
 * @version Oct 19, 2006
 */
public class SecretCode2 extends JFrame {
    private JMenuBar menuBar;
    
    private JMenu editMenu;
    private JMenuItem loadMenuItem;
    private JMenuItem saveAsMenuItem;
    private JMenuItem quitMenuItem;
    
    private JMenu codeMenu;
    private JMenuItem simpleCodeItem;
    private JMenuItem arrayCodeItem;
    private JMenuItem pigLatinItem;
    
    private JPanel contentPanel;
    private JTextArea inputTextArea;
    private JTextArea outputTextArea;
    
    private JPanel buttonPanel;
    private JButton newCodeButton;
    private JButton encodeButton;
    private JButton decodeButton;
    private JButton quitButton;

    private SecretCode2 thisGui;
    private CodeMachine coder;
    private String codeType = "simple";
    private String secretKey = "";

    private int width;
    private int height;

    /**
     * Constructor for SecretCode objects.
     * @param coder The CodeMachine object to be used when the
     *              GUI's buttons are clicked.
     */
    public SecretCode2(CodeMachine coder) {
        this.coder = coder;
        width = 200;
        height = 150;
        createWidgets();
        createGui();
        attachListeners();
        thisGui = this;
        thisGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    /**
     * Creates all the GUI elements.
     */
    private void createWidgets() {
        menuBar = new JMenuBar();
        
        editMenu = new JMenu("Edit");
        loadMenuItem = new JMenuItem("Load...");
        saveAsMenuItem = new JMenuItem("Save As...");
        quitMenuItem = new JMenuItem("Quit");

        codeMenu = new JMenu("Code");
        simpleCodeItem = new JMenuItem("Simple code...");
        arrayCodeItem = new JMenuItem("Array code...");
        pigLatinItem = new JMenuItem("Pig Latin");
        
        contentPanel = new JPanel();
        buttonPanel = new JPanel();
        inputTextArea = new JTextArea();
        outputTextArea = new JTextArea();
        
        newCodeButton = new JButton("New code");
        encodeButton = new JButton("Encode");
        decodeButton = new JButton("Decode");
        quitButton = new JButton("Quit");
    }

    /**
     * Creates the main areas of the GUI and installs them.
     */
    private void createGui() {
        createMenus();
        createContentArea();
        createButtonArea();
        setSize(width, height);
    }

    private void createMenus() {
        menuBar.add(editMenu);
        editMenu.add(loadMenuItem);
        editMenu.add(saveAsMenuItem);
        editMenu.add(quitMenuItem);
        
        menuBar.add(codeMenu);
        codeMenu.add(simpleCodeItem);
        codeMenu.add(arrayCodeItem);
        codeMenu.add(pigLatinItem);
        
        this.setJMenuBar(menuBar);
    }

    /**
     * Creates and installs the input and output text areas.
     */
    private void createContentArea() {
        setLayout(new BorderLayout());
        add(contentPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
        contentPanel.setLayout(new GridLayout(2, 1));
        contentPanel.add(makeScrollableArea(inputTextArea,
            "Input text"));
        contentPanel.add(makeScrollableArea(outputTextArea,
            "Output text"));
        inputTextArea.selectAll();
    }

    /**
     * Puts a titled border around the given text area, and adds
     * horizontal and vertical scroll bars as needed.
     *
     * @param textArea The text area to be decorated.
     * @param title The title to put above the text area.
     * @return The decorated text area.
     */
    private JScrollPane makeScrollableArea(JTextArea textArea,
                                           String title) {
        Border lineBorder;
        TitledBorder titledBorder;
        // Make a panel containing a text area
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(textArea);
        // Make a titled scroll pane containing the panel
        JScrollPane scrollPane = new JScrollPane(panel);
        // Put the border and title around the scroll pane
        lineBorder = BorderFactory.createLineBorder(Color.black);
        titledBorder = BorderFactory.createTitledBorder(lineBorder, title);
        scrollPane.setBorder(titledBorder);
        scrollPane.setBackground(Color.WHITE);

        return scrollPane;
    }

    /**
     * Puts the buttons into the button panel.
     */
    private void createButtonArea() {
        buttonPanel.setLayout(new GridLayout(1, 4));
        buttonPanel.add(newCodeButton);
        buttonPanel.add(encodeButton);
        buttonPanel.add(decodeButton);
        buttonPanel.add(quitButton);
    }

    /**
     * Activates each of the buttons in the GUI. The variable "coder"
     * is an field of this object, whose value is an instance of
     * CodeMachine, and
     * <ul><li>New code -- calls CodeMachine.create(secretKey),</li>
     *     <li>Encode -- calls coder.encode(input),</li>
     *     <li>Decode -- calls coder.decode(input),</li>
     *     <li>Quit -- just quits the program.</li>
     * </ul>
     * where "input" is gotten from the input text area of the GUI.
     * Displays the result of each coder method in the output text area.
     */
    private void attachListeners() {
        // Edit menu
        loadMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                loadFile();
            }
        });
        saveAsMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                saveFileAs();
            }
        });
        quitMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                System.exit(0);
            }
        });
        // Code menu
        simpleCodeItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                String newSecretKey = getSecretKey();
                if (newSecretKey != null) {
                    codeType = "simple";
                    secretKey = newSecretKey;
                    coder = CodeMachine.create(codeType, secretKey);
                    outputTextArea.setText("New simple code created using \"" +
                                           secretKey + "\".");
                    newCodeButton.setEnabled(true);
                }
            }
        });
        arrayCodeItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                String newSecretKey = getSecretKey();
                if (newSecretKey != null) {
                    codeType = "array";
                    secretKey = newSecretKey;
                    coder = CodeMachine.create(codeType, secretKey);
                    outputTextArea.setText("New array code created using \"" +
                                           secretKey + "\".");
                    newCodeButton.setEnabled(true);
                }
            }
        });
        pigLatinItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {;
                codeType = "pig latin";
                coder = CodeMachine.create(codeType, secretKey);
                outputTextArea.setText("Now using Pig Latin.");
                newCodeButton.setEnabled(false);
            }
        });
        
        // Buttons
        newCodeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                String newSecretKey = getSecretKey();
                coder = CodeMachine.create(codeType, secretKey);
                outputTextArea.setText("New " + codeType +
                                       " code created using \"" +
                                       secretKey + "\".");
            }
        });
        decodeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                String input = inputTextArea.getText();
                String output = coder.decode(input);
                outputTextArea.setText(output);
            }
        });
        encodeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                String input = inputTextArea.getText();
                String output = coder.encode(input);
                outputTextArea.setText(output);
            }
        });
        quitButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                System.exit(0);
            }
        });
    }

    protected void loadFile() {
        BufferedReader reader = getReader();
        String line;
        try {
            while ((line = reader.readLine()) != null) {
                inputTextArea.append(line + "\n");
            }
        } catch (IOException e) {
            JOptionPane.showMessageDialog(null, e.getMessage());
        }
    }
    
    public static BufferedReader getReader() {
        File file = getInputFile();
        try {
            if (file != null) {
                String fileName = file.getCanonicalPath();
                return new BufferedReader(new FileReader(fileName));
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    protected void saveFileAs() {
        PrintWriter writer = getWriter();
        writer.println(outputTextArea.getText());
    }

    
    private String getSecretKey() {
        return JOptionPane.showInputDialog(thisGui,
                                           "Enter a secret word or phrase:");
    }

    public static File getInputFile() {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogTitle("Load which file?");
        int result = chooser.showOpenDialog(null);
        if (result == JFileChooser.APPROVE_OPTION) {
            return chooser.getSelectedFile();
        }
        else {
            return null;
        }
    }
    
    public static PrintWriter getWriter() {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogTitle("Save file as?");
        int result = chooser.showSaveDialog(null);
        if (result == JFileChooser.APPROVE_OPTION) {
            File file = chooser.getSelectedFile();
            String fileName;
            try {
                if (file != null) {
                    fileName = file.getCanonicalPath();
                    return new PrintWriter(new FileOutputStream(fileName), true);
                }
            }
            catch (IOException e) { 
                e.printStackTrace();
            }       
        }
        return null;
    }

    /**
     * Creates the GUI, which takes over processing.
     *
     * @param args Unused.
     */
    public static void main(String[] args) {
        CodeMachine coder = CodeMachine.create("simple", "abracadabra");
        SecretCode2 window = new SecretCode2(coder);
        window.setSize(400, 250);
        window.setVisible(true);
    }
}
