local Bindings       = require('UI.Bindings')
local Widget         = require('UI.Widget')

local OptionSlider   = {}
OptionSlider.__index = OptionSlider
setmetatable(OptionSlider, Widget)

OptionSlider.value     = 0
OptionSlider.minValue  = 0
OptionSlider.maxValue  = 1
OptionSlider.elems     = nil
OptionSlider.getFn     = function() return 0.0 end
OptionSlider.setFn     = function(value) Log.Warn('OptionSlider - setFn has not been assigned') end

OptionSlider.dimBox    = 14

OptionSlider.name      = 'OptionSlider'
OptionSlider.focusable = true
OptionSlider.draggable = true

OptionSlider:setHeight(14)
OptionSlider:setAlign(0.0, 0.5)
OptionSlider.minX = 128

function OptionSlider:onClick(state)
    self:setNextValue()
end

function OptionSlider:onInput(state)
    if Bindings.Right:get() > 0 or Bindings.Down:get() > 0 then
        self:setNextValue()
    end

    if Bindings.Left:get() > 0 or Bindings.Up:get() > 0 then
        self:setPrevValue()
    end
end

function OptionSlider:onUpdate(state)
    Widget.onUpdate(self, state)

    local getValue = self.getFn()
    if getValue < self.minValue or getValue > self.maxValue then
        if not self.didRangeWarning then
            self.didRangeWarning = true
            Log.Warn('OptionSlider - Value returned from getFn (%s) is out of the range [%s, %s]',
                self.getFn(), self.minValue, self.maxValue
            )
        end
        getValue = Math.Clamp(getValue, self.minValue, self.maxValue)
    end

    self.value = getValue
end

function OptionSlider:onDraw(focus, active)
    local x, y, sx, sy = self:getRectGlobal()

    -- triangles
    local triSize = 8
    local tri2 = triSize / 2
    local padRight = Vec2f(x + sx - triSize, y + sy - tri2)
    local a = padRight + Vec2f(0, 0)
    local b = padRight + Vec2f(0, -triSize)
    local c = padRight + Vec2f(tri2, -tri2)
    local padLeft = Vec2f(x, y + sy - tri2)
    local a1 = padLeft + Vec2f(0, -tri2)
    local b1 = padLeft + Vec2f(tri2, -triSize)
    local c1 = padLeft + Vec2f(tri2, 0)
    self:getColor(focus, active, Config.ui.color.fill)
    Draw.Tri(a, b, c);
    Draw.Tri(a1, b1, c1);

    -- Value Label
    local font = Config.ui.font.normal
    local valName = self.elems[self.value]
    local bound = font:getSize(valName)
    local labelX = x - bound.x + (sx - bound.z) / 2 - triSize
    local labelY = y - bound.y + (sy + bound.y) / 2
    local color = Config.ui.color.textNormal
    local textX = labelX + triSize
    font:draw(valName, textX, labelY, color)
end

function OptionSlider:setNextValue()
    self.value = Math.Wrap(self.value + 1, self.minValue, self.maxValue)
    self.setFn(self.value)
end

function OptionSlider:setPrevValue()
    self.value = Math.Wrap(self.value - 1, self.minValue, self.maxValue)
    self.setFn(self.value)
end

function OptionSlider.Create(getFn, setFn, elems, val)
    local self = setmetatable({}, OptionSlider)
    if getFn then self.getFn = getFn end
    if setFn then self.setFn = setFn end
    if elems then self.minValue = 1 end
    if elems then self.maxValue = #elems end
    if elems then self.elems = elems end
    if val then self.value = val end
    return self
end

return OptionSlider
