local super = require "View"

Line = super:new()

local _min = math.min
local _max = math.max

local handles = {
    PointHandle:new{
        actionName = "Modify Line",
        location = Hook:new(
            function(self)
                local line = self:line()
                return line.x1, line.y1
            end,
            function(self, x, y)
                local line = self:line()
                line.x1 = x
                line.y1 = y
                self:setLine(line)
            end),
    },
    PointHandle:new{
        actionName = "Modify Line",
        location = Hook:new(
            function(self)
                local line = self:line()
                return line.x2, line.y2
            end,
            function(self, x, y)
                local line = self:line()
                line.x2 = x
                line.y2 = y
                self:setLine(line)
            end),
    },
}

local defaults = {
    thickness = 2,
}

local nilDefaults = {
}

local inspectorInfo = {
    {'Stroke', {'thickness'}, nil, 'Thickness'},
}

function Line:new()
    self = super.new(self)
    
    for k, v in pairs(defaults) do
        self:addProperty(k, v)
    end
    for _, k in pairs(nilDefaults) do
        self:addProperty(k)
    end
    
    return self
end

function Line:unarchiveStroke(archived)
    -- NOTE: Version 1.3.2 and earlier stored line stroke colors separately from the color scheme.
    self._legacyStroke = unarchive(archived)
end

function Line:unarchived()
    if self._legacyStroke then
        self:setPaint(ColorScheme.strokePaint, self._legacyStroke)
    end
    super.unarchived(self)
end

function Line:unarchiveLine(archived)
    self.x1 = archived.x1
    self.y1 = archived.y1
    self.x2 = archived.x2
    self.y2 = archived.y2
end

function Line:archive()
    local typeName, properties = Object.archive(self)
    properties.line = self:line()
    return typeName, properties
end

function Line:getHandles()
    return appendtables({}, handles)
end

function Line:getInspectors()
    local list = super.getInspectors(self)
    list:add(self:createColorInspector(ColorScheme.strokePaint, nil, 'Stroke'))
    for i = 1, #inspectorInfo do
        local info = inspectorInfo[i]
        list:add(self:createInspector(unpack(info)))
    end
    return list
end

function Line:line()
    return {
        x1 = self.x1,
        y1 = self.y1,
        x2 = self.x2,
        y2 = self.y2,
    }
end

function Line:setLine(line)
    local oldLine = self:line()
    self:addUndo(function() self:setLine(oldLine) end)
    self:invalidate(self)
    self.x1 = _max(line.x1, 0)
    self.y1 = _min(line.y1, 0)
    self.x2 = _max(line.x2, 0)
    self.y2 = _min(line.y2, 0)
    self:invalidate(self)
end

function Line:rect()
    return Rect:new{
        left = self.x1,
        bottom = self.y1,
        right = self.x2,
        top = self.y2,
    }
end

function Line:setRect(rect)
    local constrainedRect = Rect:new(rect)
    constrainedRect.left = _max(rect.left, 0)
    constrainedRect.right = constrainedRect.left + (rect.right - rect.left)
    constrainedRect.top = _min(rect.top, 0)
    constrainedRect.bottom = constrainedRect.top - (rect.top - rect.bottom)
    rect = constrainedRect
    local line = self:line()
    local oldRect = self:rect()
    if oldRect:width() == 0 then
        line.x1 = rect:midx()
        line.x2 = rect:midx()
    else
        line.x1 = rect:minx() + rect:width() * (line.x1 - oldRect:minx()) / oldRect:width()
        line.x2 = rect:minx() + rect:width() * (line.x2 - oldRect:minx()) / oldRect:width()
    end
    if oldRect:height() == 0 then
        line.y1 = rect:midy()
        line.y2 = rect:midy()
    else
        line.y1 = rect:miny() + rect:height() * (line.y1 - oldRect:miny()) / oldRect:height()
        line.y2 = rect:miny() + rect:height() * (line.y2 - oldRect:miny()) / oldRect:height()
    end
    self:setLine(line)
end

function Line:padding()
    local thickness = self:getProperty('thickness')
    return {
        left = thickness/2,
        bottom = thickness/2,
        right = thickness/2,
        top = thickness/2,
    }
end

function Line:draw(canvas)
    local stroke = self:getPaint(ColorScheme.strokePaint)
    local thickness = self:getProperty('thickness')
    if canvas:isHitTest() then
        thickness = math.max(thickness, 8)
    end
    local path = Path.line(self:line())
    canvas:setThickness(thickness):setPaint(stroke):stroke(path)
end

return Line
