package ei.game.algo;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import ei.engine.math.Vector2i;
import ei.engine.util.MultiPrintStream;
import ei.game.gamestate.InGameState;

public class AStar{
	private static final long serialVersionUID = 1L;
	private AStarPathfinder pathfinder;
	
	private int width;
	private int hight;
	private AStarNode[][] map;
	
	protected boolean randomizeMap = true;
	protected Random RAND = new Random(0);
	
	public AStar() {
		width = InGameState.getMap().getSize().getX();
		hight = InGameState.getMap().getSize().getY();
		initializePathfinder();
		initializeMap();
	}

	public List<AStarNode> startSearch(Vector2i start, Vector2i goal){
		return pathfinder.findPath(map[start.getX()][start.getY()], map[goal.getX()][goal.getY()]);
	}
	
	protected void initializePathfinder() {
		System.out.println("Initializing pathfinder");
		
		// Create the pathfinder.
		pathfinder = new AStarPathfinder();
	}
	
	
	protected void initializeMap() {
		System.out.println("Initializing map");
		// Create the map.
		map = new AStarNode2D[width][hight];
		for(int y = 0, nodeId = 0; hight > y; y++) {
			MultiPrintStream.out.println();
			 for(int x = 0; width > x; x++, nodeId++) {
				map[x][y] = new AStarNode2D(x, y, nodeId);

				if(!InGameState.getMap().isPosEmpty(x, y)) {
					map[x][y].setBlocked(true);
					MultiPrintStream.out.print(1);
				}
				else MultiPrintStream.out.print(0);
			}
		}
		
		/*
		for(int x = 0, nodeId = 0; width > x; x++) {
			for(int y = 0; hight > y; y++, nodeId++) {
				map[x][y] = new AStarNode2D(x, y, nodeId);

				if(!InGameState.getMap().isPosEmpty(x, y)) {
					map[x][y].setBlocked(true);
				}
			}
		}
		 */
		
		// Create the neighbours.
		for(int x = 0; width > x; x++) {
			for(int y = 0; hight > y; y++) {
				
				List<AStarNeighbour> neighbours = new LinkedList<AStarNeighbour>();
				
				if(y-1 >= 0) 
					neighbours.add(new AStarNeighbour(map[x][y-1], AStarNeighbour.Location.Diagonal));	// North.
				if(x+1 < width && y-1 > 0) 
					neighbours.add(new AStarNeighbour(map[x+1][y-1], AStarNeighbour.Location.Adjacent));	// North-East.
				if(x+1 < width) 
					neighbours.add(new AStarNeighbour(map[x+1][y], AStarNeighbour.Location.Diagonal));	// East.	
				if(x+1 < width && y+1 < hight) 
					neighbours.add(new AStarNeighbour(map[x+1][y+1], AStarNeighbour.Location.Adjacent));	// South-East.
				if(y+1 < hight) 
					neighbours.add(new AStarNeighbour(map[x][y+1], AStarNeighbour.Location.Diagonal));	// South.					
				if(x-1 >= 0 && y+1 < hight) 
					neighbours.add(new AStarNeighbour(map[x-1][y+1], AStarNeighbour.Location.Adjacent));	// South-West.
				if(x-1 >= 0) 
					neighbours.add(new AStarNeighbour(map[x-1][y], AStarNeighbour.Location.Diagonal));	// West.
				if(x-1 >= 0 && y-1 > 0) 
					neighbours.add(new AStarNeighbour(map[x-1][y-1], AStarNeighbour.Location.Adjacent));	// North-West.

				map[x][y].setNeighbours(neighbours);
				
			}
		}
	}
}
