-- LUALOCALS < ---------------------------------------------------------
local klots, minetest, vector
    = klots, minetest, vector
-- LUALOCALS > ---------------------------------------------------------

local modname = minetest.get_current_modname()

local nodename = modname .. ":teleporter"
local particlename = modname .. ":teleporter_particles"

local function getdest(pos)
	local meta = minetest.get_meta(pos)
	local topos = meta:get_string("dest") or ""
	topos = topos and topos ~= "" and minetest.deserialize(topos)
	if not topos then return end
	topos.x = topos.x + pos.x
	topos.y = topos.y + pos.y
	topos.z = topos.z + pos.z
	return topos
end

minetest.register_node(particlename,
	{tiles = {modname .. "_teleparticles.png"}})

minetest.register_node(nodename, {
		description = "Teleporter",
		drawtype = "airlike",
		walkable = false,
		paramtype = "light",
		sunlight_propagates = true,
		pointable = klots.editmode or false,
		groups = {
			auto_timer = 100
		},
		on_timer = function(pos)
			minetest.add_particlespawner({
					node = {name = particlename},
					collisiondetection = false,
					amount = 100,
					time = 1,
					minpos = {x = pos.x - 0.5, y = pos.y - 0.5, z = pos.z - 0.5},
					maxpos = {x = pos.x + 0.5, y = pos.y + 1.5, z = pos.z + 0.5},
					minvel = {x = -1.5, y = -1.5, z = -1.5},
					maxvel = {x = 1.5, y = 1.5, z = 1.5},
					minexptime = 1,
					maxexptime = 1,
					minsize = 2,
					maxsize = 3
				})
			minetest.get_node_timer(pos):start(1)
		end,
		on_construct = function(pos)
			minetest.get_node_timer(pos):start(0.001)
		end,
		on_rightclick = klots.editmode and function(pos, _, clicker)
			local pname = clicker and clicker.get_player_name and clicker:get_player_name()
			if not pname then return end
			local dest = getdest(pos) or {x = 0, y = 0, z = 0, control = "normal"}
			klots.show_editor(clicker, pos, minetest.serialize(dest), function(text)
					local topos = minetest.deserialize(text)
					topos.x = topos.x - pos.x
					topos.y = topos.y - pos.y
					topos.z = topos.z - pos.z
					minetest.get_meta(pos):set_string("dest", minetest.serialize(topos))
				end)
		end
	})

if not klots.editmode then
	klots.register_playerstep(function(player, data, dtime)
			local pos = player:get_pos()

			local found = data.tpos
			if not (found and minetest.get_node(found).name == nodename) then
				found = minetest.find_node_near(pos, 3, nodename, true)
				if not found then return end
				found.y = found.y - 0.49
				data.tpos = found
			end

			if vector.distance(pos, found) > 5 then
				data.tpos = nil
				return
			end

			local topos = getdest(found)
			if not topos then return end

			if vector.equals(vector.round(pos), vector.round(found)) then
				data.tpos = nil
				return klots.player_teleport(player, found, topos)
			end

			klots.player_control_set(player, "zerognofly")
			klots.player_control_apply(player, function(obj)
					local dv = vector.subtract(found, pos)
					dv = vector.multiply(dv, dtime * 10)
					local vel = obj:get_velocity()
					dv = vector.add(dv, vector.multiply(vel,
							(0.5 ^ dtime) - 1))
					obj:add_velocity(dv)
				end)
		end)
end
