--[[

	Minecart
	========

	Copyright (C) 2019-2021 Joachim Stolberg

	MIT
	See license.txt for more information

]]--

-- for lazy programmers
local M = minetest.get_meta
local S = minecart.S
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos

function minecart.get_nodecart_nearby(pos, param2, radius)
	local pos2 = param2 and vector.add(pos, minecart.param2_to_dir(param2)) or pos
	local pos3 = minetest.find_node_near(pos2, radius or 0.5, minecart.lCartNodeNames, true)
	if pos3 then
		return pos3, minetest.get_node(pos3)
	end
end

-- Convert node to entity and start cart
function minecart.start_nodecart(pos, node_name, puncher, punch_dir)
	local owner = M(pos):get_string("owner")
	local userID = M(pos):get_int("userID")
	-- check if valid cart
	if not minecart.monitoring_valid_cart(owner, userID, pos, node_name) then
		--print("Lost cart", owner, userID, P2S(pos), node_name)
		local entity_name = minecart.tNodeNames[node_name]
		if owner ~= "" and userID ~= "" and entity_name then
			minecart.monitoring_add_cart(owner, userID, pos, node_name, entity_name)
		else
			M(pos):set_string("infotext",
					minetest.get_color_escape_sequence("#FFFF00") .. owner .. ": 0")
			return
		end
	end
	-- Only the owner or a noplayer can start the cart, but owner has to be online
	if minecart.is_owner(puncher, owner) and minetest.get_player_by_name(owner) and
			userID ~= 0 then
		local entity_name = minecart.tNodeNames[node_name]
		local obj = minecart.node_to_entity(pos, node_name, entity_name)
		if obj then
			local entity = obj:get_luaentity()
			local facedir

			if puncher then
				local yaw = puncher:get_look_horizontal()
				entity.object:set_rotation({x = 0, y = yaw, z = 0})
				local dir = minetest.yaw_to_dir(yaw)
				facedir = minetest.dir_to_facedir(dir)
			elseif punch_dir then
				local yaw = minetest.dir_to_yaw(punch_dir)
				entity.object:set_rotation({x = 0, y = yaw, z = 0})
				facedir = minetest.dir_to_facedir(punch_dir)
			end
			minecart.start_entitycart(entity, pos, facedir or 0)
		end
	end
end

function minecart.show_formspec(pos, clicker)
	local owner = M(pos):get_string("owner")
	if minecart.is_owner(clicker, owner) then
		clicker:get_meta():set_string("cart_pos", P2S(pos))
		minetest.show_formspec(owner, "minecart:userID_node",
			"size[4,3]" ..
			"label[0,0;" .. S("Enter cart number") .. ":]" ..
			"field[1,1;3,1;userID;;]" ..
			"button_exit[1,2;2,1;exit;" .. S("Save") .. "]")
	end
end

-- Player places the node
function minecart.on_nodecart_place(itemstack, placer, pointed_thing)
	local node_name = itemstack:get_name()
	local param2 = minetest.dir_to_facedir(placer:get_look_dir())
	local owner = placer:get_player_name()

	-- Add node
	if minecart.is_rail(pointed_thing.under) then
		minecart.add_nodecart(pointed_thing.under, node_name, param2, {}, owner, 0)
		placer:get_meta():set_string("cart_pos", P2S(pointed_thing.under))
		minecart.show_formspec(pointed_thing.under, placer)
	elseif minecart.is_rail(pointed_thing.above) then
		minecart.add_nodecart(pointed_thing.above, node_name, param2, {}, owner, 0)
		placer:get_meta():set_string("cart_pos", P2S(pointed_thing.above))
		minecart.show_formspec(pointed_thing.above, placer)
	else
		return itemstack
	end

	minetest.sound_play({name = "default_place_node_metal", gain = 0.5},
		{pos = pointed_thing.above})

	if not (creative and creative.is_enabled_for
			and creative.is_enabled_for(placer:get_player_name())) then
		itemstack:take_item()
	end

	return itemstack
end

-- Start the node cart (or dig by shift+leftclick)
function minecart.on_nodecart_punch(pos, node, puncher, pointed_thing)
	local owner = M(pos):get_string("owner")
	local rail = M(pos):get_string("removed_rail")
	if minecart.is_owner(puncher, owner) then
		if puncher:get_player_control().sneak or not minecart.is_rail(pos, rail) then
			local ndef = minetest.registered_nodes[node.name]
			if not ndef.has_cargo or not ndef.has_cargo(pos) then
				local _, owner, userID = minecart.remove_nodecart(pos, node)
				minecart.add_node_to_player_inventory(pos, puncher, node.name)
				minecart.monitoring_remove_cart(owner, userID)
			end
		else
			minecart.start_nodecart(pos, node.name, puncher)
		end
	end
end

minetest.register_on_player_receive_fields(function(player, formname, fields)
    if formname == "minecart:userID_node" then
		if fields.exit or fields.key_enter == "true" then
			local cart_pos = S2P(player:get_meta():get_string("cart_pos"))
			local owner = M(cart_pos):get_string("owner")
			if minecart.is_owner(player, owner) then
				local userID = tonumber(fields.userID) or 0
				if minecart.userID_available(owner, userID) then
					M(cart_pos):set_int("userID", userID)
					M(cart_pos):set_string("infotext",
							minetest.get_color_escape_sequence("#FFFF00") ..
							player:get_player_name() .. ": " .. userID)
					local node = minetest.get_node(cart_pos)
					local entity_name = minecart.tNodeNames[node.name]
					minecart.monitoring_add_cart(owner, userID, cart_pos, node.name, entity_name)
				end
			end
		end
		return true
	end
    return false
end)
