package ei.game.algo;

import java.util.List;

import ei.game.algo.AStarNeighbour.Location;

/**
 * This Node class defines the Node that make up grids, paths etc.
 * 
 * @author Árni Arent
 *
 */
public abstract class AStarNode implements Comparable {

	protected int nodeId;
	protected List<AStarNeighbour> neighbours;
	protected AStarNode parent;
	protected boolean blocked;
	protected boolean visited;
	protected int visitOrder;
	protected boolean partOfPath;
	public float costFromStart;
	protected float estimatedCostToGoal;
	
	/**
	 * 
	 * @param nodeId
	 */
	public AStarNode(int nodeId) {
		this.nodeId = nodeId;
	}
	
	/**
	 * 
	 * @return
	 */
	public AStarNode getParent() {
		return parent;
	}

	/**
	 * 
	 * @param parent
	 */
	public void setParent(AStarNode parent) {
		this.parent = parent;
	}

	/**
	 * Returns all the neighbours of this node.
	 * Usually in grid maps the neighbours are positioned in north,
	 * north-east, east, south-east, south, south-west, west and north-west.
	 * 
	 * @return the neighbours of this node.
	 */
	public List<AStarNeighbour> getNeighbours() {
		return neighbours;
	}

	/**
	 * Set the neighbours of this Node.
	 * Usually in grid maps the neighbours are positioned in north,
	 * north-east, east, south-east, south, south-west, west and north-west.
	 * 
	 * @param neighbours the neighbours of this Node.
	 */
	public void setNeighbours(List<AStarNeighbour> neighbours) {
		this.neighbours = neighbours;
	}

	/**
	 * Gives the id of the Node. The id is a unique integer number
	 * defining the number of the node.
	 * Grid maps of size 64x64 have 4096 nodes, so each node has a
	 * id ranging from 0 to 4095.
	 * This can usually be thought of as a auto incremental unique
	 * identifier number, each Node created gets a incremented unique
	 * id.
	 * 
	 * @return the id of this Node.
	 */
	public int getNodeId() {
		return nodeId;
	}
	
	
	/**
	 * Tells if this Node is blocked or not.
	 * 
	 * @return true if the node is blocked, false if not.
	 */
	public boolean isBlocked() {
		return blocked;
	}

	/**
	 * Defined if this Node should be blocked or not.
	 * 
	 * @param blocked true if it should be blocked, false if not.
	 */
	public void setBlocked(boolean blocked) {
		this.blocked = blocked;
	}
	
	public boolean isVisited() {
		return visited;
	}

	public void setVisited(boolean visited) {
		this.visited = visited;
	}
	
	public void setVisitOrder(int order) {
		this.visitOrder = order;
	}
	
	public int getVisitOrder() {
		return visitOrder;
	}
	
	
	
	
	public boolean isPartOfPath() {
		return partOfPath;
	}

	public void setPartOfPath(boolean partOfPath) {
		this.partOfPath = partOfPath;
	}

	public void reset() {
		visited = false;
		visitOrder = 0;
		parent = null;
		partOfPath = false;
		estimatedCostToGoal = 0;
	}

	@Override
	public String toString() {
		return "[Node " + nodeId + " ("+(blocked?"X":" ")+")]";
	}

	public float getEstimatedCostFromStartToGoal() {
		return costFromStart+estimatedCostToGoal;
	}

	public abstract float getEstimatedCostTo(AStarNode node, AStarNode startNode);
	
	public abstract float getCost(AStarNode node, Location location);
	
	public int compareTo(Object n) {
		float cost = getEstimatedCostFromStartToGoal() - ((AStarNode)n).getEstimatedCostFromStartToGoal();
		
		if(cost > 0)
			return 1;
		else if(cost < 0)
			return -1;
		else
			return 0;
	}
	
	public abstract int getX();

	public abstract int getY();
}
