const timer = ms => new Promise(res => setTimeout(res, ms))

var cols = 9
var rows = 9

let grid = new Array(cols); 

let openSet = []; 
let closedSet = []; 

let start; 
let end; 
let path = [];


function generateClickMap() {
	var clickMap = document.getElementById('click-map')
	for (let i = 0; i < rows; i++) {
		for (let j = 0; j < cols; j++) {
			var area = document.createElement('area')
			area.shape = 'rect'
			area.href = '#'
			area.addEventListener('click', function (event) {
				if (j > 7) {
					pathfind(i, j - 1)
				} else {
					pathfind(i, j)
				}
			})
			area.coords = `${i * spriteSize},${j * spriteSize},${(i + 1) * spriteSize},${(j + 1) * spriteSize}`
			clickMap.appendChild(area)
		}
	}
}

generateClickMap()

function heuristic(position0, position1) {
	let d1 = Math.abs(position1.x - position0.x);
	let d2 = Math.abs(position1.y - position0.y);

	return d1 + d2;
}


class GridPoint {
	constructor(x, y) {
		this.x = x; 
		this.y = y; 
		this.f = 0; 
		this.g = 0; 
		this.h = 0; 
		this.neighbors = []; 
		this.parent = undefined; 
	}

	updateNeighbors(grid) {
		let i = this.x;
		let j = this.y;
		var tmpNeighbor;
		if (i < cols - 1) {
			tmpNeighbor = grid[i + 1][j]
			if (!player.isBoundary([tmpNeighbor.x, tmpNeighbor.y])) {
				this.neighbors.push(tmpNeighbor);
			}
		}
		if (i > 0) {
			tmpNeighbor = grid[i - 1][j]
			if (!player.isBoundary([tmpNeighbor.x, tmpNeighbor.y])) {
				this.neighbors.push(tmpNeighbor);
			}
		}
		if (j < rows - 1) {
			tmpNeighbor = grid[i][j + 1]
			if (!player.isBoundary([tmpNeighbor.x, tmpNeighbor.y])) {
				this.neighbors.push(tmpNeighbor);
			}
		}
		if (j > 0) {
			tmpNeighbor = grid[i][j - 1]
			if (!player.isBoundary([tmpNeighbor.x, tmpNeighbor.y])) {
				this.neighbors.push(tmpNeighbor);
			}
		}
	};
}


function init(destX, destY) {
	
	for (let i = 0; i < cols; i++) {
		grid[i] = new Array(rows);
	}

	for (let i = 0; i < cols; i++) {
		for (let j = 0; j < rows; j++) {
			grid[i][j] = new GridPoint(i, j);
		}
	}

	for (let i = 0; i < cols; i++) {
		for (let j = 0; j < rows; j++) {
			grid[i][j].updateNeighbors(grid);
		}
	}

	start = grid[player.canvasX][player.canvasY];
	end = grid[destX][destY]

	openSet.push(start);
}


function search(destX, destY) {
	path = [];
	init(destX, destY);
	while (openSet.length > 0) {
		
		let lowestIndex = 0;
		for (let i = 0; i < openSet.length; i++) {
			if (openSet[i].f < openSet[lowestIndex].f) {
				lowestIndex = i;
			}
		}
		let current = openSet[lowestIndex];

		if (current === end) {
			let temp = current;
			path.push(temp);
			while (temp.parent) {
				path.push(temp.parent);
				temp = temp.parent;
			}

			return path.reverse()
		}

		
		openSet.splice(lowestIndex, 1);
		
		closedSet.push(current);

		let neighbors = current.neighbors;

		for (let i = 0; i < neighbors.length; i++) {
			let neighbor = neighbors[i];

			if (!closedSet.includes(neighbor)) {
				let possibleG = current.g + 1;

				if (!openSet.includes(neighbor)) {
					openSet.push(neighbor);
				} else if (possibleG >= neighbor.g) {
					continue;
				}

				neighbor.g = possibleG;
				neighbor.h = heuristic(neighbor, end);
				neighbor.f = neighbor.g + neighbor.h;
				neighbor.parent = current;
			}
		}
	}

	return [];
}

async function pathfind(destX, destY) {

	var isBoundary = player.isBoundary([destX, destY])

	if (isBoundary) {
		var tmpDestX = destX
		var tmpDestY = destY
		var newDest = boundaryMap[String(destX) + String(destY)]
		destX = newDest[0]
		destY = newDest[1]
	}

	var newPath = search(destX, destY)
	for (let i = 0; i < newPath.length; i++) {
		changeDir(newPath[i].x, newPath[i].y)

		player.canvasX = newPath[i].x
		player.canvasY = newPath[i].y

		if (isBoundary && i === newPath.length - 1) {
			changeDir(tmpDestX, tmpDestY)
		}
		await timer(100)
	}
	
	if (destX === 0 && destY === 0 || destX === 1 && destY === 0) {
		player.direction = 'up'
		portfolio.show()
	}

	if (destX === 7 && destY === 0 || destX === 8 && destY === 0) {
		player.direction = 'up'
		games.show()
	}

	if (destX === 2 && destY === 4 || destX === 3 && destY === 4) {
		player.direction = 'up'
		terminal.show()
	}

	if (destX === 4 && destY === 4) {
		player.direction = 'up'
		resume.show()
	}

	if (destX === 0 && destY === 6 || destX === 1 && destY === 6) {
		player.direction = 'down'
		music.show()
	}

	if (destX === 6 && destY === 6) {
		player.direction = 'up'
		maomao.show()
	}

	dialog.hide()
}

function changeDir(destX, destY) {
		if (destX > player.canvasX) {
			player.direction = 'right'
		} else if (destX < player.canvasX) {
			player.direction = 'left'
		}

		if (destY > player.canvasY) {
			player.direction = 'down'
		} else if (destY < player.canvasY) {
			player.direction = 'up'
		}
}
