--[[
    This list box does not use a ScrollControl.  It is intended for large collections of data
    when it would be more costly to create a Control-container for each row than it would be
    to set the data (i.e. text and icons) on each row as the list is scrolled.
--]]

local DEFAULT_ROW_PADDING = 2

local function CreateListBoxRows(listBox)
    local desiredRowCount   = listBox.m_RowCount
    local existingRowCount  = #(listBox.m_Rows)
    local needRowCount      = desiredRowCount - existingRowCount
    
    if(needRowCount > 0)
    then
        local newRow
        local rowId
        local container     = listBox.m_Container
        local baseRowName   = container:GetName()
        local template      = listBox.m_RowTemplate
        local previousRow   = listBox.m_Rows[existingRowCount]
        
        for i = 1, needRowCount
        do
            rowId = i + existingRowCount
            
            newRow = CreateControlFromVirtual(baseRowName.."Row"..rowId, container, template)
            
            if(newRow)
            then
                table.insert(listBox.m_Rows, newRow)
                
                if(previousRow)
                then
                    newRow:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, listBox.m_RowPadding)
                else
                    newRow:SetAnchor(TOPLEFT, container, TOPLEFT, 0, 0)
                end                
            end
            
            previousRow = newRow
        end
    end
end

ZO_ListBox = ZO_Object:Subclass()

function ZO_ListBox:New(rowTemplate, container, displayedRowCount, maxRowCount, rowPopulationFunction, scrollUpdateFunction, rowPadding)
    local listBox = ZO_Object.New(self)
    
    if(maxRowCount < displayedRowCount)
    then
        maxRowCount = displayedRowCount
    end
    
    listBox.m_RowTemplate           = rowTemplate
    listBox.m_RowCount              = displayedRowCount
    listBox.m_MaxRowCount           = maxRowCount
    listBox.m_Rows                  = {}
    listBox.m_RowPopulationFunction = rowPopulationFunction
    listBox.m_ScrollUpdateFunction  = scrollUpdateFunction
    listBox.m_Container             = container
    listBox.m_ScrollPosition        = 1
    listBox.m_MaxScrollPosition     = listBox.m_MaxRowCount - listBox.m_RowCount + 1
    listBox.m_RowPadding            = rowPadding or DEFAULT_ROW_PADDING
    
    CreateListBoxRows(listBox)
    
    listBox:Refresh()
    return listBox
end

function ZO_ListBox:SetScrollUpdateFunction(updateFunction)
    self.m_ScrollUpdateFunction = updateFunction
end

function ZO_ListBox:SetPopulatorFunction(populatorFunction)
    self.m_RowPopulationFunction = populatorFunction
end

function ZO_ListBox:GetScrollExtents()
    return self.m_ScrollPosition, self.m_ScrollPosition + self.m_RowCount - 1, self.m_MaxScrollPosition
end

local function SetScrollPosition(listObject, newScroll)
    if(newScroll < 1)
    then
        newScroll = 1
    elseif(newScroll > listObject.m_MaxScrollPosition)
    then
        newScroll = listObject.m_MaxScrollPosition
    end
    
    if(newScroll ~= listObject.m_ScrollPosition)
    then
        listObject.m_ScrollPosition = newScroll
        listObject:Refresh()
    end
end

function ZO_ListBox:ScrollTo(newScrollPosition)
    SetScrollPosition(self, newScrollPosition)
end

function ZO_ListBox:Scroll(scrollByRows)
    SetScrollPosition(self, self.m_ScrollPosition + scrollByRows)
end

function ZO_ListBox:Refresh()
    local currentRow = 1
    local currentRowControl
    local finalPosition = self.m_ScrollPosition + self.m_RowCount
    
    for i = self.m_ScrollPosition, finalPosition
    do
        currentRowControl = self.m_Rows[currentRow]
        
        if(currentRowControl)
        then
            -- The population function returns whether or not the row should be shown.
            currentRowControl:SetHidden(self.m_RowPopulationFunction(currentRowControl, i))
        end
        
        currentRow = currentRow + 1
    end
    
    local rowCount = #(self.m_Rows)
    
    while(currentRow < rowCount)
    do
        currentRow = currentRow + 1
        currentRowControl:SetHidden(true)
    end
    
    if(self.m_ScrollUpdateFunction)
    then 
        self.m_ScrollUpdateFunction(self.m_Container, self.m_ScrollPosition, self.m_MaxScrollPosition)
    end
end

function ZO_ListBox:SetMaxRows(maxRows)
    if(maxRows and (maxRows ~= self.m_MaxRowCount))
    then
        if(maxRows < self.m_RowCount)
        then
            self.m_MaxScrollPosition = 1
        else
            self.m_MaxScrollPosition = maxRows - self.m_RowCount + 1
        end
        
        self.m_MaxRowCount = maxRows

        if(self.m_ScrollPosition > self.m_MaxScrollPosition)
        then
            self.m_ScrollPosition = self.m_MaxScrollPosition
        end
    end
end
