import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * The drawable area of the GUI that the user will be able to draw in.
 * 
 * @author Joel Carlson and Ty Strayer. Created Apr 4, 2008.
 */
public class DrawableArea extends JPanel implements ActionListener {

	private ArrayList<Tool> toolList = new ArrayList<Tool>();

	private ArrayList<Tool> redoList = new ArrayList<Tool>();

	private Color currentOutlineColor = Color.black;

	private Color currentFillColor = null;

	private String filename = null;

	private Image background = null;

	/**
	 * Constructs the drawable area with a blue border and white background.
	 * 
	 */
	public DrawableArea() {
		super();
		this.setBackground(Color.white);
	}

	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (this.background != null) {
			g.drawImage(this.background, 0, 0, this);
		}
		for (int i = 0; i < this.toolList.size(); i++) {
			this.toolList.get(i).drawTool(g);
		}
	}

	/**
	 * Disables the last tool used by removing the MouseListener and
	 * MouseMotionListener.
	 * 
	 */
	public void disableLastTool() {
		if (this.getComponentCount() > 0) {
			MouseListener[] listeners = this.getMouseListeners();
			this.removeMouseListener(listeners[0]);
			MouseMotionListener[] motionListeners = this
					.getMouseMotionListeners();
			this.removeMouseMotionListener(motionListeners[0]);
		}
	}

	/**
	 * Adds a new tool to the drawableArea and to the toolList.
	 * 
	 * @param tool
	 *            The Tool to add.
	 */
	public void addTool(Tool tool) {
		this.toolList.add(tool);
		this.add(tool);
		this.addMouseListener(tool);
		this.addMouseMotionListener(tool);
	}

	/**
	 * Changes the Color of the currentOutlineColor field.
	 * 
	 * @param color
	 *            The Color to set.
	 */
	public void setOutlineColor(Color color) {
		this.currentOutlineColor = color;
	}

	/**
	 * Get the current set outline color.
	 * 
	 * @return The color being used.
	 */
	public Color getOutlineColor() {
		return this.currentOutlineColor;
	}

	/**
	 * Changes the Color of the currentFillColor field.
	 * 
	 * @param color
	 *            The Color to set.
	 */
	public void setFillColor(Color color) {
		this.currentFillColor = color;
	}

	/**
	 * Get the current set fill color.
	 * 
	 * @return The color being used.
	 */
	public Color getFillColor() {
		return this.currentFillColor;
	}

	/**
	 * Removes the last tool from the toolList.
	 * 
	 */
	public void removeLastTool() {
		if (this.toolList.size() > 0) {
			Tool comp = this.toolList.get(this.toolList.size() - 1);
			this.toolList.remove(this.toolList.size() - 1);
			this.remove(comp);
		}
	}

	private void undo() {
		if (this.toolList.size() > 1) {
			this.redoList.add(this.toolList.get(this.toolList.size() - 2));
			this.toolList.remove(this.toolList.size() - 2);
			this.repaint();
		}
	}

	private void redo() {
		if (this.redoList.size() > 0) {
			this.toolList.add(this.toolList.get(this.toolList.size() - 1));
			this.toolList.set(this.toolList.size() - 2, this.redoList
					.get(this.redoList.size() - 1));
			this.redoList.remove(this.redoList.size() - 1);
			this.repaint();
		}
	}

	private void save() {
		int width = this.getWidth();
		int height = this.getHeight();
		BufferedImage image = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_RGB);
		this.paint(image.getGraphics());

		try {
			ByteArrayOutputStream boutstream = new ByteArrayOutputStream();
			JPEGImageEncoder enc = JPEGCodec.createJPEGEncoder(boutstream);
			enc.encode(image);
			FileOutputStream fimage = new FileOutputStream(new File(
					this.filename));
			boutstream.writeTo(fimage);
			fimage.close();
		} catch (Exception ex) {
			return;
		}

		this.open(this.filename);
	}

	private void savePrompt() {
		String input;
		input = JOptionPane
				.showInputDialog("Please enter a file name ending in .jpg to save as.");
		this.filename = input;
	}

	private void saveAs() {
		this.savePrompt();
		this.save();
	}

	private String openPrompt() {
		String input;
		input = JOptionPane
				.showInputDialog("Please enter a file name ending in .jpg to open.");
		return input;
	}

	private void clearLists() {
		this.toolList = new ArrayList<Tool>();
		this.redoList = new ArrayList<Tool>();
	}

	private void open(String input) {

		if (input == null) {
			System.out.println("Oh Shit!");
			return;
		}
		this.filename = input;
		this.background = Toolkit.getDefaultToolkit().getImage(input);
		this.clearLists();
		this.repaint();
	}

	private void newFile() {
		this.clearLists();
		this.background = null;
		this.filename = null;
		this.repaint();
	}

	public void actionPerformed(ActionEvent e) {
		String msg = e.toString();
		if (msg.contains("text=Undo")) {
			this.undo();
		} else if (msg.contains("text=Redo")) {
			this.redo();
		} else if (msg.contains("text=New")) {
			this.newFile();
		} else if (msg.contains("text=SaveAs")) {
			this.saveAs();
		} else if (msg.contains("text=Open")) {
			this.open(openPrompt());
		} else if (msg.contains("text=Save")) {
			if (this.filename == null) {
				this.savePrompt();
			}
			this.save();
		}
	}
}
