import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

/**
 * TODO Put here a description of what this class does.
 *
 * @author ian.
 *         Created Mar 22, 2008.
 */
public class Paint extends JFrame implements ActionListener, ListSelectionListener, KeyListener, ComponentListener{
	/**
	 * This is the space that all of the drawing exists on
	 */
	Canvas canvas;
	/**
	 * the is the color chooser menu for the toolbar window
	 */
	JColorChooser cc;
	/**
	 * this is the menu bar for the JPaint window
	 */
	JMenuBar mb;
	/**
	 * this is the Frame that holds all of the tool elements
	 */
	JFrame toolPallet;
	/**
	 * This is a list of all of the tools that are on the tool window
	 */
	ArrayList<Brush> brush=new ArrayList<Brush>();
	/**
	 * this is the file chooser menu for opening and saving
	 */
	JFileChooser fc;
	/**
	 * This is the button for making brushes for a picture file
	 */
	JButton makeBrush;
	/**
	 * this holds the button for custom brushes
	 */
	JPanel buttons;
	/**
	 * this holds the tools list
	 */
	JPanel tools;
	/**
	 * this is the pane that hols the list of tools
	 */
	JScrollPane brushlist;
	/**
	 * this allows the scroll bar on the Jpaint window
	 */
	JScrollPane imageviewer;
	/**
	 * this is the horizontal scroll bar
	 */
	JScrollBar imageX;
	/**
	 * this is the vertical scroll bar
	 */
	JScrollBar imageY;
	/**
	 * this scroll bar for the list of brushes
	 */
	JScrollBar brushscroller;
	/**
	 * the view area fro JPaint
	 */
	JViewport b;
	/**
	 * this is the slider that allows tolerance for magic wand and paintbucket
	 */
	JSlider tolerance;
	/**
	 * the actual list of brushes
	 */
	JList brushes;
	/**
	 * the window for JPaint
	 */
	JFrame frame;
	/**
	 * this grid for the JPaint window
	 */
	GridBagLayout l;
	/**
	 * the name of brushes
	 */
	JTextField name;
	/**
	 * the Edit menu
	 */
	JMenu edit = new JMenu("edit");
	/**
	 * the File menu
	 */
	JMenu file = new JMenu("file");
	/**
	 * the View menu
	 */
	JMenu view = new JMenu("view");
	/**
	 * the undo command
	 */
	JMenuItem undo = new JMenuItem("Undo");

	JMenuItem redo = new JMenuItem("Redo");
	/**
	 *the new JPaint wwindow command
	 */
	JMenuItem New = new JMenuItem("New");
	/**
	 *the save command
	 */
	JMenuItem save = new JMenuItem("Save");
	/**
	 * the open command
	 */
	JMenuItem open = new JMenuItem("Open");
	/**
	 * the deslect pixels command
	 */
	JMenuItem deselect = new JMenuItem("Deselect All");
	/**
	 * the exit program command
	 */
	JMenuItem exit = new JMenuItem("Exit");
	/**
	 * the command to bring back the toolbar window
	 */
	JMenuItem showTools = new JMenuItem("show Tools");
	/**
	 * the text field for naming files in x direction
	 */
	JTextField X;
	/**
	 * the text field for naming files  in y direction
	 */
	JTextField Y;
	/**
	 * the zoom fuction declaration
	 */
	/**
	 * the constructor for Paint
	 *
	 * @param w window width
	 * @param h window height
	 */
	public Paint(int w, int h){
		super("JPaint");
		this.l = new GridBagLayout();
		this.addKeyListener(this);
		this.setSize(w,h+50);
		this.mb=new JMenuBar();
		this.edit.add(this.undo);
		this.setJMenuBar(this.mb);
		//this.undo.addActionListener(this);
		this.undo.setToolTipText("Undo the previuous action");
		this.undo.setMnemonic('u');
		this.undo.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent e){
				undo(e);
			}
		});
		//this.redo.addActionListener(this);
		this.redo.setToolTipText("Redo the previuously undone action");
		this.redo.setMnemonic('r');
		this.redo.addMouseListener(new MouseAdapter(){
			public void mousePressed(MouseEvent e){
				redo(e);
			}
		});
		this.open.setMnemonic('o');
		this.open.setToolTipText("Open a new image");
		this.open.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent e){
				openFile(e);
			}
		});
		this.save.setMnemonic('s');
		this.save.setToolTipText("Save the Current image as a png");
		this.save.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent e){
				saveFile(e);
			}
		});
		this.exit.setMnemonic('x');
		this.exit.setToolTipText("Exits the program");
		this.exit.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent e){
				exitProgram(e);
			}
		});
		this.New.setMnemonic('N');
		this.New.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent e){
				newCanvas(e);
			}
		});
		this.New.setToolTipText("Create a new Image");
		this.showTools.setMnemonic('t');
		this.showTools.setToolTipText("Show the tools pallet");
		this.showTools.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent e){
				showTools(e);
			}
		});
		this.deselect.setToolTipText("deselect currently selected pixels");
		this.deselect.setMnemonic('d');
		this.deselect.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent e){
				deselectAll(e);
			}
		});
		this.file.setMnemonic('f');
		this.edit.setMnemonic('e');
		this.view.setMnemonic('v');
		this.mb.setVisible(true);
		this.mb.add(this.file);
		this.mb.add(this.edit);
		this.mb.add(this.view);
		this.file.add(this.New);
		this.file.add(this.save);
		this.file.add(this.open);
		this.file.add(this.exit);
		this.view.add(this.showTools);
		this.edit.add(this.redo);
		this.edit.add(this.deselect);
		//This is our tool list
		this.brush.add(new MoverTool());
		this.brush.add((new EllipseFillTool()));
		this.brush.add((new EllipseTool()));
		this.brush.add(new EyeDropperTool());
		this.brush.add((new PaintBucketTool()));
		this.brush.add((new EllipseSelectTool()));
		this.brush.add((new RectangleSelectTool()));
		this.brush.add((new MagicWandTool()));
		this.brush.add((new RectangleFillTool()));
		this.brush.add((new RectangleTool()));
		this.brush.add((new PolygonTool()));
		this.brush.add((new PolygonFillTool()));
		this.brush.add(new Brush(40,new File("smile.PNG"),"Fuzzy Circle(alpha)"));
		for(int i=8;i<=30;i+=2){
			this.brush.add(new Brush(i,new File("circle"+i+".bmp"),"Circle "+i));
		}
		for(int i=1;i<=15;i++){
			this.brush.add(new Brush(i));
		}
		
		
		this.canvas = new Canvas(800,600,this,this.brush.get(13));
		this.imageX=new JScrollBar();
		this.imageY=new JScrollBar();
		this.imageviewer= new JScrollPane();
		this.imageviewer.add(this.canvas);
		this.b = new JViewport();
		this.b.add(this.canvas);
		this.b.setPreferredSize(new Dimension(800,650));
		this.imageviewer.setViewport(this.b);
		//this.add(this.canvas);
		this.add(this.imageviewer);
		
		
		this.tolerance=new JSlider();
		this.tolerance.setMaximum(50);
		this.tolerance.setMinimum(0);
		this.tolerance.setName("Tolerance");
		//BasicSliderUI ui = new BasicSliderUI(this.tolerance);
		//ui.paintTicks()
		this.tolerance.setPaintTrack(true);
		this.tolerance.setMajorTickSpacing(25);
		this.tolerance.setMajorTickSpacing(5);
		this.tolerance.setValue(10);
		this.tolerance.setToolTipText("Sets Tolerance for Paint Bucket and Magic  Wand Tools");
		this.tolerance.setPaintTicks(true);
		this.tolerance.setPaintLabels(true);
		this.brushes = new JList();
		this.buttons = new JPanel();
		this.tools=new JPanel();
		this.makeBrush=new JButton("new");
		this.makeBrush.setToolTipText("Creates a Brush from an Image preferably square");
		this.makeBrush.addMouseListener(new MouseAdapter(){
			@Override
			public void mouseClicked(MouseEvent e){
				makebrush(e);
			}
		});
		this.buttons.setLayout(this.l);
		this.cc=new JColorChooser();
		this.cc.setSize(400,400);
		this.toolPallet=new JFrame("Tools");
		this.toolPallet.setVisible(true);
		this.tools.add(this.cc);
		this.brushscroller=new JScrollBar();
		this.brushlist=new JScrollPane();
		this.brushlist.add(this.brushes);
		this.brushes.setVisibleRowCount(5);
		this.brushscroller.setSize(20,100);
		this.brushlist.setVerticalScrollBar(this.brushscroller);
		JViewport a = new JViewport();
		a.add(this.brushes);
		a.setPreferredSize(new Dimension(100,160));
		this.brushlist.setViewport(a);
		this.buttons.add(this.brushlist);
		this.buttons.add(this.tolerance);
		this.buttons.add(this.makeBrush);
		this.buttons.setLayout(new GridLayout(3,1));
		this.tools.add(this.buttons);
		this.toolPallet.add(this.tools);
		this.toolPallet.pack();
		this.cc.setColor(Color.red);
		this.canvas.addMouseListener(this.canvas);
		this.canvas.addMouseMotionListener(this.canvas);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setBackground(Color.white);
		this.setVisible(true);
		this.setSize(815,655);
		this.brushes.setListData(this.brush.toArray());
		this.brushes.setSelectedIndex(13);
		this.brushes.addListSelectionListener(this);
		this.toolPallet.setAlwaysOnTop(true);
		this.toolPallet.setDefaultCloseOperation(HIDE_ON_CLOSE);
		this.addComponentListener(this);
	}
	
	/**
	 * 
	 * Creates a new brush to be selected from the list.
	 *
	 * @param e
	 */
	public void makebrush(MouseEvent e){
		this.fc=new JFileChooser();
		JPanel p = new JPanel();
		this.name = new JTextField();
		this.name.setColumns(20);
		this.frame = new JFrame("File Selection");
		p.add(this.fc);
		p.add(this.name);
		this.frame.add(p);
		this.frame.pack();
		this.frame.setAlwaysOnTop(true);
		this.frame.setVisible(true);
		this.fc.addActionListener(this);
		this.fc.setVisible(true);
	}
	
	public void actionPerformed(ActionEvent arg0) {
		if(arg0.getSource().equals(this.fc)){
			if(arg0.getActionCommand().equals("ApproveSelection")){
				File F = this.fc.getSelectedFile();
				BufferedImage b =null;
				try {
				b =javax.imageio.ImageIO.read(F);
				}
				catch(IOException e){
					//
				}
				if(b!=null){
					if(this.name.getText().equals("")){
						JDialog d = new JDialog();
						d.setAlwaysOnTop(true);
						JLabel l = new JLabel("select a name");
						d.add(l);
						l.setFont(new Font("times new roman",Font.BOLD,30));
						l.setAlignmentX(0.5f);
						d.setLocation(400,300);
						d.setSize(300,75);
						d.setVisible(true);
						return;
					}
					this.brushes.setSelectedIndex(13);
					this.brush.add(new Brush(Math.max(b.getWidth(),b.getHeight()),F,this.name.getText()+""));
					this.brushes.setListData(this.brush.toArray());
					this.brushes.repaint();
					this.frame.setVisible(false);
					this.canvas.setBrush((Brush)this.brushes.getSelectedValue());
					this.canvas.repaint();
					this.toolPallet.repaint();
				}
			}
			if(arg0.getActionCommand().equals("CancelSelection")){
				this.frame.setVisible(false);
			}
		}
	}

	public void valueChanged(ListSelectionEvent arg0) {
		if(this.canvas.getBrush() instanceof PolygonTool){
			((PolygonTool)this.canvas.getBrush()).polyFinish();
		}
		
		if(this.canvas.getBrush() instanceof PolygonFillTool){
			((PolygonFillTool)this.canvas.getBrush()).polyFinish();
		}
		
		this.canvas.setBrush((Brush)this.brushes.getSelectedValue());
		if(this.brushes.getSelectedValue() instanceof PolygonTool){
			this.canvas.setBrush(new PolygonTool());
		}
		if(this.brushes.getSelectedValue() instanceof PolygonFillTool){
			this.canvas.setBrush(new PolygonFillTool());
		}
		
		
		
		
	}
	/**
	 * 
	 * undoes the previous action up to 10 steps back.
	 *
	 * @param e
	 */
	public void undo(MouseEvent e){
		this.canvas.setBack();
		this.canvas.repaint();
	}
	public void redo(MouseEvent e){
		this.canvas.setForward();
		this.canvas.repaint();
	}
	/**
	 * 
	 * creates a new dialog to open a file.
	 *
	 * @param e
	 */
	public void openFile(MouseEvent e){
		this.fc=new JFileChooser();
		JPanel p = new JPanel();
		this.frame = new JFrame("File Selection");
		p.add(this.fc);
		this.frame.add(p);
		this.frame.pack();
		this.frame.setAlwaysOnTop(true);
		this.frame.setVisible(true);
		this.fc.addActionListener(new opener(this));
		this.fc.setVisible(true);	
	}
	/**
	 * 
	 * creates a new dialog to save a file
	 *
	 * @param e
	 */
	public void saveFile(MouseEvent e){
		this.fc=new JFileChooser();
		JPanel p = new JPanel();
		this.frame = new JFrame("File Selection");
		p.add(this.fc);
		this.frame.add(p);
		this.frame.pack();
		this.frame.setAlwaysOnTop(true);
		this.frame.setVisible(true);
		this.fc.setApproveButtonText("Save");
		this.fc.addActionListener(new saver(this));
		this.fc.setVisible(true);
	}
	/**
	 * 
	 * exits the program
	 *
	 * @param e
	 */
	public void exitProgram(MouseEvent e){
		System.exit(0);
	}
	/**
	 * 
	 * creates a new canvas after new was selected from the file menu
	 *
	 * @param e
	 */
	public void newCanvas(MouseEvent e){
		JPanel p = new JPanel();
		this.frame = new JFrame("New Image");
		JLabel A=new JLabel("Width"),B=new JLabel("Height");
		JButton create = new JButton("OK");
		this.X=new JTextField();
		this.Y=new JTextField();
		this.X.setColumns(5);
		this.Y.setColumns(5);
		create.addMouseListener(new MouseAdapter(){
			@Override
			public void mouseClicked(MouseEvent e){
				create(e);
			}
		});
		p.setLayout(new GridLayout(3,2));
		p.add(A);
		p.add(this.X);
		p.add(B);
		p.add(this.Y);
		p.add(create);
		this.frame.add(p);
		this.frame.pack();
		this.frame.setAlwaysOnTop(true);
		this.frame.setVisible(true);
		
		
	}
	
	/**
	 * the creation of brush strokes in the Paint window 
	 *
	 * @param e
	 */
	public void create(MouseEvent e){
		int x=0,y=0;
		try{
		this.remove(this.canvas);
		x = Integer.parseInt(this.X.getText());
		y = Integer.parseInt(this.Y.getText());
		this.remove(this.canvas);
		this.canvas = new Canvas(x,y, this,(Brush)this.brushes.getSelectedValue());
		this.b = new JViewport();
		this.b.add(this.canvas);
		this.b.setPreferredSize(new Dimension(x,y));
		this.imageviewer.setViewport(this.b);
		//this.add(this.canvas);
		this.canvas.setBrush((Brush)this.brushes.getSelectedValue());
		this.canvas.addMouseListener(this.canvas);
		this.canvas.addMouseMotionListener(this.canvas);
		//this.setSize(x, y);
		this.repaint();
		}
		catch(IllegalArgumentException err){
			return;
		}
		this.frame.setVisible(false);
	}
	/**
	 * 
	 * Shows the tool pallet window
	 *
	 * @param e
	 */
	public void showTools(MouseEvent e){
		this.toolPallet.setVisible(true);
	}
	/**
	 * 
	 * Starts the program.
	 * @param e 
	 *
	 * 
	 */

	public void deselectAll(MouseEvent e){
		for(int i=0;i<this.canvas.getImage().getWidth();i++){
			for(int j=0;j<this.canvas.getImage().getHeight();j++){
				this.canvas.select(i,j);
			}
		}
		this.canvas.setShape(null);
	}

	
	/**
	 *this class allows a picture file to be opened in Paint
	 *
	 * @author ian
	 *         Created Apr 14, 2008.
	 */
	class opener implements ActionListener {
		/**
		 * the object that is being oepened
		 */
		Paint a;

		/**
		 * The constructor for opener
		 *
		 * @param a
		 */
		public opener(Paint a) {
			this.a = a;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand().equals("ApproveSelection")) {
				BufferedImage b = null;
				try {
					b = javax.imageio.ImageIO.read(this.a.fc.getSelectedFile());
				} catch (IOException err) {
					return;
				}
				this.a.remove(this.a.canvas);
				this.a.canvas = new Canvas(b.getWidth(), b.getHeight(), this.a,(Brush)this.a.brushes.getSelectedValue());
				for (int i = 0; i < b.getWidth(); i++) {
					for (int j = 0; j < b.getHeight(); j++) {
						this.a.canvas.getImage().setRGB(i, j, b.getRGB(i, j));
					}
				}
				this.a.b = new JViewport();
				this.a.b.add(this.a.canvas);
				this.a.b.setPreferredSize(new Dimension(b.getWidth(),b.getHeight()));
				this.a.imageviewer.setViewport(this.a.b);
				//this.a.add(this.a.canvas);
				this.a.canvas.setBrush((Brush)this.a.brushes.getSelectedValue());
				this.a.canvas.addMouseListener(this.a.canvas);
				this.a.canvas.addMouseMotionListener(this.a.canvas);
				//this.a.setSize(b.getWidth(), b.getHeight()+50);
				this.a.repaint();
				this.a.frame.setVisible(false);
			}
			if (e.getActionCommand().equals("CancelSelection")) {
				this.a.frame.setVisible(false);
			}
		}
	}
	/**
	 * the class that allows Paint to save files
	 *
	 * @author Bryan Warner
	 *         Created Apr 14, 2008.
	 */
	class saver implements ActionListener {
		/**
		 * the object being saved
		 */
		Paint a;

		/**
		 * this constructor lets Paint save files
		 *
		 * @param a
		 */
		public saver(Paint a) {
			this.a = a;
		}

		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand().equals("ApproveSelection")) {
				BufferedImage b = null;
				try {
					javax.imageio.ImageIO.write(this.a.canvas.getImage(),
							"png", new File(this.a.fc.getSelectedFile()
									+ ".png"));
				} catch (IOException err) {
					return;
				}
				this.a.frame.setVisible(false);
			}
			if (e.getActionCommand().equals("CancelSelection")) {
				this.a.frame.setVisible(false);
			}
		}
	}
	public void keyPressed(KeyEvent arg0) {
		if(arg0.getKeyCode()==arg0.VK_CONTROL){
			//this.canvas.setZoom(2.0f);
		}
		
	}
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub.
		
	}
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub.
		
	}
	
	/**
	 * This is what causes Paint to run
	 *
	 * @param args
	 */
	public static void main(String args[]){
		/**
		 * the Paint window initializing
		 */
		Paint p = new Paint(800,600);
	}

	public void componentHidden(ComponentEvent e) {
		// TODO Auto-generated method stub.
		
	}

	public void componentMoved(ComponentEvent e) {
		// TODO Auto-generated method stub.
		
	}

	public void componentResized(ComponentEvent e) {
		this.b.setPreferredSize(this.getSize());
		this.imageviewer.setPreferredSize(this.getSize());
		//this.imageviewer.setSize(this.getWidth(),this.getHeight()+50);
		
	}

	public void componentShown(ComponentEvent e) {
		// TODO Auto-generated method stub.
		
	}

}
