--[[------------------------------------------------
	-- Love Frames - A GUI library for LOVE --
	-- Copyright (c) 2013 Kenny Shields --
--]]------------------------------------------------

-- columnlist class
local newobject = loveframes.NewObject("columnlist", "loveframes_object_columnlist", true)

--[[---------------------------------------------------------
	- func: initialize()
	- desc: intializes the element
--]]---------------------------------------------------------
function newobject:initialize()
	
	self.type = "columnlist"
	self.width = 300
	self.height = 100
	self.columnheight = 16
	self.buttonscrollamount = 200
	self.buttons = true;--the arrow buttons
	self.mousewheelscrollamount = 1500
	self.autoscroll = false
	self.dtscrolling = true
	self.internal = false
	self.selectionenabled = true
	self.multiselect = false
	self.children = {}
	self.internals = {}
	self.OnRowClicked = nil
	self.OnRowRightClicked = nil
	self.OnRowSelected = nil
	self.OnScroll = nil
	self.rowArray = {}    --omar addition
	self.columnMetaData = {}

	local list = loveframes.objects["columnlistarea"]:new(self)
	table.insert(self.internals, list)
	list.rowArray = self.rowArray
	
end

--[[---------------------------------------------------------
	- func: update(deltatime)
	- desc: updates the object
--]]---------------------------------------------------------
function newobject:update(dt)
	
	local state = loveframes.state
	local selfstate = self.state
	
	if state ~= selfstate then
		return
	end
	
	local visible = self.visible
	local alwaysupdate = self.alwaysupdate
	
	if not visible then
		if not alwaysupdate then
			return
		end
	end
	
	local parent = self.parent
	local base = loveframes.base
	local children = self.children
	local internals = self.internals
	local update = self.Update
	
	self:CheckHover()
	
	-- move to parent if there is a parent
	if parent ~= base then
		self.x = self.parent.x + self.staticx
		self.y = self.parent.y + self.staticy
	end
	
	for k, v in ipairs(children) do
		v:update(dt)
	end
	
	for k, v in ipairs(internals) do
		v:update(dt)
	end
	
	if update then
		update(self, dt)
	end

end

--[[---------------------------------------------------------
	- func: draw()
	- desc: draws the object
--]]---------------------------------------------------------
function newobject:draw()

	local state = loveframes.state
	local selfstate = self.state

	if state ~= selfstate then
		return
	end
	
	local visible = self.visible
	
	if not visible then
		return
	end
	
	local children = self.children
	local internals = self.internals
	local skins = loveframes.skins.available
	local skinindex = loveframes.config["ACTIVESKIN"]
	local defaultskin = loveframes.config["DEFAULTSKIN"]
	local selfskin = self.skin
	local skin = skins[selfskin] or skins[skinindex]
	local drawfunc = skin.DrawColumnList or skins[defaultskin].DrawColumnList
	local draw = self.Draw
	local drawcount = loveframes.drawcount
	
	-- set the object's draw order
	self:SetDrawOrder()
		
	if draw then
		draw(self)
	else
		drawfunc(self)
	end
	
	for k, v in ipairs(internals) do
		v:draw()
	end
	
	for k, v in ipairs(children) do
		v:draw()
	end

end

--[[---------------------------------------------------------
	- func: mousepressed(x, y, button)
	- desc: called when the player presses a mouse button
--]]---------------------------------------------------------
function newobject:mousepressed(x, y, button)

	local state = loveframes.state
	local selfstate = self.state
	
	if state ~= selfstate then
		return
	end
	
	local visible = self.visible
	
	if not visible then
		return
	end
	
	local hover = self.hover
	local children  = self.children
	local internals = self.internals
	
	if hover and button == "l" then
		local baseparent = self:GetBaseParent()
		if baseparent and baseparent.type == "frame" then
			baseparent:MakeTop()
		end
	end
	
	for k, v in ipairs(internals) do
		v:mousepressed(x, y, button)
	end
	
	for k, v in ipairs(children) do
		v:mousepressed(x, y, button)
	end
	
end

--[[---------------------------------------------------------
	- func: mousereleased(x, y, button)
	- desc: called when the player releases a mouse button
--]]---------------------------------------------------------
function newobject:mousereleased(x, y, button)

	local state = loveframes.state
	local selfstate = self.state
	
	if state ~= selfstate then
		return
	end
	
	local visible = self.visible
	
	if not visible then
		return
	end
	
	local children = self.children
	local internals = self.internals
	
	for k, v in ipairs(internals) do
		v:mousereleased(x, y, button)
	end
	
	for k, v in ipairs(children) do
		v:mousereleased(x, y, button)
	end
	
end

--[[---------------------------------------------------------
	- func: Adjustchildren()
	- desc: adjusts the width of the object's children
--]]---------------------------------------------------------
function newobject:AdjustColumns()

	local width = self.width
	local bar = self.internals[1].bar
	
	if bar then
		width = width - self.internals[1].internals[1].width
	end
	
	local children = self.children
	local numchildren = #children
	local columnwidth = width/numchildren
	local x = 0
	
	for k, v in ipairs(children) do
		if(v.customWidth ~= nil)then columnwidth = v.customWidth * width else columnwidth = width/numchildren end
		if bar then
			v:SetWidth(columnwidth)
		else
			v:SetWidth(columnwidth)
		end
		v:SetPos(x, 0)
		x = x + columnwidth
	end
	
end

--[[---------------------------------------------------------
	- func: AddColumn(name)
	- desc: gives the object a new column with the specified
			name
--]]---------------------------------------------------------
function newobject:AddColumn(name,noTitle,customWidth,center,offset)--custom width is a % of the total width

	local internals = self.internals;
	local list = internals[1];
	local width = self.width;
	local height = self.height;
	
	if noTitle ~= true then
	    loveframes.objects["columnlistheader"]:new(name, self,customWidth,center,offset)
	end

	self.columnMetaData[#self.columnMetaData+1] = {noTitle = noTitle, customWidth = customWidth, customOffset = offset}

	self:AdjustColumns()
	
	list:SetSize(width, height)
	list:SetPos(0, 0)
	
end

--[[---------------------------------------------------------
	- func: AddRow(...)
	- desc: adds a row of data to the object's list
--]]---------------------------------------------------------
function newobject:AddRow(...)
	local arg = {...};
	local internals = self.internals
	local list = internals[1]
	
	
	list:AddRow(arg)
end

function newobject:AddRowNoReadjust(...)
	local arg = {...};
	local internals = self.internals
	local list = internals[1]
	
	
	list:AddRowNoReadjust(arg)
end

--[[---------------------------------------------------------
	- func: Getchildrenize()
	- desc: gets the size of the object's children
--]]---------------------------------------------------------
function newobject:GetColumnSize()

	local children = self.children
	local numchildren = #self.children
	
	if numchildren > 0 then
		local column    = self.children[1]
		local colwidth  = column.width
		local colheight = column.height
		return colwidth, colheight
	else
		return 0, self.columnheight
	end
	
end

function newobject:GetAllColumnSize()
	
	local index = 1
	local array = {}

	for _,metaData in pairs(self.columnMetaData) do
	    if metaData.noTitle then
		    array[#array+1] = {metaData.customWidth or 80,self.columnheight}
		else
		    local column = self.children[index]
			array[#array+1] = {column.width,column.height}
			index = index + 1
		end
	end

	return array
end

function newobject:GetAllColumnOffset()

    local index = 1
	local array = {}

	for _,metaData in pairs(self.columnMetaData) do
	    if metaData.noTitle then
		    array[#array+1] = metaData.customOffset or 0
		else
		    local column = self.children[index]
			array[#array+1] = column.offset or 0
			index = index + 1
		end
	end

	return array

end

function newobject:GetAllColumnAlignment()

    local index = 1
	local array = {}

	for _,metaData in pairs(self.columnMetaData) do
	    if metaData.noTitle then
		    array[#array+1] = false
		else
		    local column = self.children[index]
			array[#array+1] = column.center ~= nil
			index = index + 1
		end
	end

	return array
end

--[[---------------------------------------------------------
	- func: SetSize(width, height)
	- desc: sets the object's size
--]]---------------------------------------------------------
function newobject:SetSize(width, height)
	
	local internals = self.internals
	local list = internals[1]
	
	self.width = width
	self.height = height
	self:AdjustColumns()
	
	list:SetSize(width, height)
	list:SetPos(0, 0)
	list:CalculateSize()
	list:RedoLayout()
	
end

--[[---------------------------------------------------------
	- func: SetWidth(width)
	- desc: sets the object's width
--]]---------------------------------------------------------
function newobject:SetWidth(width)
	
	local internals = self.internals
	local list = internals[1]
	
	self.width = width
	self:AdjustColumns()
	
	list:SetSize(width)
	list:SetPos(0, 0)
	list:CalculateSize()
	list:RedoLayout()
	
end

--[[---------------------------------------------------------
	- func: SetHeight(height)
	- desc: sets the object's height
--]]---------------------------------------------------------
function newobject:SetHeight(height)
	
	local internals = self.internals
	local list = internals[1]
	
	self.height = height
	self:AdjustColumns()
	
	list:SetSize(height)
	list:SetPos(0, 0)
	list:CalculateSize()
	list:RedoLayout()
	
end

--[[---------------------------------------------------------
	- func: SetMaxColorIndex(num)
	- desc: sets the object's max color index for
			alternating row colors
--]]---------------------------------------------------------
function newobject:SetMaxColorIndex(num)

	local internals = self.internals
	local list = internals[1]
	
	list.colorindexmax = num
	
end

--[[---------------------------------------------------------
	- func: Clear()
	- desc: removes all items from the object's list
--]]---------------------------------------------------------
function newobject:Clear()

	local internals = self.internals
	local list = internals[1]
	self.rowArray = {}
	list.rowArray = self.rowArray;
	
	list:Clear()
	
end

function newobject:ClearNoReadjust()

	local internals = self.internals
	local list = internals[1]
	self.rowArray = {}
	list.rowArray = self.rowArray;
	
	list:ClearNoReadjust()
	
end

--[[---------------------------------------------------------
	- func: SetAutoScroll(bool)
	- desc: sets whether or not the list's scrollbar should
			auto scroll to the bottom when a new object is
			added to the list
--]]---------------------------------------------------------
function newobject:SetAutoScroll(bool)

	local internals = self.internals
	local list = internals[1]
	local scrollbar = list:GetScrollBar()
	
	self.autoscroll = bool
	
	if list then
		if scrollbar then
			scrollbar.autoscroll = bool
		end
	end
	
end

function newobject:DisableButtons()
	self.internals[1].buttons = false;
end

--[[---------------------------------------------------------
	- func: SetButtonScrollAmount(speed)
	- desc: sets the scroll amount of the object's scrollbar
			buttons
--]]---------------------------------------------------------
function newobject:SetButtonScrollAmount(amount)

	self.buttonscrollamount = amount
	self.internals[1].buttonscrollamount = amount
	
end

--[[---------------------------------------------------------
	- func: GetButtonScrollAmount()
	- desc: gets the scroll amount of the object's scrollbar
			buttons
--]]---------------------------------------------------------
function newobject:GetButtonScrollAmount()

	return self.buttonscrollamount
	
end

--[[---------------------------------------------------------
	- func: SetMouseWheelScrollAmount(amount)
	- desc: sets the scroll amount of the mouse wheel
--]]---------------------------------------------------------
function newobject:SetMouseWheelScrollAmount(amount)

	self.mousewheelscrollamount = amount
	self.internals[1].mousewheelscrollamount = amount
	
end

--[[---------------------------------------------------------
	- func: GetMouseWheelScrollAmount()
	- desc: gets the scroll amount of the mouse wheel
--]]---------------------------------------------------------
function newobject:GetButtonScrollAmount()

	return self.mousewheelscrollamount
	
end

--[[---------------------------------------------------------
	- func: SetColumnHeight(height)
	- desc: sets the height of the object's columns
--]]---------------------------------------------------------
function newobject:SetColumnHeight(height)

	local children = self.children
	local internals = self.internals
	local list = internals[1]
	
	self.columnheight = height
	
	for k, v in ipairs(children) do
		v:SetHeight(height)
	end
	
	list:CalculateSize()
	list:RedoLayout()
	
end

--Omie's function
function newobject:SetRowHeight(height)
	local list = self.internals[1];
	local rowArray = list.rowArray;
	for i=1,#rowArray do 
		local row = rowArray[i];
		row.height = height;
	end

	list:CalculateSize()
	list:RedoLayout()
end

--[[---------------------------------------------------------
	- func: SetDTScrolling(bool)
	- desc: sets whether or not the object should use delta
			time when scrolling
--]]---------------------------------------------------------
function newobject:SetDTScrolling(bool)

	self.dtscrolling = bool
	self.internals[1].dtscrolling = bool
	
end

--[[---------------------------------------------------------
	- func: GetDTScrolling()
	- desc: gets whether or not the object should use delta
			time when scrolling
--]]---------------------------------------------------------
function newobject:GetDTScrolling()

	return self.dtscrolling
	
end

--[[---------------------------------------------------------
	- func: SelectRow(row, ctrl)
	- desc: selects the specfied row in the object's list
			of rows
--]]---------------------------------------------------------
function newobject:SelectRow(row, ctrl)

	local selectionenabled = self.selectionenabled
	
	if not selectionenabled then
		return
	end
	
	local list = self.internals[1]
	local children = list.children
	local multiselect = self.multiselect
	local onrowselected = self.OnRowSelected
	
	if(multiselect == false)then ctrl = false end

	for k, v in ipairs(children) do
		if v == row then
			if v.selected and ctrl then
				v.selected = false
			else
				v.selected = true
				if onrowselected then
					onrowselected(self, row, row:GetColumnData())
				end
			end
		elseif v ~= row and not multiselect and not ctrl then
			v.selected = false
		end
	end
	
	--Make the list scroll if the selected ot a object is out of bounds

	local scrollbar = list:GetScrollBar()
	if(scrollbar)then 
		if(row.y >= self.height+self.y)then 
			scrollbar:Scroll(row.height * 4)
		end
		if(row.y-row.height < self.y)then 
			scrollbar:Scroll(-row.height * 2)
		end
	end


end

--[[---------------------------------------------------------
	- func: DeselectRow(row)
	- desc: deselects the specfied row in the object's list
			of rows
--]]---------------------------------------------------------
function newobject:DeselectRow(row)

	row.selected = false
	
end

--[[---------------------------------------------------------
	- func: GetSelectedRows()
	- desc: gets the object's selected rows
--]]---------------------------------------------------------
function newobject:GetSelectedRows()
	
	local rows = {}
	local list = self.internals[1]
	local children = list.children
	
	for k, v in ipairs(children) do
		if v.selected then
			table.insert(rows, v)
		end
	end
	
	return rows;
	
end

--[[---------------------------------------------------------
	- func: SetSelectionEnabled(bool)
	- desc: sets whether or not the object's rows can be
			selected
--]]---------------------------------------------------------
function newobject:SetSelectionEnabled(bool)

	self.selectionenabled = bool
	
end

--[[---------------------------------------------------------
	- func: GetSelectionEnabled()
	- desc: gets whether or not the object's rows can be
			selected
--]]---------------------------------------------------------
function newobject:GetSelectionEnabled()

	return self.selectionenabled
	
end

--[[---------------------------------------------------------
	- func: SetMultiselectEnabled(bool)
	- desc: sets whether or not the object can have more
			than one row selected
--]]---------------------------------------------------------
function newobject:SetMultiselectEnabled(bool)

	self.multiselect = bool
	
end

--[[---------------------------------------------------------
	- func: GetMultiselectEnabled()
	- desc: gets whether or not the object can have more
			than one row selected
--]]---------------------------------------------------------
function newobject:GetMultiselectEnabled()

	return self.multiselect
	
end