local super = require "Axis"

CategoryAxis = super:new()

local defaults = {
    padding = 0.5,
}

local nilDefaults = {
    'label',
}

local labelInspectorInfo = {
    {'KeyArtifact', {'label'}, 'Category Name'},
}

function CategoryAxis: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
    
    self._datasetHook = nil
    self.labelInspectorInfo = labelInspectorInfo
    
    return self
end

function CategoryAxis:getPreferredType()
    return 'string'
end

function CategoryAxis:allowsNumberValues()
    return true
end

function CategoryAxis:allowsDateValues()
    return true
end

function CategoryAxis:unarchived()
    local dataset = self:getDataset()
    if dataset then
        if self:getProperty('label') == nil then
            local field = dataset:pickField('string')
            if field then
                self:setProperty('label', KeyArtifact:new(field))
            end
        end
    end
    super.unarchived(self)
end

function CategoryAxis:createInspector(type, hooks, title, undoTitle)
    local inspector = super.createInspector(self, type, hooks, title, undoTitle)
    inspector:addHook(self._datasetHook, 'dataSource')
    return inspector
end

function CategoryAxis:setDatasetHook(hook)
    self._datasetHook = hook
end

function CategoryAxis:getDataset()
    if self._datasetHook then
        return self._datasetHook:getValue()
    end
end

function CategoryAxis:getLabelFont(parent)
    return parent:getAxisCategoryFont()
end

function CategoryAxis:origin()
    if self:getOrientation() == Graph.verticalOrientation then
        local dataset = self:getDataset()
        if dataset then
            return dataset:entryCount() + 1
        end
    end
    return 0
end

function CategoryAxis:distribute(rect, crossing)
    local values = {}
    local positions = {}
    local tickPositions = {}
    local dataset = self:getDataset()
    local labelArtifact = self:getProperty('label')
    local scaler = self:getScaler(rect)
    if dataset and labelArtifact then
        local sequence = labelArtifact:evaluate(dataset)
        local entryCount = dataset:entryCount()
        local length = self:getLength(rect)
        if length == 0 then
            length = math.huge
        end
        local maxLabels = math.floor(length / (self:getLabelSize() * 2))
        local step
        if maxLabels <= 2 then
            step = math.max(1, entryCount - 1)
        else
            step = math.max(1, math.floor(entryCount / maxLabels))
        end
        for i = 1, entryCount do
            if (i - 1) % step == 0 then
                positions[#positions + 1] = scaler(i)
                values[#positions] = sequence:getValue(i)
            end
            if i < entryCount then
                tickPositions[#tickPositions + 1] = scaler(i + 0.5)
            end
        end
    end
    return nil, tickPositions, values, positions
end

function CategoryAxis:getScaler(rect, itemSpacing, groupableCount, groupableIndex)
    local rectMin, rectSize
    if self:getOrientation() == Graph.horizontalOrientation then
        rectMin, rectSize = rect:minx(), rect:width()
    else
        rectMin, rectSize = rect:maxy(), -rect:height()
    end
    local dataset = self:getDataset()
    if dataset then
        local length = dataset:entryCount()
        if length >= 1 then
            return CategoryScaler(length, rectMin, rectSize, itemSpacing, groupableCount, groupableIndex)
        end
    end
    if self:getOrientation() == Graph.horizontalOrientation then
        return function(value, size) return rectMin, rectMin end
    else
        return function(value, size) return rectMin + rectSize, rectMin + rectSize end
    end
end

return CategoryAxis
