package ei.game.algo;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

/**
 * A test for the different path finding implementations defined
 * 
 * Note: Like all the tests this isn't designed to be a robust piece
 * of software, rather a testing tool.
 * 
 * @author Kevin Glass
 */
public class TestPathFinder extends JPanel implements TileSet, TileMap, PathFinderCallback {
	private static final long serialVersionUID = 1L;

	/** The depth of search allowed */
	private static final int SEARCH_DEPTH = 500;
	
	/** The map being searched */
	private int[][] map = new int[100][100];
	/** The current start x coordinate */
	private int sx = 5;
	/** The current start y coordinate */
	private int sy = 5;
	/** The current end x coordinate */
	private int dx = 5;
	/** The current end y coordinate */
	private int dy = 5;
	/** The finder searching the map */
	private PathFinder finder;
	/** The last path found */
	private Path path;
	
	/**
	 * Create a test for path finding
	 */
	public TestPathFinder() {
		generateData(map);

		finder = new AStarPathFinder(this,this,this);
		//finder = new DJKPathFinder(this,this);
		
		JFrame frame = new JFrame();
		frame.setContentPane(new JScrollPane(this));
		
		addMouseListener(new MouseHandler());
		setPreferredSize(new Dimension(1000,1000));
		
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		
		frame.setSize(800,600);
		frame.setVisible(true);
	}
	
	/**
	 * Generate a random map for testing against, worst 
	 * alogrithm ever?
	 * 
	 * @param data The data array to generate the map into
	 */
	private void generateData(int[][] data) {
		for (int x=0;x<100;x++) {
			for (int y=0;y<100;y++) {
				data[x][y] = 1;
			}
		}
		
		int count = (int) (Math.random() * 110) + 40;
		for (int i=0;i<count;i++) {
			int xs = (int) (Math.random() * 100);
			int ys = (int) (Math.random() * 100);
			int w = (int) (Math.random() * 10) + 6;
			int h = (int) (Math.random() * 10) + 6;
			
			for (int x=xs;x<xs+w;x++) {
				for (int y=ys;y<ys+h;y++) {
					if ((x > 0) && (y > 0) && (x < 99) && (y < 99)) {
						data[x][y] = 0;
					}
				}
			}
		data[2][1] = 1;
		data[1][1] = 0;
		data[1][2] = 0;
		data[1][3] = 0;
		data[2][3] = 0;
		data[2][4] = 0;
		data[2][5] = 0;
		data[2][6] = 0;
		}
	}
	
	/**
	 * @see java.awt.Component#paint(java.awt.Graphics)
	 */
	public void paint(Graphics g) {
		g.setColor(Color.black);
		g.fillRect(0,0,1000,1000);
		
		for (int x=0;x<100;x++) {
			for (int y=0;y<100;y++) {
				
				if (isBlocked(x,y)) {
					g.setColor(Color.white);
					g.fillRect(x*10,y*10,10,10);
				}
			}
		}
		
		if (finder.getSearchData() != null) {
			int[] data = finder.getSearchData();
			
			for (int x=0;x<100;x++) {
				for (int y=0;y<100;y++) {
					if (!isBlocked(x,y)) {
						if (data[x+(y*100)] != 0) {
							g.setColor(Color.blue);
							g.fillRect(x*10,y*10,10,10);
						}
					}
				}
			}
		}

		if (path != null) {
			for (int i=0;i<path.getSize();i++) {
				g.setColor(Color.yellow);
				g.fillRect(path.getX(i)*10,path.getY(i)*10,10,10);
			}
		}
		g.setColor(Color.green);
		g.fillRect(sx*10,sy*10,10,10);
		g.setColor(Color.red);
		g.fillRect(dx*10,dy*10,10,10);
	}
	
	/**
	 * Handler for mouse clicks. Attempts to find paths
	 * via the path finder objects.
	 * 
	 * @author Kevin Glass
	 */
	private class MouseHandler extends MouseAdapter {
		
		/**
		 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
		 */
		public void mousePressed(MouseEvent e) {
			if (e.getButton() == 1) {
				sx = e.getX() / 10;
				sy = e.getY() / 10;
			} else {
				dx = e.getX() / 10;
				dy = e.getY() / 10;
				
				Thread t = new Thread() {
					public void run() {
						long start = System.currentTimeMillis();
						finder.reset();
						path = finder.findPath(sx,sy,dx,dy,SEARCH_DEPTH);
						long delta = System.currentTimeMillis() - start;
						if (path != null) {
							System.out.println("Path length: "+path.getSize());
						} else {
							System.out.println("No path found");
						}
						System.out.println("Path find took: "+delta+" milliseconds");
						repaint();
					}
				};
				t.start();
			}
			
			repaint();
		}
	}

	/**
	 * @see org.newdawn.util.map.TileMap#getTileAt(int, int, int)
	 */
	public int getTileAt(int x, int y, int layer) {
		return map[x][y];
	}

	/**
	 * @see org.newdawn.util.map.TileMap#isBlocked(int, int)
	 */
	public boolean isBlocked(int x, int y) {
		return map[x][y] != 0;
	}

	/**
	 * @see org.newdawn.util.map.TileMap#getMapWidth()
	 */
	public int getMapWidth() {
		return 100;
	}

	/**
	 * @see org.newdawn.util.map.TileMap#getMapHeight()
	 */
	public int getMapHeight() {
		return 100;
	}
	
	/**
	 * Entry point to the path finding test 
	 * 
	 * @param argv The arguments into the test (none)
	 */
	public static void main(String[] argv) {
		new TestPathFinder();
	}

	/**
	 * @see org.newdawn.util.map.PathFinderCallback#fireNode(int, int)
	 */
	public void fireNode(int x, int y) {
		//repaint(0);
		//try { Thread.sleep(100); } catch (Exception e) {};
	}

	/**
	 * @see org.newdawn.util.map.TileSet#blocksMovement(int)
	 */
	public boolean blocksMovement(int tile) {
		return tile != 0;
	}
}
