import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.Stack;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.text.AttributeSet.ColorAttribute;


public class StackFill extends JPanel {
 	public static final int WINDOW_WIDTH = 640;
	public static final int WINDOW_HEIGHT = 480;

	private boolean painting = false;
	private boolean[][] grid = new boolean[WINDOW_WIDTH / 20][WINDOW_HEIGHT / 20];
	
	public static void main(final String[] args) {
   		JFrame frame = new JFrame("Paint and Fill");
      	frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
   		frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
  	 	frame.setLocationRelativeTo(null);
       		
		StackFill paint = new StackFill();
		frame.setContentPane(paint);
		paint.init();
		
		frame.setVisible(true);
	}
    
	public StackFill() {
	}

	public void init() {
		addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (e.getButton() == MouseEvent.BUTTON1) {
					painting = true;
					grid[e.getX() / 20][e.getY() / 20] = true;
					repaint();
				} else {
					// Recursive method.
					//fill(e.getX() / 20, e.getY() / 20);
					
					// Alternative iterative method using stack.
					Stack<Point> stack = new Stack<Point>();
					stack.push(new Point(e.getX() / 20, e.getY() / 20));
					while (!stack.empty()) {
						Point next = stack.pop();
						if (next.x < 0 || next.x >= grid.length || next.y < 0 || next.y >= grid[next.x].length || grid[next.x][next.y]) {
							continue;
						}
						grid[next.x][next.y] = true;
						
						stack.push(new Point(next.x + 1, next.y));
						stack.push(new Point(next.x - 1, next.y));
						stack.push(new Point(next.x, next.y + 1));
						stack.push(new Point(next.x, next.y - 1));
					}
					repaint();
				}
			}

			public void mouseReleased(MouseEvent e) {
				painting = false;
			}
		});
			
		addMouseMotionListener(new MouseMotionAdapter() {
			public void mouseDragged(MouseEvent e) {
				grid[e.getX() / 20][e.getY() / 20] = true;
				repaint();
			}
		});
	}		

	public void paint(Graphics g) {
		Graphics2D g2d = (Graphics2D)g;

		for (int i = 0; i < grid.length; i++) {
			for (int j = 0; j < grid[i].length; j++) {
				if (!grid[i][j]) {
					g.setColor(Color.black);
				} else {
					g.setColor(Color.white);
				}
				g.fillRect(i * 20, j * 20, 20, 20);
			}
		}
	}
	
	// Recursive method to fill adjacent squares with same color.
	public void fill(int x, int y) {
		if (x < 0 || x >= grid.length || y < 0 || y >= grid[x].length || grid[x][y]) {
			return;
		}
		grid[x][y] = true;
		fill(x - 1, y);
		fill(x + 1, y);
		fill(x, y - 1);
		fill(x, y + 1);
	}
}

