docs: @Pure
  	@SuppressWarnings("checkstyle:nestedifdepth")
  	List<AStarNode<ST, PT>> findPath(AStarNode<ST, PT> startPoint, PT endPoint) {
  		final CloseComparator<ST, PT> cComparator = new CloseComparator<>();
  		final OpenComparator<ST, PT> oComparatorWithoutRef = new OpenComparator<>();
  		final List<AStarNode<ST, PT>> openList = new ArrayList<>();
  		final List<AStarNode<ST, PT>> closeList = new ArrayList<>();
  
  		openList.add(startPoint);
  		fireNodeOpened(startPoint, openList);
  
  		int idx;
  		AStarNode<ST, PT> candidate;
  		AStarNode<ST, PT> ocandidate;
  		AStarNode<ST, PT> reachableCandidate;
  		AStarNode<ST, PT> reachedCandidate;
  		PT reachableNode;
  		PT node;
  		double gCost;
  		double h1;
  		boolean foundTarget = false;
  
  		while (!foundTarget && !openList.isEmpty()) {
  
  			ocandidate = openList.remove(0);
  			fireNodeConsumed(ocandidate, openList);
  
  			candidate = translateCandidate(endPoint, ocandidate);
  			foundTarget = candidate == null;
  
  			if (!foundTarget) {
  				assert candidate != null;
  				node = candidate.getGraphPoint();
  				// Update the nodes that are reachable from the current candidate.
  				for (final ST segment : candidate.getGraphSegments()) {
  					reachableNode = segment.getOtherSidePoint(node);
  					if (reachableNode != null && !reachableNode.equals(node)) {
  						gCost = candidate.getCost()
  								+ computeCostFor(node)
  								+ computeCostFor(segment);
  						h1 = estimate(reachableNode, endPoint);
  						reachableCandidate = newAStarNode(reachableNode, gCost, h1, segment);
  
  						// Reopen node if better cost
  						idx = (isClosedNodeReopeningEnabled())
  								? ListUtil.indexOf(closeList, cComparator, reachableCandidate)
  										: -1;
  						if (idx >= 0) {
  							reachedCandidate = closeList.get(idx);
  							if (gCost < reachedCandidate.getCost()) {
  								closeList.remove(idx);
  								final AStarNode<ST, PT> nn = node(
  										reachableNode,
  										gCost,
  										h1,
  										segment);
  								ListUtil.add(
  										openList,
  										oComparatorWithoutRef,
  										nn,
  										true, false);
  								fireNodeOpened(nn, openList);
  							}
  						} else {
  							idx = openList.indexOf(reachableCandidate);
  							if (idx >= 0) {
  								// Rearrange open list if better cost
  								reachedCandidate = openList.get(idx);
  								if ((gCost + h1) < reachedCandidate.getPathCost()) {
  									openList.remove(idx);
  									final AStarNode<ST, PT> nn = node(
  											reachableNode,
  											gCost,
  											h1,
  											segment);
  									ListUtil.add(openList,
  											oComparatorWithoutRef,
  											nn,
  											true, false);
  									fireNodeReopened(nn, openList);
  								}
  							} else {
  								// Node was neither treated nor seen, add it
  								final AStarNode<ST, PT> nn = node(
  										reachableNode,
  										gCost,
  										h1,
  										segment);
  								ListUtil.add(openList,
  										oComparatorWithoutRef,
  										nn,
  										true, false);
  								fireNodeOpened(nn, openList);
  							}
  						}
  					}
  				}
  			}
  
  			// Refresh the close list
  			idx = ListUtil.add(closeList, cComparator, ocandidate, false, true);
  			fireNodeClosed(ocandidate, closeList);
  			assert idx >= 0;
  		}
  
  		return closeList;
  	}