-- Spawns a new sprite
function newSprite(x, y, textureID)
	table.insert(sprites, {x = x, y = y, id = textureID})
end

-- Spawns a new door
function newDoor(x, y, textureID, wide, mapX, mapY) -- Wide determines whether or not the door is horizontal or not
	table.insert(doors, {x = x, y = y, id = textureID, wide = wide, open = false, opening = false, mapX = mapX, mapY = mapY, movementLeft = 1,})
end

-- Checks for a door
function checkDoor(mapX, mapY)
	for i=1, #doors do
		if doors[i].mapX == mapX and doors[i].mapY == mapY then
			if doors[i].open then
				return true
			else
				doors[i].opening = true
				return false
			end
		end
	end

	return false
end

-- Updates Doors
function updateDoor(dt)
	for i=1, #doors do
		if doors[i].opening then
			if doors[i].wide then
				doors[i].y = doors[i].y - (dt / 2)
			else
				doors[i].x = doors[i].x - (dt / 2)
			end
			doors[i].movementLeft = doors[i].movementLeft - (dt / 2)

			if doors[i].movementLeft <= 0 then
				doors[i].opening = false
				doors[i].open = true
			end
		end
	end
end

-- Gets the rotation of the player
function getPlayerRot()
	return math.atan2(player.dirX, player.dirY)
end

-- Stencil
function stencil()
	if beginSt < endSt then
		love.graphics.rectangle("fill", beginSt, 0, endSt - beginSt, h)
	else
		love.graphics.rectangle("fill", endSt, 0, beginSt - endSt, h)
	end
end

-- Sort Algorithm
function zSort(object1, object2)
    return object1.z > object2.z
end

-- Check Match
function checkMatch(t1, t2)
	local match = false
	for i,v in ipairs(t1) do
		if v.x == t2.x and v.y == t2.y then
			match = true
		end
	end

	return match
end

-- Floor Tile
function floorTile(x, y, additive, invDet)
	local allowedDraw = true
	local spriteX = x - player.posX;
	local spriteY = y - player.posY;

	tx = invDet * (player.dirY * (spriteX) - player.dirX * (spriteY));
	ty = invDet * (-player.planeY * (spriteX) + player.planeX * (spriteY));
	if ty <= 0 then allowedDraw = false end

	local X1 = ((w / 2) * (1 + tx / ty));
	local Y1 = math.abs((h / ty)) / 2 + (h/ 2)

	tx = invDet * (player.dirY * (spriteX + additive) - player.dirX * (spriteY));
	ty = invDet * (-player.planeY * (spriteX + additive) + player.planeX * (spriteY));
	if ty <= 0 then allowedDraw = false end

	local X2 = ((w / 2) * (1 + tx / ty));
	local Y2 = math.abs((h / ty)) / 2 + (h/ 2)

	tx = invDet * (player.dirY * (spriteX + additive) - player.dirX * (spriteY + additive));
	ty = invDet * (-player.planeY * (spriteX + additive) + player.planeX * (spriteY + additive));
	if ty <= 0 then allowedDraw = false end

	local X3 = ((w / 2) * (1 + tx / ty));
	local Y3 = math.abs((h / ty)) / 2 + (h/ 2)

	tx = invDet * (player.dirY * (spriteX) - player.dirX * (spriteY + additive));
	ty = invDet * (-player.planeY * (spriteX) + player.planeX * (spriteY + additive));
	if ty <= 0 then allowedDraw = false end

	local X4 = ((w / 2) * (1 + tx / ty));
	local Y4 = math.abs((h / ty)) / 2 + (h/ 2)

	return {X1, Y1}, {X2, Y2}, {X3, Y3}, {X4, Y4}, allowedDraw
end

-- Player Input
function input(dt)
	local moveSpeed = dt * player.moveMod
	local rotSpeed = dt * player.rotMod
	local strafeSpeed = dt * player.strafeMod
	local z = player.w

	if love.keyboard.isDown("w") then
		local mapX = math.floor(player.posX + player.dirX * moveSpeed + player.dirX * z)
		local mapY = math.floor(player.posY + player.dirY * z)
		local tempMove = map[mapX][mapY]
		if (tempMove == 0 or ((tempMove == -7 or tempMove == -8) and checkDoor(mapX, mapY))) then
			player.posX = player.posX + player.dirX * moveSpeed
		end

		local mapX = math.floor(player.posX + player.dirX * z)
		local mapY = math.floor(player.posY + player.dirY * moveSpeed + player.dirY * z)
		local tempMove = map[mapX][mapY]
		if (tempMove == 0 or ((tempMove == -7 or tempMove == -8)  and checkDoor(mapX, mapY))) then
			player.posY = player.posY + player.dirY * moveSpeed
		end
	end
	if love.keyboard.isDown("s") then
		local mapX = math.floor(player.posX - player.dirX * moveSpeed - player.dirX * z)
		local mapY = math.floor(player.posY - player.dirY * z)
		local tempMove = map[mapX][mapY]
		if (tempMove == 0 or ((tempMove == -7 or tempMove == -8)  and checkDoor(mapX, mapY))) then
			player.posX = player.posX - player.dirX * moveSpeed
		end

		local mapX = math.floor(player.posX - player.dirX * z)
		local mapY = math.floor(player.posY - player.dirY * moveSpeed - player.dirY * z)
		local tempMove = map[mapX][mapY]
		if (tempMove == 0 or ((tempMove == -7 or tempMove == -8)  and checkDoor(mapX, mapY))) then
			player.posY = player.posY - player.dirY * moveSpeed
		end
	end
	if love.keyboard.isDown("d") then
		local mapX = math.floor(player.posX + player.planeX * moveSpeed + player.planeX * z)
		local mapY = math.floor(player.posY + player.planeY * z)
		local tempMove = map[mapX][mapY]
		if (tempMove == 0 or ((tempMove == -7 or tempMove == -8)  and checkDoor(mapX, mapY))) then
			player.posX = player.posX + player.planeX * strafeSpeed
		end

		local mapX = math.floor(player.posX + player.planeX * z)
		local mapY = math.floor(player.posY + player.planeY * moveSpeed + player.planeY * z)
		local tempMove = map[mapX][mapY]
		if (tempMove == 0 or ((tempMove == -7 or tempMove == -8)  and checkDoor(mapX, mapY))) then
			player.posY = player.posY + player.planeY * strafeSpeed
		end
	end
	if love.keyboard.isDown("a") then
		local mapX = math.floor(player.posX - player.planeX * moveSpeed - player.planeX * z)
		local mapY = math.floor(player.posY - player.planeY * z)
		local tempMove = map[mapX][mapY]
		if (tempMove == 0 or ((tempMove == -7 or tempMove == -8)  and checkDoor(mapX, mapY))) then
			player.posX = player.posX - player.planeX * strafeSpeed
		end

		local mapX = math.floor(player.posX - player.planeX * z)
		local mapY = math.floor(player.posY - player.planeY * moveSpeed - player.planeY * z)
		local tempMove = map[mapX][mapY]
		if (tempMove == 0 or ((tempMove == -7 or tempMove == -8)  and checkDoor(mapX, mapY))) then
			player.posY = player.posY - player.planeY * strafeSpeed
		end 
	end

	if grabbed then
		local mouseX = love.mouse.getX()
		local mouseY = love.mouse.getY()

		if mouseX ~= w/2 then
			local turnSpeed = 0
			if mouseX > w/2 then turnSpeed = rotSpeed * (w/2 - mouseX) end
			if mouseX < w/2 then turnSpeed = -rotSpeed * (mouseX - (w/2)) end

			local oldDirX = player.dirX
			player.dirX = player.dirX * math.cos(turnSpeed) - player.dirY * math.sin(turnSpeed)
			player.dirY = oldDirX * math.sin(turnSpeed) + player.dirY * math.cos(turnSpeed)
			local oldPlaneX = player.planeX
			player.planeX = player.planeX * math.cos(turnSpeed) - player.planeY * math.sin(turnSpeed)
			player.planeY = oldPlaneX * math.sin(turnSpeed) + player.planeY * math.cos(turnSpeed)
		end
		
		-- Head Tilt (Not Working)
		--[[ if mouseY ~= h/2 then
			local tiltSpeed = 0
			if mouseY > h/2 then tiltSpeed = 400 * (h/2 - mouseY) end
			if mouseY < h/2 then tiltSpeed = -400 * (mouseY - (h/2)) end

			if TILT + tiltSpeed * dt > -tLim and TILT + tiltSpeed * dt < tLim then
				TILT = TILT + tiltSpeed * dt
			end
		end ]]--

		love.mouse.setPosition(w/2, h/2)
	end
end

-- Corner images for the floor
function genCorner()
	for i = 1, #img do
		local fullImg = love.image.newImageData(directory[i])
		local widthh, heightt = fullImg:getDimensions()
		local fakeX, fakeY = 0, 0
		cornerImg[i] = {}

		local imageData = love.image.newImageData(widthh / 2, heightt / 2)
		for x = 0, (widthh / 2) - 1 do
			for y = 0, (heightt / 2) - 1 do
				local r, g, b, a = fullImg:getPixel(x, y)
				imageData:setPixel(fakeX, fakeY, r, g, b, a)

				fakeY = fakeY + 1
			end
			fakeX = fakeX + 1
			fakeY = 0
		end
		fakeX, fakeY = 0, 0

		cornerImg[i][1] = love.graphics.newImage(imageData)

		for x = (widthh / 2), widthh - 1 do
			for y = 0, (heightt / 2) - 1 do
				local r, g, b, a = fullImg:getPixel(x, y)
				imageData:setPixel(fakeX, fakeY, r, g, b, a)

				fakeY = fakeY + 1
			end
			fakeX = fakeX + 1
			fakeY = 0
		end
		fakeX, fakeY = 0, 0

		cornerImg[i][2] = love.graphics.newImage(imageData)

		for x = 0, (widthh / 2) - 1 do
			for y = (heightt / 2), heightt - 1 do
				local r, g, b, a = fullImg:getPixel(x, y)
				imageData:setPixel(fakeX, fakeY, r, g, b, a)

				fakeY = fakeY + 1
			end
			fakeX = fakeX + 1
			fakeY = 0
		end
		fakeX, fakeY = 0, 0

		cornerImg[i][3] = love.graphics.newImage(imageData)

		for x = (widthh / 2), widthh - 1 do
			for y = (heightt / 2), heightt - 1 do
				local r, g, b, a = fullImg:getPixel(x, y)
				imageData:setPixel(fakeX, fakeY, r, g, b, a)

				fakeY = fakeY + 1
			end
			fakeX = fakeX + 1
			fakeY = 0
		end

		cornerImg[i][4] = love.graphics.newImage(imageData)
	end
end