
aom_gates.gate_controller = {}

aom_gates.adjacent = {
    vector.new( 1, 0, 0),
    vector.new(-1, 0, 0),
    vector.new( 0, 1, 0),
    vector.new( 0,-1, 0),
    vector.new( 0, 0, 1),
    vector.new( 0, 0,-1),
}

function aom_gates.get_dir_of_gates(pos)
    local first_dir
    local node
    for i, d in ipairs(aom_gates.adjacent) do
        node = minetest.get_node(pos + d)
        if (minetest.get_item_group(node.name, "aom_gates") > 0) then
            first_dir = vector.copy(d)
            break
        end
    end
    return first_dir
end

function aom_gates.get_controller_on_best_axis(pos, force_axis)
    local first_dir = force_axis
    local node
    if not first_dir then
        for i, d in ipairs(aom_gates.adjacent) do
            node = minetest.get_node(pos + d)
            if minetest.get_item_group(node.name, "aom_gates") > 0 then
                first_dir = vector.copy(d)
                break
            end
        end
    end
    if not first_dir then return false end
    local p = pos
    for i = 1, 20 do
        p = p + first_dir
        node = minetest.get_node(p)
        if minetest.get_item_group(node.name, "aom_gates_controller") > 0 then
            return p
        elseif minetest.get_item_group(node.name, "aom_gates") == 0 then
            return false
        end
    end
end

function aom_gates.get_controller_above(pos)
    local p = vector.copy(pos)
    local node
    for i = 1, 20 do
        p.y = pos.y + i
        node = minetest.get_node(p)
        if minetest.get_item_group(node.name, "aom_gates_controller") > 0 then
            return p
        elseif minetest.get_item_group(node.name, "aom_gates") == 0 then
            return false
        end
    end
end

-- gets how many axis are equal between two vectors, `v` and `b`
function aom_gates.get_vector_axis_overlap(v, b)
    local hits = 0
    for i, axis in ipairs({"x", "y", "z"}) do
        if v[axis] == b[axis] then hits = hits + 1 end
    end
    return hits
end

---As if a player used it
function aom_gates.gate_controller.activate(pos, node, clicker)
    local nt = minetest.get_node_timer(pos)
    if nt:is_started() then
        if minetest.is_player(clicker) then
            minetest.sound_play("aom_not_allowed", {
                gain = 0.2,
                pos = pos,
                to_player = clicker:get_player_name(),
            })
        end
        return
    end
    nt:start(2)
    local above = minetest.get_node(vector.offset(pos, 0, 1, 0))
    local ndef = minetest.registered_nodes[node.name]
    if ndef and ndef._gate_open_sound then
        minetest.sound_play(ndef._gate_open_sound.name, {
            pos = pos,
            gain = ndef._gate_open_sound.gain or 1,
            pitch = ndef._gate_open_sound.pitch or 1 + math.random() * 0.2-0.1,
        })
    end
    if minetest.get_item_group(above.name, "aom_gates_open") > 0 then
        local controller_pos_above = aom_gates.get_controller_above(pos)
        if controller_pos_above then
            node_updates.cause_single_update(
                controller_pos_above, "use_gate_controller",
                clicker, {
                    start = controller_pos_above,
                    _delay = 0.0,
                    _count = 20
                }
            )
            return
        else
            -- minetest.log("nothing found above")
        end
    end
    node_updates.cause_single_update(
        pos, "use_gate_controller",
        clicker, {
            start = pos,
            _delay = 0.0,
            _count = 40
        }
    )
end


function aom_gates.gate_controller._on_wire_input(pos, user, source)
    local node = minetest.get_node_or_nil(pos)
    if not node then return end
    aom_gates.gate_controller.activate(pos, node, user)
end

function aom_gates.gate_controller.on_rightclick(pos, node, clicker, itemstack, pointed_thing)
    aom_gates.gate_controller.activate(pos, node, clicker)
end

function aom_gates.gate_controller._on_node_update(pos, cause, user, data)
    if cause ~= "use_gate_controller" then return end
    if not data then return end
    -- prevent loops / overloads
    if aom_gates.get_vector_axis_overlap(data.start, pos) < 2 then return end

    local dir = aom_gates.get_dir_of_gates(pos)
    if dir then
        aom_gates.switch_gate(pos + dir, dir)
    else
        -- minetest.log("no dir")
    end
    local nt = minetest.get_node_timer(pos)
    nt:start(2)
    return data
end

function aom_gates.register_gate_controller(name, def)
    def = table.copy(def)
    def._original_name = name
    def.name = name
    if def._gate_no_rightclick == nil then
        def.on_rightclick = aom_gates.gate_controller.on_rightclick
    end
    def._on_node_update = aom_gates.gate_controller._on_node_update
    def.groups = table.copy(def.groups)
    -- def.groups.aom_gates = 1
    def.groups.aom_gates_controller = 1
    def._on_wire_input = aom_gates.gate_controller._on_wire_input

    minetest.register_node(def.name, def)
end
