local gc_newQuad=love.graphics.newQuad

---Get distance between two points
---@param x1 number
---@param y1 number
---@param x2 number
---@param y2 number
---@return number
local function math_distance(x1,y1,x2,y2)
    return ((x1-x2)^2+(y1-y2)^2)^.5
end

local function mDrawQ(obj,quad,x,y,a,k)
    local _,_,w,h=quad:getViewport()
    love.graphics.draw(obj,quad,x,y,a,k,nil,w*.5,h*.5)
end

local empty_quad
-- A table containing quads used to draw icons for virtual control system.
local virtual_quad=setmetatable((function()
    local t={}
    local w=180
    empty_quad=gc_newQuad(0,0,1,1,5*w,7*w)
    for i,name in next,{
        'left','right','up','down','',
        'rotate_right','rotate_left','','','',
        'menu_deicde','','menu_back','','',
        '','','','','',
        '','','back','','',
        '','','','','',
        '','','','','select',
    } do if #name>0 then t[name]=gc_newQuad((i-1)%4*w,math.floor((i-1)/4)*w,w,w,4*w,3*w) end end -- 4x2 is the size of entire texture
    return t
end)(),{
    __index=function() return empty_quad end
})
local virtual_texture=love.graphics.newImage('game/vctrlTexture.png')


local control_type={}

control_type.button={}
control_type.button.__index=control_type.button
function control_type.button:new(data)
    local data=data or {}
    return setmetatable({
        show=data.show or true,
        x=data.x or 320,
        y=data.y or 240,
        r=data.r or 80, -- size
        shape=data.shape or 'circle',
        key=data.key or 'X',
        iconSize=data.iconSize or 80,
        alpha=data.alpha or 0.75,
        quad=virtual_quad[data.icon]
    },self)
end
function control_type.button:reset()
    self.pressed=false
    self.lastPressTime=-1e99
end
function control_type.button:press()
    self.pressed=true
    self.lastPressTime=love.timer.getTime()
    love.keypressed(self.key, love.keyboard.getScancodeFromKey(self.key))
end
function control_type.button:release()
    self.pressed=false
    love.keyreleased(self.key,love.keyboard.getScancodeFromKey(self.key))
end
function control_type.button:drag(dx,dy)
    self.x,self.y=self.x+dx,self.y+dy
end
function control_type.button:draw(forceLight)
    love.graphics.setLineWidth(4)
    if self.shape=='circle' then
        love.graphics.setColor(1,1,1,self.pressed and .5 or .05)
        love.graphics.circle('fill',self.x,self.y,self.r-4)

        love.graphics.setColor(1,1,1)
        love.graphics.circle('line',self.x,self.y,self.r-2)
    elseif self.shape=='square' then
        love.graphics.setColor(1,1,1,self.pressed and .5 or .05)
        love.graphics.rectangle('fill',self.x-self.r-4,self.y-self.r-4,self.r*2+8,self.r*2+8)

        love.graphics.setColor(1,1,1)
        love.graphics.rectangle('line',self.x-self.r-2,self.y-self.r-2,self.r*2+4,self.r*2+4)
    end
    if self.iconSize>0 and self.quad then
        love.graphics.setColor(1,1,1,forceLight and 1 or self.alpha)
        local _,_,w,h=self.quad:getViewport()
        mDrawQ(
            virtual_texture,
            self.quad,
            self.x,self.y,0,
            self.iconSize/100*math.min(self.r*2/w,self.r*2/h)
        )
    end
end
function control_type.button:getDistance(x,y)
    if self.shape=='circle' then
        return math_distance(x,y,self.x,self.y)/self.r
    elseif self.shape=='square' then
        return math.max(math.abs(x-self.x),math.abs(y-self.y))/self.r
    end
end

local touches={}
local global_toggle=false
VCTRL={}
-- VCTRL.focus=nil -- Focusing buttons

---@param toggle boolean|false
---Enabling virtual control or not
function VCTRL.toggle(toggle)
    global_toggle=toggle
end

---@param ... table
---@class data
---@field type string
---@field x number
---@field y number
---@field shape string
---@field key string
---@field iconSize number
---@field alpha number
---Adding (multiple) virtual button(s)
function VCTRL.new(...)
    for _,d in pairs(...) do
        local t=d.type
        d.type=nil
        table.insert(VCTRL,control_type[t]:new(d))
    end
end

function VCTRL.press(x,y,id)
    if not global_toggle then return end
    local obj,closestDist=false,1e99
    for i=1,#VCTRL do
        local w=VCTRL[i]
        if w.show then
            local d=w:getDistance(x,y)
            if d<=1 and d<closestDist then
                obj,closestDist=w,d
            end
        end
    end
    if obj then
        touches[id]=obj
        obj:press(x,y,id)
        -- VCTRL.focus=obj
        return true
    end
end

function VCTRL.release(id)
    if not global_toggle then return end
    if touches[id] then
        touches[id]:release()
        return true
    end
    touches[id]=nil
end

function VCTRL.drag(dx,dy,id)
    if not global_toggle then return end
    if touches[id] then
        touches[id]:drag(dx,dy)
    end
end

function VCTRL.draw(forceLight)
    if not global_toggle then return end
    for i=1,#VCTRL do
        if VCTRL[i].show then
            VCTRL[i]:draw(forceLight)
        end
    end
end