local super = require "Control"

ThumbnailPicker = super:new()

local OUTER_PADDING = 8
local INNER_PADDING = 4
local PADDING = OUTER_PADDING + INNER_PADDING
local SEPARATOR_HEIGHT = 2

ThumbnailPicker.DRAW = {}
ThumbnailPicker.CLIP = {}

function ThumbnailPicker:new()
    self = super.new(self)
    
    self._thumbnails = {}
    self._index = nil
    self._hintedIndex = nil
    self._pressingIndex = nil
    self._pressing = false
    self._style = ThumbnailPicker.DRAW
    
    return self
end

function ThumbnailPicker:draw(canvas)
    local style = self._style
    local rect = self:rect()
    local top = rect.top

    for index = 1, #self._thumbnails do
        local thumbnail = self._thumbnails[index]
        local thumbnailRect = Rect:new{
            left = rect.left,
            bottom = top - self:getItemHeight(thumbnail),
            right = rect.right,
            top = top,
        }
        if thumbnail then
            canvas:preserve(function(canvas)
                canvas:setPaint(self:getBackgroundPaint(index))
                    :fill(Path.rect(thumbnailRect))
                    :setPaint(self:getHintPaint(index))
                    :setThickness(1)
                    :stroke(Path.rect(thumbnailRect:insetXY(1.5, 1.5)))
                if style == ThumbnailPicker.DRAW then
                    canvas:drawIcon(thumbnail, thumbnailRect:insetXY(OUTER_PADDING, OUTER_PADDING))
                elseif style == ThumbnailPicker.CLIP then
                    canvas:clipIcon(thumbnail, thumbnailRect:insetXY(OUTER_PADDING, OUTER_PADDING))
                        :setPaint(self:getForegroundPaint(index))
                        :fill(Path.rect(thumbnailRect))
                end
            end)
        else
            canvas:setPaint(Color.gray(0.93))
                :fill(Path.rect(thumbnailRect:insetXY(PADDING, OUTER_PADDING)))
        end
        top = thumbnailRect.bottom
    end
end

function ThumbnailPicker:setStyle(style)
    self._style = style
end

function ThumbnailPicker:addThumbnail(thumbnailFunction)
    self._thumbnails[#self._thumbnails + 1] = thumbnailFunction
end

function ThumbnailPicker:addSeparator()
    self._thumbnails[#self._thumbnails + 1] = false
end

function ThumbnailPicker:removeAllThumbnails()
    self._thumbnails = {}
end

function ThumbnailPicker:getSelectedIndex()
    return self._index
end

function ThumbnailPicker:setSelectedIndex(index)
    self._index = index
    self:invalidate()
end

function ThumbnailPicker:getHintedIndex()
    return self._hintedIndex
end

function ThumbnailPicker:setHintedIndex(index)
    self._hintedIndex = index
    self:invalidate()
end

function ThumbnailPicker:getItemHeight(item)
    if item then
        return 0.8 * (self:rect():width() - 2 * PADDING) + 2 * PADDING
    else
        return OUTER_PADDING + SEPARATOR_HEIGHT + OUTER_PADDING
    end
end

function ThumbnailPicker:getBackgroundPaint(index)
    if index == self._index then
        return Color.highlight(0.25)
    elseif index == self._pressingIndex and self._pressing then
        return Color.gray(0.93)
    else
        return Color.invisible
    end
end

function ThumbnailPicker:getHintPaint(index)
    if index == self._hintedIndex and index ~= self._index then
        return Color.highlight(0.25)
    else
        return Color.invisible
    end
end

function ThumbnailPicker:getForegroundPaint(index)
    if index == self._index then
        return Color.tint(1)
    else
        return Color.gray(0, 0.75)
    end
end

function ThumbnailPicker:getThumbnailRect(thumbnailIndex)
    local rect = self:rect()
    local top = rect.top
    for index = 1, thumbnailIndex - 1 do
        local item = self._thumbnails[index]
        top = top - self:getItemHeight(item)
    end
    return Rect:new{
        left = rect.left,
        bottom = top - self:getItemHeight(self._thumbnails[thumbnailIndex]),
        right = rect.right,
        top = top,
    }
end

function ThumbnailPicker:down(x, y)
    local rect = self:rect()
    if rect:contains(x, y) then
        self._pressingIndex = nil
        self._pressing = false
        local top = rect.top
        for index = 1, #self._thumbnails do
            local item = self._thumbnails[index]
            local bottom = top - self:getItemHeight(item)
            if item and bottom <= y and y <= top then
                self._pressingIndex = index
                self._pressingRect = Rect:new{ left = rect.left, bottom = bottom, right = rect.right, top = top }
                self._pressing = true
                self:invalidate()
                return true
            end
            top = bottom
        end
    end
end

function ThumbnailPicker:dragged(x, y)
    local rect = self._pressingRect
    self._pressing = rect:contains(x, y)
    self:invalidate()
end

function ThumbnailPicker:up()
    local index = self._pressingIndex
    if index and self._pressing then
        self._index = index
        self._pressingIndex = nil
        self._pressingRect = false
        self._pressing = false
        self:invalidate()
        self:action(index)
    end
end

return ThumbnailPicker
