local super = require "Object"

ButtonBarElement = super:new()

ButtonBarElement.defaultFont = Font.system(13)

function ButtonBarElement:new(height, tag, icon, text, font)
    self = super.new(self)
    
    self.pressing = false
    self.hovering = false
    self.state = false
    
    self.height = height
    self.tag = tag
    self.icon = icon
    self.text = text
    if text then
        self.styledString = StyledString.new(text, { font = font or self.defaultFont })
        self.truncatedString = self.styledString
    end
    
    self.iconWidth = 0
    self.iconInset = 0
    self.textWidth = 0
    self.iconTextSpacing = 6
    self.textInset = 0
    self.left = 0
    self.width = 0
    self.desiredWidth = 0
    self.truncated = false
    
    self:measure()
    
    return self
end

function ButtonBarElement:measure()
    local iconWidth, iconInset
    local icon = self.icon
    if icon then
        local iconRect = Rect:new(icon:canvas():metrics():rect())
        local iconHeight = math.min(iconRect:height(), self.height - 6)
        iconWidth = iconRect:width() * iconHeight / iconRect:height()
        iconInset = (self.height - 1 - iconHeight) / 2
    end
    self.iconWidth = iconWidth or 0
    self.iconInset = iconInset or 0
    local textWidth, textInset
    local styledString = self.styledString
    if styledString then
        local textRect = styledString:measure()
        textWidth = textRect:width()
        textInset = 10
    end
    self.textWidth = textWidth or 0
    self.textInset = textInset or 0
    local width = math.max(self.iconInset + self.iconWidth + self.iconTextSpacing, self.textInset) + self.textWidth + self.textInset
    self.desiredWidth = math.floor(0.5 + width)
end

function ButtonBarElement:draw(canvas, isActive)
    local height = self.height
    local width = self.width
    local rect = Rect:new{left = 0, bottom = 0, right = width, top = height}
    local fillPath = Path.rect(rect)
    
    canvas:setPaint(self:backgroundPaint(rect))
        :fill(fillPath)
    canvas:setPaint(self:strokePaint())
        :setThickness(1)
        :stroke(Path.line{x1 = rect.left, y1 = rect.top - 0.5, x2 = rect.right, y2 = rect.top - 0.5})
    
    local icon = self.icon
    if icon then
        local iconWidth = self.iconWidth
        local iconInset = self.iconInset
        local iconRect = Rect:new{left = iconInset, bottom = 1 + iconInset, right = iconInset + iconWidth, top = height - iconInset}
        canvas:preserve(function(canvas)
            canvas:clipIcon(icon, iconRect)
                :setPaint(self:contentPaint())
                :fill(fillPath)
        end)
    end
    
    local styledString = self.truncatedString
    if styledString then
        local textWidth = self.textWidth
        local textInset = self.textInset
        local textRect = styledString:measure()
        local x = width - textInset - 0.5 * textWidth - textRect:minx()
        local y = math.ceil(0.5 * (height - textRect:height()) - textRect:miny())
        canvas:preserve(function(canvas)
            canvas:setPaint(self:contentPaint())
                :drawText(styledString, x, y, 0.5)
        end)
    end
end

function ButtonBarElement:backgroundPaint(rect)
    if self.pressing then
        return Color.gray(0.8, 1)
    elseif self.state then
        return Color.gray(0.96, 1)
    elseif self.hovering then
        return Color.gray(0.83, 1)
    else
        return Color.gray(0.87, 1)
    end
end

function ButtonBarElement:strokePaint()
    return Color.gray(0.7)
end

function ButtonBarElement:contentPaint()
    if self.pressing then
        return Color.gray(0.1)
    elseif self.state then
        return Color.gray(0.2)
    else
        return Color.gray(0.3)
    end
end

function ButtonBarElement:setHeight(height)
    if self.height == height then
        return
    end
    self.height = height
    self:measure()
    self:invalidate()
end

function ButtonBarElement:getHeight(height)
    return self.height
end

function ButtonBarElement:setWidth(width)
    width = math.floor(0.5 + width)
    if self.width == width then
        return
    end
    self.width = width
    if self.styledString then
        self.textWidth = self.width - math.max(self.iconInset + self.iconWidth + self.iconTextSpacing, self.textInset) - self.textInset
        local availableWidth = self.textWidth + 0.5 * self.textInset
        local stringWidth = self.styledString:measure():width()
        if stringWidth > availableWidth then
            self.truncated = true
            self.truncatedString = self.styledString:truncate(availableWidth)
        else
            self.truncated = false
            self.truncatedString = self.styledString
        end
    end
    self:invalidate()
end

function ButtonBarElement:getWidth()
    return self.width
end

function ButtonBarElement:getDesiredWidth()
    return self.desiredWidth
end

function ButtonBarElement:getSpacing()
    return 1
end

function ButtonBarElement:setLeft(left)
    self.left = left
end

function ButtonBarElement:getLeft()
    return self.left
end

function ButtonBarElement:getTag()
    return self.tag
end

function ButtonBarElement:getText()
    return self.text, self.truncated
end

function ButtonBarElement:isPressing()
    return self.pressing
end

function ButtonBarElement:setPressing(pressing)
    if self.pressing == pressing then
        return
    end
    self.pressing = pressing
    self:invalidate()
end

function ButtonBarElement:isHovering()
    return self.hovering
end

function ButtonBarElement:setHovering(hovering)
    if self.hovering == hovering then
        return
    end
    self.hovering = hovering
    self:invalidate()
end

function ButtonBarElement:getState()
    return self.state
end

function ButtonBarElement:setState(state)
    if self.state == state then
        return
    end
    self.state = state
    self:invalidate()
end

return ButtonBarElement
