import java.awt.Point;
import java.util.Vector;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.BasicStroke;
import java.awt.RenderingHints;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.awt.image.BufferedImage;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import javax.swing.BoxLayout;

/**
 * @author Milan Ruzicka
 *
 */

public class WaterBrush extends Tool {
	private static final long serialVersionUID = 10L;
	
	public float width = 20;
	public float wetness = 0.5f;
	public int hair = 50;
	public int colorAmount = 30;
	
	public int[] brushX;
	public int[] brushY;
	
	final int xSize = 1024;
	final int ySize = 768;


	public WaterBrush() {
		points = new Vector();
		colors = new Vector();
		
		colors.add(new Color(0.0f,0.0f,1.0f,0.2f));
		colors.add(Color.blue);
	}
	
	public WaterBrush(Color c) {
		points = new Vector();
		colors = new Vector();
		
		colors.add(new Color(c.getRed(),c.getGreen(),c.getBlue(),colorAmount));
		colors.add(Color.blue);
	}
	
	
	
	private void generateBrush(){
		float radius = ((float)width) / 2f;		
		brushX = new int[hair];
		brushY = new int[hair];
		for (int i=0; i<hair;i++){

			double angle = Math.random()*2*Math.PI;
			double distance = Math.sqrt(Math.random())*radius;

			brushX[i] = (int)Math.round(Math.sin(angle) * distance);
			brushY[i] = (int)Math.round(Math.cos(angle) * distance);
			
		}
	}

	/* (non-Javadoc)
	 * @see Tool#draw(java.awt.Image)
	 */
	@Override
	
	public void draw(Graphics g1) {
		Graphics2D g2 = (Graphics2D) g1;


//		ConvolveOp Op = new ConvolveOp(new Kernel(3,3,new float[] {0.0f, -1.0f, 0.0f, -1.0f, 4.0f, -1.0f, 0.0f, -1.0f, 0.0f}));
//		ConvolveOp Op = new ConvolveOp(new Kernel(3,3,new float[] {0.1111f, 0.1111f, 0.1111f, 0.1111f, 0.1111f, 0.1111f, 0.1111f, 0.1111f, 0.1111f}));
//		ConvolveOp Op = new ConvolveOp(new Kernel(3,3,new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}));
	//	ConvolveOp Op = new ConvolveOp(new Kernel(3,3,new float[] {0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f}));
	/*	ConvolveOp Op = new ConvolveOp(new Kernel(7,7, new float[] {
		0.00000067f,0.00002292f,0.00019117f,0.00038771f,0.00019117f,0.00002292f,0.00000067f,
		0.00002292f,0.00078633f,0.00655965f,0.01330373f,0.00655965f,0.00078633f,0.00002292f,
		0.00019117f,0.00655965f,0.05472157f,0.11098164f,0.05472157f,0.00655965f,0.00019117f,
		0.00038771f,0.01330373f,0.11098164f,15.22508352f,0.11098164f,0.01330373f,0.00038771f,
		0.00019117f,0.00655965f,0.05472157f,0.11098164f,0.05472157f,0.00655965f,0.00019117f,
		0.00002292f,0.00078633f,0.00655965f,0.01330373f,0.00655965f,0.00078633f,0.00002292f,
		0.00000067f,0.00002292f,0.00019117f,0.00038771f,0.00019117f,0.00002292f,0.00000067f}));*/
		
		
		float sur = (1f-0.8f*(1f-wetness) ) / 24f;
		float cent = 0.8f*(1f-wetness);

		ConvolveOp Op = new ConvolveOp(new Kernel(5,5,new float[] {
			sur, sur, sur, sur, sur,
			sur, sur, sur, sur, sur,
			sur, sur, cent, sur, sur,
			sur, sur, sur, sur, sur,
			sur, sur, sur, sur, sur
		}));
			
		/*ConvolveOp Op = new ConvolveOp(new Kernel(3,3,new float[] {
			0.1f, 0.1f, 0.1f,
			0.1f, 0.1f, 0.1f,
			0.1f, 0.1f, 0.1f
		}));*/
		
		BufferedImage buf = new BufferedImage(xSize,ySize,BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = (Graphics2D)buf.getGraphics();
		Color cc = new Color(1f,1f,1f,0f);	
		for (int i=0; i<xSize; i++)
			for (int j=0; j<ySize;j++){
				buf.setRGB(i, j, cc.getRGB());
			}

		
		Stroke thindashed = new BasicStroke(1f, // line width
			      /* cap style */BasicStroke.CAP_BUTT,
			      /* join style, miter limit */BasicStroke.JOIN_BEVEL, 4.0f);

		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
		 
		g.setStroke(thindashed);
		g.setColor((Color) colors.get(0));
		
		generateBrush();
		
		
		for (int j=0; j<hair; j++){
				
				GeneralPath gp = new GeneralPath();
				for (int i=0; i < points.size()-1;i++) {
					gp.append(new Line2D.Float(new Point( ((Point)points.get(i)).x+brushX[j],((Point)points.get(i)).y+brushY[j]) ,new Point( ((Point)points.get(i+1)).x+brushX[j],((Point)points.get(i+1)).y+brushY[j])) , true);
				}
				g.draw(gp);
			
		}

		
		
		buf = Op.filter(buf, null);
		buf = Op.filter(buf, null);
		buf = Op.filter(buf, null);
		
		g2.drawImage(buf,0,0,xSize,ySize,null);
		
	}
	
	public void setColor(Color c){
		colors.set(0, new Color(c.getRed(),c.getGreen(),c.getBlue(),colorAmount));
	}
	
	public void drawPreview(Graphics g1) {
		Graphics2D g = (Graphics2D) g1;
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
		  Stroke thindashed = new BasicStroke(2f, // line width
			      /* cap style */BasicStroke.CAP_BUTT,
			      /* join style, miter limit */BasicStroke.JOIN_BEVEL, 1.0f,
			      /* the dash pattern */new float[] { 8.0f, 3.0f, 2.0f, 3.0f },
			      /* the dash phase */0.0f); /* on 8, off 3, on 2, off 3 */
		g.setColor(Color.GRAY);
		for (int i=0; i < points.size()-1;i++) {
			Line2D.Float l = new Line2D.Float(((Point)points.get(i)).x, ((Point)points.get(i)).y, ((Point)points.get(i+1)).x, ((Point)points.get(i+1)).y);
			g.drawLine(((Point)points.get(i)).x, ((Point)points.get(i)).y, ((Point)points.get(i+1)).x, ((Point)points.get(i+1)).y);
			
		}
	
	}
	
	
	public JPanel settingPanel(){
		JPanel panel = new JPanel();
		
		panel.add(new JLabel("Set width"));
		
		JSlider widthSlider = new JSlider(JSlider.HORIZONTAL,2,30,Math.round(width));
		widthSlider.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent e){
				width = (float)((JSlider)e.getSource()).getValue();
			}
		});
		widthSlider.setPreferredSize(new Dimension(50,20));
        panel.add(widthSlider);
        
        
        panel.add(new JLabel("Hair amount"));
        
		JSlider hairSlider = new JSlider(JSlider.HORIZONTAL,15,100,hair);
		hairSlider.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent e){
				hair = ((JSlider)e.getSource()).getValue();
			}
		});
		hairSlider.setPreferredSize(new Dimension(50,20));
        panel.add(hairSlider);
        
        
        
        panel.add(new JLabel("Wetness"));
        
		JSlider wetnessSlider = new JSlider(JSlider.HORIZONTAL,0,100,Math.round(wetness*100f));
		wetnessSlider.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent e){
				wetness = (float)((JSlider)e.getSource()).getValue()/100f;
			}
		});
		wetnessSlider.setPreferredSize(new Dimension(50,20));
        panel.add(wetnessSlider);
        
        
        panel.add(new JLabel("Color amount"));
        
		JSlider colorAmountSlider = new JSlider(JSlider.HORIZONTAL,0,120,colorAmount);
		colorAmountSlider.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent e){
				colorAmount = ((JSlider)e.getSource()).getValue();
				setColor((Color)colors.get(0));
			}
		});
		
		colorAmountSlider.setPreferredSize(new Dimension(50,20));
        panel.add(colorAmountSlider);        

        panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
		return panel;
	}
	
	public boolean isDrawable(){
		return true;
	}

}