import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;

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;

/**
 * Panel to draw the graphics
 * 
 * @author baekj. Created Apr 7, 2008.
 */
public class DrawingPanel extends JPanel implements ActionListener,
		MouseListener, MouseMotionListener {
	private static final int D_PANEL_HEIGHT = 600;

	private static final int D_PANEL_WIDTH = 600;

	private int buttonRecognizer = 2;

	private int intialX1Line, intialX1LineFirst, intialX2, intialX,
			intialXLine, intialX1;

	private int intialY1Line, intialY1LineFirst, intialY2, intialY,
			intialYLine, intialY1;

	private int x, q = 0;

	private Ellipse2D.Double firstCircle;

	private int subFunctionCode = 0;

	private ArrayList<Shape> arr = new ArrayList<Shape>();

	private ArrayList<Ellipse2D.Double> arrLine = new ArrayList<Ellipse2D.Double>();
	
	private ArrayList<Integer> arrUndo = new ArrayList<Integer>();
	
	private ArrayList<Point2D.Double> arrCoord = new ArrayList<Point2D.Double>();

	private static final double RADIUS = 5;

	private ArrayList<Color> arrColor = new ArrayList<Color>();

	private double pencilX1, pencilX2, pencilY1, pencilY2;

	private double brushX1, brushY1, brushX2, brushY2;

	private double sprayX1, sprayY1, sprayX2, sprayY2;
	
	private Color colorchanger;
	
	private int counterForSpray=0;

	/**
	 * creates a drawing panel that draws the graphics
	 * 
	 */
	public DrawingPanel() {
		super();
		this.setBackground(Color.WHITE);
		this.setSize(D_PANEL_WIDTH, D_PANEL_HEIGHT);
		this.setPreferredSize(new Dimension(D_PANEL_WIDTH, D_PANEL_HEIGHT));
		this.setVisible(true);
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
	}

	/**
	 * Resets the array which repaints the graphics.
	 *
	 */
	public void clearImage(){
		this.arr.clear();
		this.arrColor.clear();
		this.arrCoord.clear();
		this.resize(600,601);
		this.resize(601,601);
		//this.resetKeyboardActions();
		//System.out.println(this.arr.isEmpty());
		
	}

	/**
	 * cancels the last operation.
	 *
	 */
	public void undo(){
		int size = this.arr.size();
		int limit = this.arrUndo.get(this.arrUndo.size()-1);
		
		
		
		for(int i = size;i > limit;i--)
		{
			this.arr.remove(i-1);
			this.arrColor.remove(i-1);
		}
		
		this.resize(600,601);
		this.resize(601,601);
		
		
		
	}
	/**
	 * Returns the button rec number.
	 *
	 * @return the button recognization number.
	 */
	// Circle = 1, Pencil = 2, Rectangle = 0, Brush = 4, Polygon = 3.
	
	public int buttonRecReturn() {
		return this.buttonRecognizer;
	}

	/**
	 * Used in choosing which writing tool to use.
	 *
	 * @param buttonRec sent from WritingTools panel.
	 */
	public void buttonRecChanger(int buttonRec) {
		this.buttonRecognizer = buttonRec;
	}

	/**
	 * Selects which one of the brush to use.
	 * 
	 * @param sub sent from the SubFunctionClass.
	 */
	public void setSubFunctionCode(int sub) {
		this.subFunctionCode = sub;
	}

	/**
	 * Sets the color.
	 * 
	 * @param color color from the colorselection panel.
	 */
	public void colorChanger(Color color) {
		this.colorchanger = color;
	}

	public void actionPerformed(ActionEvent arg0) {

	}

	public void mouseClicked(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {

	}

	public void mousePressed(MouseEvent e) {
		if(this.buttonRecognizer==0||this.buttonRecognizer==1){
			this.intialX = e.getX();
			this.intialY = e.getY();
		}
		
		// for pencil
		if (this.buttonRecognizer == 2) {
			this.pencilX1 = e.getX();
			this.pencilY1 = e.getY();
		}
		if (this.buttonRecognizer == 4) {
			this.brushX1 = e.getX();
			this.brushY1 = e.getY();
		}
		if(this.buttonRecognizer == 5){
			this.sprayX1 = e.getX();
			this.sprayY1 = e.getY();
		}

		if (this.buttonRecognizer == 3) {
			// x++;
			// q++;
			if (this.x == 0) {
				this.intialX1LineFirst = e.getX();
				this.intialY1LineFirst = e.getY();
			}
			this.firstCircle = new Ellipse2D.Double(this.intialX1LineFirst
					- RADIUS, this.intialY1LineFirst - RADIUS, 2 * RADIUS,
					2 * RADIUS);
			this.intialX1Line = e.getX();
			this.intialY1Line = e.getY();
			System.out.println(this.intialX1Line);
			System.out.println(this.intialY1Line);

			//			
			// this.repaint();

		}

	}

	public void mouseReleased(MouseEvent e) {
		// rectangle
		if (this.buttonRecognizer == 0) {
			if (e.getX() > this.intialX && e.getY() < this.intialY) {
				this.arr.add(new Rectangle2D.Double(this.intialX, e.getY(),
						Math.abs(this.intialX - e.getX()), Math
								.abs(this.intialY - e.getY())));
				this.arrColor.add(this.colorchanger);
			}
			if (this.intialX > e.getX() && e.getY() < this.intialY) {
				this.arr.add(new Rectangle2D.Double(e.getX(), e.getY(), Math
						.abs(this.intialX - e.getX()), Math.abs(this.intialY
						- e.getY())));
				this.arrColor.add(this.colorchanger);
			}
			if (this.intialX > e.getX() && this.intialY < e.getY()) {
				this.arr.add(new Rectangle2D.Double(e.getX(), this.intialY, Math
						.abs(this.intialX - e.getX()), Math.abs(this.intialY
						- e.getY())));
				this.arrColor.add(this.colorchanger);
			}
			if (e.getX() > this.intialX && this.intialY < e.getY()) {
				this.arr.add(new Rectangle2D.Double(this.intialX, this.intialY, Math
						.abs(this.intialX - e.getX()), Math.abs(this.intialY
						- e.getY())));
				this.arrColor.add(this.colorchanger);
			}
			// System.out.println(e.getX());
			// System.out.println(e.getY());
			this.arrUndo.add(this.arr.size()-1);
			this.repaint();
		}
		// circle
		if (this.buttonRecognizer == 1) {
			if (e.getX() > this.intialX && e.getY() < this.intialY) {
				this.arr.add(new Ellipse2D.Double(this.intialX, e.getY(), Math
						.abs(this.intialX - e.getX()), Math.abs(this.intialY
						- e.getY())));
				this.arrColor.add(this.colorchanger);
			}
			if (this.intialX > e.getX() && e.getY() < this.intialY) {
				this.arr.add(new Ellipse2D.Double(e.getX(), e.getY(), Math
						.abs(this.intialX - e.getX()), Math.abs(this.intialY
						- e.getY())));
				this.arrColor.add(this.colorchanger);
			}
			if (this.intialX > e.getX() && this.intialY < e.getY()) {
				this.arr.add(new Ellipse2D.Double(e.getX(), this.intialY, Math
						.abs(this.intialX - e.getX()), Math.abs(this.intialY
						- e.getY())));
				this.arrColor.add(this.colorchanger);
			}
			if (e.getX() > this.intialX && this.intialY < e.getY()) {
				this.arr.add(new Ellipse2D.Double(this.intialX, this.intialY,
						Math.abs(this.intialX - e.getX()), Math
								.abs(this.intialY - e.getY())));
				this.arrColor.add(this.colorchanger);
			}
			this.arrUndo.add(this.arr.size()-1);
			this.repaint();

		}
		//polygon
		if (this.buttonRecognizer == 3) {
			this.x++;
			this.q++;
			this.intialXLine = e.getX();
			this.intialYLine = e.getY();
			this.arrLine.add(new Ellipse2D.Double(this.intialXLine - RADIUS,
					this.intialYLine - RADIUS, 2 * RADIUS, 2 * RADIUS));
			this.arr.add(new Line2D.Double(this.intialX1Line, this.intialY1Line,
					this.intialXLine, this.intialYLine));

			if (Math.sqrt(Math.pow((this.firstCircle.getX() - this.arrLine.get(
					this.arrLine.size() - 1).getX()), 2)
					+ Math.pow((this.firstCircle.getY() - this.arrLine.get(
							this.arrLine.size() - 1).getY()), 2)) < (this.firstCircle
					.getHeight() / 2 + this.arrLine.get(this.arrLine.size() - 1)
					.getHeight() / 2)) {
				this.x = 0;
				this.q = 0;
				System.out.println(this.x);
				System.out.println(this.q);
			}

			this.repaint();
		}
	}

	@Override
	public void paintComponent(Graphics g) {

		Graphics2D g2 = (Graphics2D) g;
		//polygon
		if (this.buttonRecognizer == 3) {

			System.out.println("x" + this.x);
			System.out.println("q" + this.q);
			//
			//			
			for (this.q = 1; this.q < this.arrLine.size(); this.q++) {
				g2.fill(this.arrLine.get(this.q));
				//
				//				
				g2.draw(new Line2D.Double(this.arrLine.get(this.q).getX() + RADIUS,
						this.arrLine.get(this.q).getY() + RADIUS, this.arrLine.get(this.q - 1)
								.getX()
								+ RADIUS, this.arrLine.get(this.q - 1).getY() + RADIUS));
				//				
			}
			// this.repaint();
			//			
			if (this.x <= 1) {
				for (int i = 0; i < this.arr.size(); i++) {
					g2.draw(this.arr.get(i));
				}
			}
			g2.fill(this.firstCircle);
			this.repaint();
		}
		else{
			
			for (int i = 0; i < this.arr.size(); i++) {
				if(this.arr.get(i).equals(new Ellipse2D.Double(1, 1, 200, 200))){
					g2.setColor(this.arrColor.get(i));
					for(int j =0 ; j< 33;j++){
						g2.draw(new Line2D.Double(
								(this.arrCoord.get(this.counterForSpray).x -5) + (5*Math.random()) 
								,(this.arrCoord.get(this.counterForSpray).y -5) + (5 * Math.random())
								,(this.arrCoord.get(this.counterForSpray).x -5) + (5*Math.random())
								,(this.arrCoord.get(this.counterForSpray).y -5) + (5 * Math.random())));
					}
					
					this.counterForSpray ++;
				}
				else{
				g2.setColor(this.arrColor.get(i));
				g2.draw(this.arr.get(i));
				this.repaint();
				}
			}
		}
	}

	public void mouseDragged(MouseEvent arg0) {
		//spray paint
		if (this.buttonRecognizer == 5) {

			this.sprayX2 = arg0.getX();
			this.sprayY2 = arg0.getY();

			Line2D.Double line = new Line2D.Double(this.sprayX1, this.sprayY1,
					this.sprayX2, this.sprayY2);

			double diffX = -line.getX1() + line.getX2();
			double diffY = -line.getY1() + line.getY2();
			double diff = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2));
			double remainder = diff % ((int) diff);

			int num = (int) diff;
			if (remainder > 0.5) {
				num++;
			}
			double num1 = (num * 3);

			double xNum = diffX / num1;
			double yNum = diffY / num1;

			double xCoord = line.getX1();
			double yCoord = line.getY1();
			this.arrUndo.add(this.arr.size());
			for (int i = 0; i < num1; i++) {
				xCoord = xCoord + xNum;
				yCoord = yCoord + yNum;
				
				
			this.arr.add(new Ellipse2D.Double(1, 1, 200, 200));
			this.arrCoord.add(new Point2D.Double(xCoord,yCoord));
			this.arrColor.add(this.colorchanger);
			}}
		// pencil
		if (this.buttonRecognizer == 2) {
			this.pencilX2 = arg0.getX();
			this.pencilY2 = arg0.getY();
			this.arr.add(new Line2D.Double(this.pencilX1, this.pencilY1,
					this.pencilX2, this.pencilY2));
			this.arrColor.add(this.colorchanger);
			this.arrUndo.add(this.arr.size()-1);
			this.repaint();
			this.pencilX1 = this.pencilX2;
			this.pencilY1 = this.pencilY2;
		}
		// brush
		if (this.buttonRecognizer == 4) {

			this.brushX2 = arg0.getX();
			this.brushY2 = arg0.getY();

			Line2D.Double line = new Line2D.Double(this.brushX1, this.brushY1,
					this.brushX2, this.brushY2);

			double diffX = -line.getX1() + line.getX2();
			double diffY = -line.getY1() + line.getY2();
			double diff = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2));
			double remainder = diff % ((int) diff);

			int num = (int) diff;
			if (remainder > 0.5) {
				num++;
			}
			double num1 = (num * 3);

			double xNum = diffX / num1;
			double yNum = diffY / num1;

			double xCoord = line.getX1();
			double yCoord = line.getY1();
			this.arrUndo.add(this.arr.size());
			for (int i = 0; i < num1; i++) {
				xCoord = xCoord + xNum;
				yCoord = yCoord + yNum;
				// circles
				if (this.subFunctionCode == 0) {
					this.arr.add(new Ellipse2D.Double(xCoord, yCoord, .5, .5));
					this.arrColor.add(this.colorchanger);
				} else if (this.subFunctionCode == 1) {
					this.arr.add(new Ellipse2D.Double(xCoord, yCoord, 3, 3));
					this.arrColor.add(this.colorchanger);
				} else if (this.subFunctionCode == 2) {
					this.arr.add(new Ellipse2D.Double(xCoord, yCoord, 5, 5));
					this.arrColor.add(this.colorchanger);
				}
				// squares
				else if (this.subFunctionCode == 3) {
					this.arr
							.add(new Rectangle2D.Double(xCoord, yCoord, .5, .5));
					this.arrColor.add(this.colorchanger);
				} else if (this.subFunctionCode == 4) {
					this.arr.add(new Rectangle2D.Double(xCoord, yCoord, 3, 3));
					this.arrColor.add(this.colorchanger);
				} else if (this.subFunctionCode == 5) {
					this.arr.add(new Rectangle2D.Double(xCoord, yCoord, 5, 5));
					this.arrColor.add(this.colorchanger);
				}
				// right 45degrees slanted lines
				else if (this.subFunctionCode == 6) {
					this.arr.add(new Line2D.Double(xCoord + .5, yCoord + .5,
							xCoord - 0.5, yCoord - 0.5));
					this.arrColor.add(this.colorchanger);
				} else if (this.subFunctionCode == 7) {
					this.arr.add(new Line2D.Double(xCoord + 3, yCoord + 3,
							xCoord - 3, yCoord - 3));
					this.arrColor.add(this.colorchanger);
				} else if (this.subFunctionCode == 8) {
					this.arr.add(new Line2D.Double(xCoord + 5, yCoord + 5,
							xCoord - 5, yCoord - 5));
					this.arrColor.add(this.colorchanger);
				}
				// left 45degrees slanted lines
				else if (this.subFunctionCode == 9) {
					this.arr.add(new Line2D.Double(xCoord - .5, yCoord - .5,
							xCoord + 0.5, yCoord + 0.5));
					this.arrColor.add(this.colorchanger);
				} else if (this.subFunctionCode == 10) {
					this.arr.add(new Line2D.Double(xCoord - 3, yCoord - 3,
							xCoord + 3, yCoord + 3));
					this.arrColor.add(this.colorchanger);
				} else if (this.subFunctionCode == 11) {
					this.arr.add(new Line2D.Double(xCoord - 3, yCoord - 3,
							xCoord + 3, yCoord + 3));
					this.arrColor.add(this.colorchanger);
				}
			}
		}
		this.repaint();
		this.brushX1 = this.brushX2;
		this.brushY1 = this.brushY2;
	}

	public void mouseMoved(MouseEvent arg0) {

	}

}
