local addonName, addon = ...
local ui = addon:NewModule("Options.UI")
local L = LibStub("AceLocale-3.0"):GetLocale(addonName)

LibStub("Libra"):EmbedWidgets(ui)

local function compByName(a, b)
	return a:GetText():lower() < b:GetText():lower()
end

local function createSeparator(parent, from, to)
	local line = parent:CreateTexture()
	line:SetPoint(unpack(from))
	line:SetPoint(unpack(to))
	line:SetHeight(1)
	line:SetTexture(0.8, 0.8, 0.8, 0.5)
end

function ui:CreateSeparator(parent)
	if parent.label then
		parent:SetPoint("RIGHT", -31, 0)
		parent:SetHeight(1)
		parent.label:ClearAllPoints()
		parent.label:SetPoint("CENTER")
		createSeparator(parent, {"LEFT", parent}, {"RIGHT", parent.label, "LEFT", -5, 0})
		createSeparator(parent, {"RIGHT", parent}, {"LEFT", parent.label, "RIGHT", 5, 0})
	else
		local relativeTo = parent.desc or parent
		createSeparator(parent, {"BOTTOMLEFT", parent.desc, 0, 0}, {"BOTTOMRIGHT", parent.desc, 0, 0})
	end
end

function ui:CreateListItem()
	local frame = CreateFrame("Button")
	frame:SetSize(220, 16)
	frame:SetPushedTextOffset(0, 0)
	frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]])
	
	local font = frame:CreateFontString(nil, nil, "GameFontHighlight")
	font:SetJustifyH("LEFT")
	font:SetAllPoints()
	
	frame:SetFontString(font)
	
	local item = {}

	function item:Select()
		frame.selected = true
		frame:LockHighlight()
	end

	function item:Deselect()
		frame.selected = false
		frame:UnlockHighlight()
	end
    
    function item:Remove()
		self:Deselect()
        
        font:Hide()
        font:SetText(nil)
        font:ClearAllPoints()
        font = nil
        
        frame:Hide()
        frame:SetScript("OnClick", nil)
		frame:SetParent(nil)
        frame:ClearAllPoints()
		frame = nil
        
        item = nil;
	end
	
	function item:IsSelected()
		return frame.selected
	end
	
	function item:SetText(value)
		frame:SetText(value)
	end
	
	function item:GetText()
		return frame:GetText()
	end
	
	function item:Copy(destItem)
		destItem:SetText(self:GetText())
	end
	
	frame:SetScript("OnClick", function() 
		if not item:IsSelected() then
			item:Select()
		else
			item:Deselect()
		end
	end)

	item.frame = frame
	
	return item
end

function ui:CreateList(parent)
	parent = parent.frame or parent
	
	local frame = CreateFrame("Frame", nil, parent)

	local title = frame:CreateFontString(nil, nil, "GameFontNormal")
	title:SetPoint("TOP", 0, 20)
	title:SetText(name)
	title:SetSize(220, 16)

	local bg = frame:CreateTexture(nil, "BORDER")
	bg:SetTexture(0.3, 0.3, 0.3)
	bg:SetBlendMode("MOD")
	bg:SetAllPoints()

	local border = frame:CreateTexture(nil, "BORDER", nil, -1)
	border:SetTexture(0.5, 0.5, 0.5, 0.3)
	border:SetPoint("TOPLEFT", bg, -1, 1)
	border:SetPoint("BOTTOMRIGHT", bg, 1, -1)	
	
	local count = 0
	local list, items = {}, {}
	
	function list:SetTitle(value)
		title:SetText(value)
	end
	
	function list:SetSize(width, height)
		frame:SetSize(width, height)
	end
	
	function list:SetPoint(point, relativeTo, ...)
		frame:SetPoint(point, type(relativeTo) == "table" and relativeTo.frame or relativeTo, ...)
	end
	
	function list:AddItem(item)
		count = count + 1
		
		table.insert(items, item)
		
		local child = item.frame
		child:SetParent(frame)
        
		if count == 1 then
			child:SetPoint("TOPLEFT", frame, 10, -10)
		else
			local parent = items[count - 1].frame
			child:SetPoint("TOP", parent, "BOTTOM")
		end
	end
	
	function list:RemoveItem(index)
		local item = table.remove(items, index)
		
		if not item then
			return
		end
		
		if item:IsSelected() then
			item:Deselect()
		end
        
        item:Remove();
        
		count = count - 1
	end
	
	function list:Update()
		for i, item in ipairs(items) do
			local child = item.frame
			child:ClearAllPoints()
			if i == 1 then
				child:SetPoint("TOPLEFT", frame, 10, -10)
			else
				local parent = items[i - 1].frame
				child:SetPoint("TOP", parent, "BOTTOM")
			end
		end
	end
	
	function list:Items()
		return ipairs(items)
	end
	
	local function reverse()
		local i = #items + 1
		return function ()
			i = i - 1
			if i > 0 then return i, items[i] end
		end
	end
	
	function list:Sort(comp)
		table.sort(items, comp)
		self:Update()
	end
	
	function list:CopyItem(item)
		local destItem = ui:CreateListItem()
		item:Copy(destItem)
		self:AddItem(destItem)
	end
	
	function list:MoveSelectedTo(destList)
		for i, item in reverse() do
			if item:IsSelected() then
				destList:CopyItem(item)
				self:RemoveItem(i)
			end	
		end
		destList:Sort(compByName)
		self:Sort(compByName)
	end
	
	local function selectedItems()
		local i = 0
		local n = 0
		local max = #items
		return function ()
			while n <= max do
				n = n + 1
				local item = items[n]
				if item and item:IsSelected() then
					i = i + 1
					return i, n, item
				end
			end
			return nil
		end
	end
	
	local function swap(sourceIndex, destIndex)
		items[sourceIndex], items[destIndex] = items[destIndex], items[sourceIndex]
	end
	
	local function moveSelected(up)
		local selectedIndices = {}
		for i, n in selectedItems() do
			selectedIndices[i] = n
		end
		local i = up and 1 or #selectedIndices
		local selectedIndex = selectedIndices[i]
		while selectedIndex do
			local index = up and selectedIndex - 1 or selectedIndex + 1
			if count >= index and index > 0 then
				swap(selectedIndex, index)
			end
			i = up and i + 1 or i - 1
			selectedIndex = selectedIndices[i]
		end
	end
	
	function list:MoveSelectedDown()
		moveSelected()
		self:Update()
	end
	
	function list:MoveSelectedUp()
		moveSelected(true)
		self:Update()
	end
	
	function list:Clear()
		for i in reverse() do
			self:RemoveItem(i)
		end
	end
	
	list.frame = frame
	
	return list
end

function ui:CreateButton(parent)
	parent = parent.frame or parent
	
	local frame = CreateFrame("Button", nil, parent)
	frame:SetSize(24, 24)
	frame:SetHighlightTexture([[Interface\Buttons\UI-Common-MouseHilight]])
	
	local button = {}
	
	function button:SetSize(width, height)
		frame:SetSize(width, height)
	end
	
	function button:SetPoint(point, relativeTo, ...)
		frame:SetPoint(point, type(relativeTo) == "table" and relativeTo.frame or relativeTo, ...)
	end
	
	function button:SetNormalTexture(texture)
		frame:SetNormalTexture(texture)
	end

	function button:SetPushedTexture(texture)
		frame:SetPushedTexture(texture)
	end
	
	function button:OnClick(handler)
		frame:SetScript("OnClick", function() 
			handler()
		end)
	end
	
	button.frame = frame
	
	return button
end