#include "../../script/helpers/entity.lua"
#include "../../config/constants.lua"

VELOCITY = nil
joints = nil
min, max = nil, nil
btn = nil
prevState = nil
state = nil
stateTime = nil
disabled = nil
motorSound = nil
clickUp = nil
clickDown = nil

function init()
    VELOCITY = 0.5

    joints = FindJoints()
    for i = 1, #joints do
        local joint = joints[i]
        local min, max = GetJointLimits(joint)
        joints[i] = { joint, min, max }
    end
    btn = FindBody("garage_control", true)
    prevState = 0
    state = 0
    stateTime = 0.0

    disabled = false
    if not IsHandleValid(btn) then
        btn = GetShapeBody(FindShape("garage_control", true))
        if not IsHandleValid(btn) then
            disabled = cEntity:EnqueueDeletion()
            return
        end
    end
    disableFrameCollision()
    SetTag(btn, "interact", "loc@OPEN")
	motorSound = LoadLoop("vehicle/hydraulic-loop.ogg")
    clickUp = LoadSound("clickup.ogg")
	clickDown = LoadSound("clickdown.ogg")
end

function disableFrameCollision()
    for i = 1, #joints do
        local joint = joints[i][1]
        local shapes = GetJointShapes(joint)
        for j = 1, #shapes do
            local shape = shapes[j]
            SetShapeCollisionFilter(shape, COLLISIONS.WORLD_SPECIAL, COLLISIONS.MAX - COLLISIONS.WORLD_SPECIAL)
        end
        if #shapes > 0 then
            local door = shapes[1]
            local mi, ma = GetShapeBounds(door)
            local list = QueryAabbShapes(mi, ma)
            for j = 1, #list do
                local shape = list[j]
                SetShapeCollisionFilter(shape, COLLISIONS.WORLD_SPECIAL, COLLISIONS.MAX - COLLISIONS.WORLD_SPECIAL)
            end
        end
    end
end

function setState(s)
    prevState = state
    state = s
    stateTime = 0.0
end

function timedOut()
    return stateTime > 10.0
end

function tick(dt)
    if disabled then return end

    if IsBodyBroken(btn) then
        exit()
        return
    else
        for i = #joints, 1, -1 do if IsJointBroken(joints[i][1]) then table.remove(joints, i) end end
        if #joints == 0 then
            exit()
            return
        end
    end

    stateTime = stateTime + dt

    if state == 1 then
        local joint, min = unpack(joints[1])
        local m = GetJointMovement(joint)
        if m <= (min + 0.1) or timedOut() then
            setState(0)
        end
        SetTag(btn, "interact", "loc@OPEN")
    elseif state == 2 then
        local joint, _, max = unpack(joints[1])
        local m = GetJointMovement(joint)
        if m >= (max - 0.1) or timedOut() then
            setState(0)
        end
        SetTag(btn, "interact", "loc@CLOSE")
    end

    if state ~= 0 then
        PlayLoop(motorSound, GetBodyTransform(btn).pos)
    end

    if GetPlayerInteractBody() == btn and InputPressed("interact") then
        if state == 2 or prevState == 2 then
            setState(1)
            PlaySound(clickDown)
            for i = #joints, 1, -1 do
                local joint, min, max = unpack(joints[i])
                if IsJointBroken(joint) then
                    if #joints == 1 then
                        exit()
                    else
                        SetJointMotorTarget(joint, GetJointMovement(joint))
                    end
                    table.remove(joints, i)
                else
                    SetJointMotorTarget(joint, min, VELOCITY)
                end
            end
        else
            setState(2)
            PlaySound(clickUp)
            for i = #joints, 1, -1 do
                local joint, min, max = unpack(joints[i])
                if IsJointBroken(joint) then
                    if #joints == 1 then
                        exit()
                    else
                        SetJointMotorTarget(joint, GetJointMovement(joint))
                    end
                    table.remove(joints, i)
                else
                    SetJointMotorTarget(joint, max, VELOCITY)
                end
            end
        end
    end
end

function exit()
    RemoveTag(btn, "interact")
    for i=1, #joints do
        local joint = joints[i][1]
        local mov = GetJointMovement(joint)
        SetJointMotorTarget(joint, mov)
    end
    disabled = cEntity:EnqueueDeletion()
    motorSound, clickUp, clickDown = nil, nil, nil
end
