import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;


/**
 * This is the canvas that will be drawn on.
 *
 * @author Annmarie Stanley and Hannah Chadd
 *         Created Apr 4, 2008.
 */
public class CanvasPanel extends JPanel implements MouseListener, MouseMotionListener, ActionListener{

	private ShapeInfo shape;
	private double x;
	private double y;
	private double x2;
	private double y2;
	private Point2D.Double pt1;
	private Point2D.Double pt2;
	private double width;
	private double height;
	private static int type;

	/** An array of ShapeInfos to store data */
	public ArrayList<ShapeInfo> shapeList = new ArrayList<ShapeInfo>();
	private static int color;
	private Point2D.Double beginPt = new Point2D.Double(0.0, 0.0);
	/** Creates the actual panel */
	public CanvasPanel() {
		this.setBackground(Color.WHITE);
		
		// Setting a border for the panel		
		LineBorder bord = new LineBorder(Color.BLACK);
		this.setBorder(bord);
		
	}
	
	/**
	 * 
	 * Changes the type according to the drawing button pressed.
	 *
	 * @param i
	 */
	public static void changeButton(int i) {
		type = i;
}

	/**
	 * 
	 * Changes the color according to the color button pressed.
	 *
	 * @param i
	 */
	public static void changeColor(int i) {
		color = i;
	}


	public void mouseClicked(MouseEvent e) {
		// Empty
		
	}

	public void mouseEntered(MouseEvent e) {
		// Empty
	}

	public void mouseExited(MouseEvent e) {
		// Empty
	}
    
	public void mousePressed(MouseEvent e) {	
		if (type != 6) {
		this.x = e.getX();
		this.y = e.getY();
		this.pt1 = new Point2D.Double(this.x, this.y);
		}
		else if (polyButton.state == 1) {
			this.x = e.getX();
			this.y = e.getY();
			this.pt1 = new Point2D.Double(this.x, this.y);
			this.beginPt = this.pt1;
		}
	}
	
	public void mouseDragged(MouseEvent arg0) {
		if (type == 3 || type == 4 || type == 9 || type == 10){
			this.x2 = arg0.getX();
			this.y2 = arg0.getY();
			this.pt2 = new Point2D.Double(this.x2, this.y2);
			this.width = this.pt2.distance(this.pt1);
			this.height = this.pt2.distance(this.pt1);
			if (type == 9) {color = 11;}
			if (this.shapeList.size() > 0) {
			if (this.shapeList.get(this.shapeList.size()-1).type == 9 && type != 9) {color = 0;}}
			this.shape = new ShapeInfo(this.pt1, this.pt2, this.width, this.height, type, color);
			this.shapeList.add(this.shape);
			this.pt1 = this.pt2;
		}
		repaint();
	}



	public void mouseReleased(MouseEvent e) {
		
		this.x2 = e.getX();
		this.y2 = e.getY();
		this.pt2 = new Point2D.Double(this.x2, this.y2);
		this.width = this.pt2.distance(this.pt1);
		this.height = this.pt2.distance(this.pt1);
		this.shape = new ShapeInfo(this.pt1, this.pt2, this.width, this.height, type, color);
		this.shapeList.add(this.shape);
		
		if (type == 6) {			
			if (polyButton.state == 1) {
				polyButton.state = 0;
			}
			
			else if (polyButton.state == 0) {
				if (this.pt2.distance(this.beginPt) < 5) {
					// Note: Made this measure a distance of 5 between the first point 
					// and the final point for each polygon instead of forcing
					// the user to click the exact same point, which we thought
					// would be difficult. In the GUI, the distance is so small as 
					// to seem negligible.
					this.pt1 = null;
					this.beginPt = null;
					polyButton.state = 1;				
			}
			this.pt1 = this.pt2;
		}
			
			else {
				polyButton.state = 1;
			}	
		}
		this.repaint();
	}
	
	public void mouseMoved(MouseEvent arg0) {
		// Empty
		
	}



	public void actionPerformed(ActionEvent e) {
		// Empty
		
	}
	
	
	/**
	 * Draws the canvas again
	 *
	 * @param g the Graphics object onto which to draw.
	 */
	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);

		Graphics2D graphics = (Graphics2D) g;
	
		

		if (this.shapeList.size() > 0) {
			for (int i = 0; i <= this.shapeList.size()-1; i++) {
				switch (this.shapeList.get(i).type) {
				
//				Oval
				case 1: 		{	
					double x, y, width, height;
					x = this.shapeList.get(i).pt1.getX();
					y = this.shapeList.get(i).pt1.getY();
					width = Math.abs(this.shapeList.get(i).pt1.getX() - this.shapeList.get(i).pt2.getX());
					height = Math.abs(this.shapeList.get(i).pt1.getY() - this.shapeList.get(i).pt2.getY());
					if ((this.shapeList.get(i).pt1.getX() - this.shapeList.get(i).pt2.getX()) > 0 && 
							(this.shapeList.get(i).pt1.getY() - this.shapeList.get(i).pt2.getY()) < 0) {
						x = (this.shapeList.get(i)).pt1.getX() - width;	
						y = (this.shapeList.get(i)).pt1.getY();
					}
					
					
					else if ((this.shapeList.get(i).pt1.getY() - this.shapeList.get(i).pt2.getY()) > 0 && 
							(this.shapeList.get(i).pt1.getX() - this.shapeList.get(i).pt2.getX()) < 0) {
						x = (this.shapeList.get(i)).pt2.getX() - width;
						y = (this.shapeList.get(i)).pt2.getY();
					}
					
					else if ((this.shapeList.get(i).pt1.getY() - this.shapeList.get(i).pt2.getY()) > 0 && 
							(this.shapeList.get(i).pt1.getX() - this.shapeList.get(i).pt2.getX()) > 0) {
						x = (this.shapeList.get(i)).pt2.getX();
						y = (this.shapeList.get(i)).pt2.getY();
					}

					Ellipse2D.Double circ = new Ellipse2D.Double(x, y, width, height);
					graphics.draw(circ);
				}
				break;
//			Rectangle
				case 2:{
					
					double x, y, width, height;
					x = this.shapeList.get(i).pt1.getX();
					y = this.shapeList.get(i).pt1.getY();
					width = Math.abs(this.shapeList.get(i).pt1.getX() - this.shapeList.get(i).pt2.getX());
					height = Math.abs(this.shapeList.get(i).pt1.getY() - this.shapeList.get(i).pt2.getY());

					if (this.shapeList.get(i).pt1.getX() - this.shapeList.get(i).pt2.getX() > 0 && 
							this.shapeList.get(i).pt1.getY() - this.shapeList.get(i).pt2.getY() < 0) {
						x = (this.shapeList.get(i)).pt1.getX() - width;	
						y = (this.shapeList.get(i)).pt1.getY();
					}
					
					
					else if ((this.shapeList.get(i).pt1.getY() - this.shapeList.get(i).pt2.getY()) > 0 && 
							(this.shapeList.get(i).pt1.getX() - this.shapeList.get(i).pt2.getX()) < 0) {
						x = (this.shapeList.get(i)).pt2.getX() - width;
						y = (this.shapeList.get(i)).pt2.getY();
					}
					
					else if ((this.shapeList.get(i).pt1.getY() - this.shapeList.get(i).pt2.getY()) > 0 && 
							(this.shapeList.get(i).pt1.getX() - this.shapeList.get(i).pt2.getX()) > 0) {
						x = (this.shapeList.get(i)).pt2.getX();
						y = (this.shapeList.get(i)).pt2.getY();
					}
					
					Rectangle2D.Double rect = new Rectangle2D.Double(x, y, width, height);			
					graphics.draw(rect);
				}
				break;
				
				//Pencil
				case 3: {
					
					Line2D.Double lin = new Line2D.Double(this.shapeList.get(i).pt1, this.shapeList.get(i).pt2);
					graphics.draw(lin);
				}
				break;
			
				//Brush
				case 4: {
					Ellipse2D.Double circ = new Ellipse2D.Double(this.shapeList.get(i).pt1.x, this.shapeList.get(i).pt1.y, 15.0, 15.0);
					graphics.fill(circ);
					graphics.draw(circ);
				}
				break;
				
				//Fill
//				case 5: {
//					
//				}
//				break;
				
				//Polygon
				case 6: {
					if (polyButton.state == 1) {
						Line2D.Double line = new Line2D.Double(this.shapeList.get(i).pt1, this.shapeList.get(i).pt2);
						graphics.draw(line);
						}
					else if (polyButton.state == 0) {
						Line2D.Double line = new Line2D.Double(this.shapeList.get(i).pt1, this.shapeList.get(i).pt2);
						graphics.draw(line);
					}
				}

				break;
				
				// Undo
				case 7: {
					
//					Shape shape;
//					double x = this.shapeList.get(this.shapeList.size()).pt1.x;
//					double y = this.shapeList.get(this.shapeList.size()).pt1.y;
//					double height = this.shapeList.get(this.shapeList.size()).height;
//					double width = this.shapeList.get(this.shapeList.size()).width;
//					shape = new Ellipse2D.Double(x, y, height, width);
//					if (this.shapeList.get(this.shapeList.size()).type == 1) {
//						shape = new Ellipse2D.Double(x, y, height, width);
//					}
//					else if (this.shapeList.get(this.shapeList.size()).type == 2) {
//						shape = new Rectangle2D.Double(x, y, height, width);
//					}
//					else if (this.shapeList.get(this.shapeList.size()).type == 8) {
//						shape = new Line2D.Double(this.shapeList.get(this.shapeList.size()).pt1, this.shapeList.get(this.shapeList.size()).pt2);
//					}
//					
//					System.out.println("size of shapeList: " + this.shapeList.size());
//					graphics.draw(shape);
//					
//					
//					System.out.println("undo started");
//					System.out.println("removing size-1: "+ this.shapeList.get(this.shapeList.size()-1).toString() );
//					//this.shapeList.remove(this.shapeList.size()-1);
//					this.shapeList.get(i).pt1 = null;
//					this.shapeList.get(i).pt2 = null;
//					i--;
//					this.repaint();
					
				}
				break;
//				Line
				case 8: {
					Line2D.Double line = new Line2D.Double(this.shapeList.get(i).pt1, this.shapeList.get(i).pt2);
					graphics.draw(line);
				}
				break;
				
				//Eraser
				case 9: {
					Ellipse2D.Double circ = new Ellipse2D.Double(this.shapeList.get(i).pt1.x, this.shapeList.get(i).pt1.y, 15.0, 15.0);
					this.shapeList.get(i).nowColor = Color.WHITE;
					graphics.setColor(this.shapeList.get(i).nowColor);
					graphics.fill(circ);
					graphics.draw(circ);
				}
				break;
				
				//Spraypaint
				case 10: {
					Point2D.Double[] pts = new Point2D.Double[100];
					for (int k = 0; k <= 25; k++) {
						pts[k] = new Point2D.Double(Math.random() * 5 * 2 * Math.PI + this.shapeList.get(i).pt1.x, Math.random() * 5 * 2 * Math.PI + this.shapeList.get(i).pt1.y);
						Ellipse2D.Double ptToDraw = new Ellipse2D.Double(pts[k].x, pts[k].y, 1.0, 1.0);
						graphics.draw(ptToDraw);
					}
				}
				break;
				
				default:{
					// Do nothing
					
				}
				break;
				}
				graphics.setColor(this.shapeList.get(i).nowColor);
				if (this.shapeList.size()-1 > i ) {
					graphics.setColor(this.shapeList.get(i+1).nowColor);
				}
				this.repaint();

	}
	}
}
}

