--[[ usage
	data = {
		[1] = {
			id			= "1-Display Name",		-- unique id
			name		= "Display Name",
			color		= {r, g, b},			-- Text color
			tt_title	= "Tooltip Title",		-- OnEnter can changed with "SetToolTipFunc", arg list = ShowToolTip(...)
			tt_text		= "Tooltip Text",
			arg			= "arg",				-- OnClick(arg)
			icon		= "Interface\\Icons\\INV_Misc_QuestionMark",
		},
	}
]] --
local ALName, ALPrivate = ...
local AtlasLoot = _G.AtlasLoot
local GUI = AtlasLoot.GUI

-- lua
local assert, type = assert, type
local next, wipe = next, table.wipe
local min, floor = min, floor

--//\\
local SELECT_COUNT = 0

local BUTTON_HEIGHT = 15

local COIN_TEXTURE = ALPrivate.COIN_TEXTURE

local COIN_TEXTURE_LINK = {
	["Achievement"] = "AC",
	["Reputation"]  = "REPUTATION",
	["Faction"]     = "REPUTATION",
}


-- functions
local UpdateContent, UpdateScroll

local function SetWidth(self, width)
	self.width = width
	self:Update()
end

local function SetNumEntrys(self, num)
	self.numEntrys = num or 1
	self:Update()
end

local function SetButtonHeight(self, height)
	self.buttonHeight = height
	self:Update()
end

local function SetBgColor(self, r, g, b, alpha)
	self.frame:SetBackdropColor(r, g, b, alpha or 1)
end

--- Select a entry
-- @param	id				the entry ID
-- @param	dataNum			the table index of the data table
-- @param	startSelect		true/false if this is the first call
local function SetSelected(self, id, dataNum, startSelect)
	if not id and not dataNum then
		if self.selected then
			self.selected = nil
			UpdateScroll(self)
		end
		return
	end
	if not id then
		if self.data[dataNum] then
			self.selected = { dataNum, self.data[dataNum].id }
			if self.ButtonOnClick then
				self:ButtonOnClick(self.data[dataNum].id, self.data[dataNum].arg)
			end
		else
			self.selected = nil
			--return
		end
	else
		self.selected = id
	end
	if not dataNum then
		self.selected = nil
		for i = 1, #self.data do
			if self.data[i].id == id then
				self.selected = { i, id }
				if self.ButtonOnClick then
					self:ButtonOnClick(id, self.data[i].arg, startSelect)
				end
				break
			end
		end
	end
	if not startSelect then
		UpdateScroll(self)
	end
end

local function GetSelected(self)
	if self.selected and self.data then
		return self.data[self.selected[1]]
	end
end

local function SetNext(self)
	if self.selected and self.data[self.selected[1] + 1] then
		self:SetSelected(nil, self.selected[1] + 1)
	end
end

local function CheckIfNext(self)
	return (self.selected and self.data[self.selected[1] + 1]) and true or nil
end

local function SetPrev(self)
	if self.selected and self.data[self.selected[1] - 1] then
		self:SetSelected(nil, self.selected[1] - 1)
	end
end

local function CheckIfPrev(self)
	return (self.selected and self.data[self.selected[1] - 1]) and true or nil
end

local function SetData(self, data, startValue)
	if not data then
		self:Clear()
		return
	end
	assert(type(data) == "table", "'data' must be a table. See 'GUI/Template_Select.lua' for infos.")
	self.data = data
	self.numContent = #data
	self.selected = startValue
	if startValue then
		self:SetSelected(startValue, nil, true)
	end
	self:Update()
end

local function ShowSelectedCoin(self, enabled)
	self.showSelectedCoin = enabled
end

local function SetButtonOnClick(self, func)
	if func and type(func) == "function" then
		self.ButtonOnClick = func
	else
		self.ButtonOnClick = nil
	end
end

local function ShowToolTip(self)
	self.obj.ttSource:SetOwner(self, "ANCHOR_RIGHT")
	self.obj.ttSource:AddLine(self.ttTitle or "", 1.0, 1.0, 1.0)
	self.obj.ttSource:AddLine(self.ttText or "", nil, nil, nil, 1)
	self.obj.ttSource:Show()
end

local function HideToolTip(self)
	self.obj.ttSource:Hide()
end

local function SetToolTipFunc(self, OnEnter, OnLeave)
	self.OnEnterButton = OnEnter or ShowToolTip
	self.OnLeaveButton = OnLeave or HideToolTip
end

-- local UpdateContent, UpdateScroll
do
	local BUTTON_COUNT = 0

	local cache = {}

	local function GetButtonFromCache()
		local frame = next(cache)
		if frame then
			cache[frame] = nil
		end
		return frame
	end

	local function ClearButtonList(self)
		if not self or not self.buttons then return end
		for i = 1, #self.buttons do
			local button = self.buttons[i]
			cache[button] = true
			button.info = nil
			button:Hide()
		end
		wipe(self.buttons)
	end

	local function GetStartAndEndPos(self)
		if not self.enableScroll then
			return 1, self.numContent
		end
		local numEntrys = self.numContent
		local selected = self.curPos
		local startPos, endPos = 1, 1
		if selected then
			if selected + self.numEntrys - 1 >= numEntrys then
				startPos = numEntrys - self.numEntrys + 1
				endPos = numEntrys
			else
				startPos = selected
				endPos = selected + self.numEntrys - 1
			end
		else
			startPos = 1
			endPos = self.numEntrys
		end

		return startPos, endPos
	end

	local function ButtonOnClick(self, ...)
		if self.obj.selected and self.info.id == self.obj.selected[2] then
			self:SetChecked(true)
			return
		end
		self.obj:SetSelected(self.info.id)
	end

	local function CreateButton(self)
		local frame = GetButtonFromCache()
		if not frame then
			BUTTON_COUNT = BUTTON_COUNT + 1
			local frameName = "AtlasLoot-Select-Button"..BUTTON_COUNT

			frame = CreateFrame("CheckButton", frameName)
			frame:SetHeight(self.buttonHeight)
			frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
			-- Below will now cover the text and currently not transparent
			-- Can be fixed by setting text and coin to a higher level (and sublevel)
			frame:SetCheckedTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
			frame:RegisterForClicks("LeftButtonDown", "RightButtonDown")
			frame:SetChecked(false)
			frame:SetScript("OnClick", ButtonOnClick)

			frame.label = frame:CreateFontString(frameName.."-label", "OVERLAY", "GameFontNormal")
			--frame.label:SetPoint("LEFT", frame, "LEFT")
			--frame.label:SetHeight(self.buttonHeight)
			frame.label:SetPoint("TOPLEFT", frame, "TOPLEFT")
			frame.label:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -18, 0)
			frame.label:SetJustifyH("LEFT")
			frame.label:SetJustifyV("MIDDLE")
			frame.label:SetText(frameName.."-label")

			frame.coin = frame:CreateTexture(frameName.."-coin", "OVERLAY", nil, 1)
			frame.coin:SetPoint("RIGHT", frame, "RIGHT")
			--frame.coin:SetTexture(_G.AtlasLoot.IMAGE_PATH.."silver")--gold
			frame.coin:SetHeight(self.buttonHeight)
			frame.coin:SetWidth(self.buttonHeight)
			frame.coin.obj = self
		end

		frame:ClearAllPoints()
		frame:SetParent(self.frame)
		frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)

		frame.obj = self
		frame:SetWidth(self.buttonWidth)
		frame:SetHeight(self.buttonHeight)
		--frame.label:SetHeight(self.buttonHeight)
		frame:SetScript("OnEnter", self.OnEnterButton)
		frame:SetScript("OnLeave", self.OnLeaveButton)

		if #self.buttons > 0 then
			frame:SetPoint("TOPLEFT", self.buttons[#self.buttons], "BOTTOMLEFT", 0, -self.space)
		else
			frame:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 5, -5)
		end

		frame:Show()

		return frame
	end

	local function SetupCoin(coinTexture, button, selected)
		button.coin:SetDesaturated(false)
		button.coin:SetTexCoord(0, 1, 0, 1)
		button.coin:SetWidth(button.obj.buttonHeight)

		if COIN_TEXTURE[COIN_TEXTURE_LINK[coinTexture] or ""] or COIN_TEXTURE[coinTexture] then
			local coin = COIN_TEXTURE[COIN_TEXTURE_LINK[coinTexture] or ""] or COIN_TEXTURE[coinTexture]
			button.coin:SetTexture(coin.texture)
			if coin.texCoord then
				button.coin:SetTexCoord(unpack(coin.texCoord))
			end
			if coin.width then
				button.coin:SetWidth(button.obj.buttonHeight * coin.width)
			end
			if selected then
				button.coin:SetDesaturated(false)
			else
				button.coin:SetDesaturated(true)
			end
		else
			if selected then
				button.coin:SetTexture(COIN_TEXTURE.GOLD.texture)
			else
				button.coin:SetTexture(COIN_TEXTURE.SILVER.texture)
			end
		end
	end

	function UpdateScroll(self)
		if not self or not self.data or self.numContent < 1 then return end
		local startPos, endPos = GetStartAndEndPos(self)
		local info
		for i = 1, #self.buttons do
			local button = self.buttons[i]
			info = self.data[startPos + i - 1]

			if info then
				assert(info.id, "No 'id' found for button")
				button.info = info
				button.ttTitle = info.tt_title
				button.ttText = info.tt_text
				if self.selected and self.selected[2] == info.id then
					button:SetChecked(true)
					if self.showSelectedCoin then
						SetupCoin(info.coinTexture, button, true)
						button.coin:Show()
					else
						button.coin:Hide()
					end
				else
					if button:GetChecked() then
						button:SetChecked(false)
					end
					if self.showSelectedCoin then
						SetupCoin(info.coinTexture, button, false)
						button.coin:Show()
					else
						button.coin:Hide()
					end
				end
				button.label:SetText(info.name or UNKNOWN)
				button.label:GetWidth() -- this "fix" a bug with text is not shown
			else
				button:Hide()
			end
		end
	end

	function UpdateContent(self)
		if not self or not self.data then return end
		ClearButtonList(self)
		if self.numContent < 1 then return end
		local count = 1
		if self.numContent >= self.numEntrys then
			count = self.numEntrys
		else
			count = self.numContent + 1
		end
		for i = 1, count do
			self.buttons[i] = CreateButton(self)
		end
		UpdateScroll(self)
	end
end

local function Clear(self)
	wipe(self.data)
	self:Update()
end

local function Update(self)
	self.frame:SetWidth(self.width)
	self.buttonWidth = self.width - 10
	self.height = (self.numEntrys * (self.buttonHeight + self.space)) + 10 - self.space
	self.frame:SetHeight(self.height)

	if self.numEntrys < self.numContent then
		self.frame.scrollbar:Show()
		self.enableScroll = true
		self.buttonWidth = self.buttonWidth - 20
		self.maxScroll = self.numContent - self.numEntrys + 1
		self.frame.scrollbar:SetMinMaxValues(1, self.maxScroll)
		self.frame.scrollbar:SetValue(1)
	else
		self.frame.scrollbar:Hide()
		self.enableScroll = false
	end

	self:UpdateContent()
end

-- value: up +1, down -1
local function OnMouseWheel(self, value)
	if not self.obj.enableScroll then return end
	self = self.obj
	self.curPos = self.curPos - value
	if self.curPos >= self.maxScroll then self.curPos = self.maxScroll end
	if self.curPos <= 0 then self.curPos = 1 end
	self.frame.scrollbar:SetValue(min(self.curPos, self.maxScroll))
end

local function OnValueChanged(self, value)
	if not self.obj.enableScroll then return end
	self = self.obj
	self.curPos = floor(value)

	if self.curPos <= 0 then self.curPos = 1 end
	UpdateScroll(self)
end

function GUI.CreateSelect()
	SELECT_COUNT = SELECT_COUNT + 1
	local frameName = "AtlasLoot-Select-"..SELECT_COUNT
	local self = {}

	-- functions
	self.SetWidth = SetWidth
	self.SetParPoint = GUI.Temp_SetParPoint
	self.SetNumEntrys = SetNumEntrys
	self.SetButtonHeight = SetButtonHeight
	self.SetBgColor = SetBgColor
	-- set the selected entry (id, dataNum, startSelect)
	self.SetSelected = SetSelected
	self.GetSelected = GetSelected
	-- goto next entry ()
	self.SetNext = SetNext
	self.CheckIfNext = CheckIfNext
	self.SetPrev = SetPrev
	self.CheckIfPrev = CheckIfPrev
	-- set the table data (data, startValue)
	self.SetData = SetData
	self.ShowSelectedCoin = ShowSelectedCoin
	self.SetToolTipFunc = SetToolTipFunc
	self.SetButtonOnClick = SetButtonOnClick
	self.Clear = Clear
	self.UpdateContent = UpdateContent
	self.Update = Update
	self.OnEnterButton = ShowToolTip
	self.OnLeaveButton = HideToolTip

	-- data
	self.data = {}                 -- data SetData(dataTable)
	self.buttons = {}              -- button storage
	self.selected = nil            -- { <NumberInDataTable>, id }
	self.curPos = 1                -- current position in scrollframe
	self.width = 250               -- frame width
	self.numEntrys = 4             -- number of buttons
	self.maxScroll = 4             -- Max value for scrollbar (SetMinMaxValues)
	self.space = 2                 -- Space between buttons
	self.numContent = 0            -- number of content in data tabel (#self.data)
	self.buttonHeight = BUTTON_HEIGHT -- button height
	self.enableScroll = false      -- scrollbar is shown
	self.showSelectedCoin = true   -- show grey/gold coin on the right side
	self.ttSource = GameTooltip


	self.frame = CreateFrame("ScrollFrame", frameName, nil, _G.BackdropTemplateMixin and "BackdropTemplate" or nil)
	local frame = self.frame
	frame:ClearAllPoints()
	frame:EnableMouse(true)
	frame:SetBackdrop({
		bgFile = "Interface/Tooltips/UI-Tooltip-Background",
		edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true,
		tileSize = 16,
		edgeSize = 16,
		insets = { left = 4, right = 4, top = 4, bottom = 4 }
	})
	frame:SetBackdropColor(0, 0, 0, 1)
	frame:EnableMouseWheel(true)
	frame:SetScript("OnMouseWheel", OnMouseWheel)
	frame.obj = self

	frame.scrollbar = CreateFrame("Slider", frameName.."-scrollbar", frame, "UIPanelScrollBarTemplate")
	frame.scrollbar:SetPoint("TOPLEFT", frame, "TOPRIGHT", -20, -20)
	frame.scrollbar:SetPoint("BOTTOMLEFT", frame, "BOTTOMRIGHT", 20, 20)
	frame.scrollbar:SetMinMaxValues(0, 1000)
	frame.scrollbar:SetValueStep(1)
	frame.scrollbar.scrollStep = 1
	frame.scrollbar:SetValue(0)
	frame.scrollbar:SetWidth(16)
	frame.scrollbar:Hide()
	frame.scrollbar:SetScript("OnValueChanged", OnValueChanged)
	frame.scrollbar.obj = self

	local scrollbg = frame.scrollbar:CreateTexture(nil, "BACKGROUND")
	scrollbg:SetAllPoints(frame.scrollbar)
	scrollbg:SetColorTexture(0, 0, 0, 0.5)

	self:Update()

	return self
end
