local super = require "GraphLayer"

BubbleGraphLayer = super:new()

local defaults = {
}

local nilDefaults = {
    'x', 'y', 'value', 'size', 'paint',
}

local freeGetterNames = {'x', 'y'}
local constrainedGetterNames = {'#', 'value'}
local commonGetterNames = {'size', 'paint'}

local freeInspectorInfo = {
    {'KeyArtifact', {'x'}, 'X'},
    {'KeyArtifact', {'y'}, 'Y'},
}

local constrainedInspectorInfo = {
    {'KeyArtifact', {'value'}, 'Value'},
}

local commonInspectorInfo = {
    {'KeyArtifact', {'size'}, 'Size'},
    {'Color', {'getPaint:setPaint', custom = 'hasExplicitPaint:'}, 'Color'},
}

local _sqrt = math.sqrt

function BubbleGraphLayer: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 BubbleGraphLayer:unarchived()
    local dataset = self:getDataset()
    if dataset then
        if self:isPositionConstrained() then
            if self:getProperty('value') == nil and self:getProperty('size') == nil then
                local sizeFields = self:peerPropertyKeyArtifactValues(BubbleGraphLayer, 'size')
                local sizeField = dataset:pickField('number', sizeFields)
                if sizeField then
                    self:setProperty('size', KeyArtifact:new(sizeField))
                end
                local valueFields = self:peerPropertyKeyArtifactValues(BubbleGraphLayer, 'value')
                local valueField = dataset:pickField('number', valueFields)
                if valueField then
                    self:setProperty('value', KeyArtifact:new(valueField))
                end
            end
        else
            if self:getProperty('x') == nil and self:getProperty('y') == nil and self:getProperty('size') == nil then
                local sizeFields = self:peerPropertyKeyArtifactValues(BubbleGraphLayer, 'size')
                local sizeField = sizeFields[#sizeFields]
                local xFields = self:peerPropertyKeyArtifactValues(GraphLayer, 'x')
                local xField = xFields[#xFields] or dataset:pickField(self:getParent():getHorizontalAxis():getPreferredType(), { sizeField })
                local yFields = self:peerPropertyKeyArtifactValues(BubbleGraphLayer, 'y')
                yFields[#yFields + 1] = sizeField
                yFields[#yFields + 1] = xField
                local yField = dataset:pickField(self:getParent():getVerticalAxis():getPreferredType(), yFields)
                if xField and yField then
                    self:setProperty('x', KeyArtifact:new(xField))
                    self:setProperty('y', KeyArtifact:new(yField))
                end
                sizeField = sizeField or dataset:pickField('number', { xField, yField })
                if sizeField then
                    self:setProperty('size', KeyArtifact:new(sizeField))
                end
            end
        end
    end
    super.unarchived(self)
end

function BubbleGraphLayer:getGetterPieceNames(constrained)
    local result = {}
    if constrained then
        appendtables(result, constrainedGetterNames)
    else
        appendtables(result, freeGetterNames)
    end
    appendtables(result, commonGetterNames)
    return result
end

function BubbleGraphLayer:getInspectorInfo(constrained)
    local result = {}
    if constrained then
        appendtables(result, constrainedInspectorInfo)
    else
        appendtables(result, freeInspectorInfo)
    end
    appendtables(result, commonInspectorInfo)
    return result
end

function BubbleGraphLayer:iterateValues(orientation, mapFunction)
    local dataset = self:getDataset()
    local propertyName = 'value'
    if not self:isPositionConstrained() then
        if orientation == Graph.horizontalOrientation then
            propertyName = 'x'
        else
            propertyName = 'y'
        end
    end
    local sequence = self:getPropertySequence(propertyName, dataset)
    for _, value in sequence:iter() do
        mapFunction(value)
    end
end

function BubbleGraphLayer:draw(canvas, rect, propertySequence, xScaler, yScaler)
    local parent = self:getParent()
    local baseSize = parent:getBaseSize()
    local defaultPaint = self:getPaint()
    local isVertical = self:getOrientation() == Graph.verticalOrientation
    canvas:clipRect(rect:expand{left = 4, bottom = 4, right = 4, top = 4})
    
    propertySequence:each(function(position, value, area, paint)
        local x, y
        if isVertical then
            x, y = xScaler(position), yScaler(value)
        else
            y, x = yScaler(position), xScaler(value)
        end
        if x and y and rect.left <= x and x <= rect.right and rect.bottom <= y and y <= rect.top then
            local radius = _sqrt(tonumber(area) or 10) / 2
            CirclePointStamp(canvas, x, y, radius * baseSize, paint or defaultPaint)
        end
    end)
end

return BubbleGraphLayer
