local S = minetest.get_translator("elevator")


function elevator.on_receive_fields(pos, _, fields, player)
	if not pos then
		return
	end

	local meta = minetest.get_meta(pos)
	local name = player:get_player_name()

	-- the player wants to quit/exit the formspec; do not save/update anything
	if fields and fields.station_exit and fields.station_exit ~= "" then
		return
	end

	local owner_name      = meta:get_string("owner")
	local station_network = meta:get_string("station_network")
	local station_name    = meta:get_string("station_name")

	-- if there is something wrong with the data
	if not owner_name or not station_network or not station_name then
		minetest.chat_send_player(name, S("Error") .. ": " ..
				S("There is something wrong with the configuration of this station.") ..
					" DEBUG DATA: owner: " .. (owner_name or "?") ..
					" station_name: " .. (station_name or "?") ..
					" station_network: " .. (station_network or "?") .. "."
		)
		print(
			"ERROR: The elevator at " .. minetest.pos_to_string(pos) .. " has a problem: " ..
			" DATA: owner: " .. (owner_name or "?") ..
			" station_name: " .. (station_name or "?") ..
			" station_network: " .. (station_network or "?") .. "."
		)
		return
	end

	local node = minetest.get_node(pos)

	-- the player wants to remove the station
	if fields.station_dig then
		local description

		if node and minetest.get_item_group(node.name, "elevator") == 1 then
			description = "elevator box"
		elseif node and minetest.get_item_group(node.name, "elevator") == 1 then
			description = "elevator"
		elseif node and node.name == "locked_elevator:elevator" then
			description = "locked elevator"
		elseif node and node.name == "locked_elevator:elevator" then
			description = "locked elevator"
		else
			minetest.chat_send_player(name, "Error: Unknown node.")
			return
		end

		-- players with elevator_remove priv can dig the station
		if	    not minetest.check_player_privs(name, { elevator_remove=true })
			-- the function elevator.allow_dig(..) may allow additional digging
			and not elevator.allow_dig(name, owner_name, station_network, pos)
			-- the owner can remove the station
			and owner_name ~= name
			-- stations without owner can be removed by anybody
			and owner_name ~= ""
		then
			minetest.chat_send_player(name,
				S("This %s belongs to %s. You can't remove it."):format(
					description,
					tostring(owner_name)
				)
			)
			return
		end

		-- abort if protected by another mod
		if	minetest.is_protected(pos, name)
			and not minetest.check_player_privs(name, { protection_bypass=true })
		then
			minetest.record_protection_violation(pos, name)
			return
		end

		local player_inventory = player:get_inventory()
		if not player_inventory:room_for_item("main", node.name) then
			minetest.chat_send_player(name, S("You do not have enough room in your inventory."))
			return
		end

		-- give the player the box
		player_inventory:add_item("main", node.name)
		-- remove the box from the data structure
		elevator.remove_box(pos, nil, meta:to_table(), player)
		-- remove the node as such
		minetest.remove_node(pos)
		return
	end


	-- if the box has not been configured yet
	if station_network == "" then
		elevator.add_target(fields.station_name, fields.station_network, pos, name, meta, fields.owner)
		return
	end

	if fields.open_door then
		elevator.open_close_door(pos, player, "toggle")
		return
	end

	-- the owner or players with the elevator_attach priv can move stations up or down in the list
	if fields.move_up or fields.move_down then
		elevator.update_formspec(pos, name, fields)
		return
	end

	if not fields.target then
		minetest.chat_send_player(name, S("Please click on the target you want to travel to."))
		return
	end

	local network = elevator.get_network(owner_name, station_network)

	if not network then
		elevator.add_target(station_name, station_network, pos, owner_name, meta, owner_name)
	end

	if node ~= nil and elevator.is_elevator(node.name) then
		for k,_ in pairs(network) do
			if network[k].nr == fields.target then
				fields.target = k
				-- break ??
			end
		end
	end

	local target_station = network[fields.target]

	-- if the target station is gone
	if not target_station then
		minetest.chat_send_player(name,
				S("Station '@1' does not exist (anymore?)" ..
					" " .. "on this network.", fields.target or "?")
		)
		elevator.update_formspec(pos, name, nil)
		return
	end


	if not elevator.allow_travel(name, owner_name, station_network, station_name, fields.target) then
		return
	end
	minetest.chat_send_player(name, S("Initiating transfer to station '@1'.", fields.target or "?"))

	if elevator.elevator_sound_enabled then
		if node.name == "elevator:elevator" then
			minetest.sound_play("elevator_bell", {
				pos = pos,
				gain = 0.75,
				max_hear_distance = 10
			})
		else
			minetest.sound_play("elevator_travel", {
				pos = pos,
				gain = 0.75,
				max_hear_distance = 10
			})
		end
	end

	if elevator.elevator_effect_enabled then
		minetest.add_entity(vector.add(pos, { x=0, y=0.5, z=0 }), "elevator:effect")  -- it self-destructs after 20 turns
	end

	-- close the doors at the sending station
	elevator.open_close_door(pos, player, "close")

	-- transport the player to the target location

	-- may be 0.0 for some versions of MT 5 player model
	local player_model_bottom = tonumber(minetest.settings:get("player_model_bottom")) or -.5
	local player_model_vec = vector.new(0, player_model_bottom, 0)
	local target_pos = target_station.pos

	local top_pos = vector.add(pos, { x=0, y=2, z=0 })
	local top_node = minetest.get_node(top_pos)
	if top_node.name ~= "elevator:hidden_top" then
		local def = minetest.registered_nodes[top_node.name]
		if def and def.buildable_to then
			minetest.set_node(top_pos, { name="elevator:hidden_top" })
		end
	end

	player:move_to(vector.add(target_pos, player_model_vec), false)

	-- check if the box has at the other end has been removed.
	local target_node = minetest.get_node_or_nil(target_pos)
	if target_node ~= nil then
		local target_node_def = minetest.registered_nodes[target_node.name]
		local has_elevator_group = target_node_def.groups.elevator or target_node_def.groups.elevator

		if not has_elevator_group then
			-- provide information necessary to identify the removed box
			local oldmetadata = {
				fields = {
					owner           = owner_name,
					station_name    = fields.target,
					station_network = station_network
				}
			}

			elevator.remove_box(target_pos, nil, oldmetadata, player)
			-- send the player back as there's no receiving elevator
			player:move_to(pos, false)
		else
			elevator.rotate_player(target_pos, player, 0)
		end
	end
end
