local addonName = ...
local addon = _G[addonName]

--[[
The methods below are slightly modified versions of Blizzard's own code to manage scroll frames.
I wanted to clean my own code, to reduce the amount of named frames, which often make the code too specific and less flexible.
By using parentKeys, it becomes easier to manage some bits in a generic way, for this I had to modify Blizzard's own UI templates (see .xml)
Blizzard is using parentKeys in their newer UI elements (ex: Garrison stuff), but older elements like scroll frames have not been updated,
most likely for compatibility reasons.
I thus had to redo the xml templates and their supporting code.
--]]

addon:Controller("AltoholicUI.UIPanelScrollFrame", {
	OnBind = function(frame)
		local scrollBar = frame.ScrollBar
		
		scrollBar.ScrollDownButton:Disable()
		scrollBar.ScrollUpButton:Disable()
		scrollBar:SetMinMaxValues(0, 0)
		scrollBar:SetValue(0)
		
		frame.offset = 0
		
		if frame.scrollBarHideable then
			scrollBar:Hide()
			scrollBar.ScrollDownButton:Hide()
			scrollBar.ScrollUpButton:Hide()
		else
			scrollBar.ScrollDownButton:Disable()
			scrollBar.ScrollUpButton:Disable()
			scrollBar.ScrollDownButton:Show()
			scrollBar.ScrollUpButton:Show()
		end
		
		if frame.noScrollThumb then
			scrollBar.ThumbTexture:Hide()
		end
		
		if not frame.numRows or not frame.rowTemplate then 
			return 
		end
			
		local prefix = frame.rowPrefix
		local parent = frame:GetParent()
		local xOffset = frame.xOffset or 0
		local yOffset = frame.yOffset or 0
		
		-- auto create the buttons, with the quantity passed as key
		for i = 1, frame.numRows do
			local button = CreateFrame("Button", nil, parent, frame.rowTemplate)
			
			if i == 1 then
				button:SetPoint("TOPLEFT", xOffset, yOffset)
			else
				-- attach to previous frame
				button:SetPoint("TOPLEFT", parent[prefix..(i-1)], "BOTTOMLEFT", 0, 0)
			end
			
			button:SetID(i)
			parent[prefix..i] = button
		end
	end,
	GetOffset = function(frame)
		return frame.offset
	end,
	SetOffset = function(frame, offset)
		frame.offset = offset
	end,
	OnScrollRangeChanged = function(frame, xrange, yrange)
		local scrollBar = frame.ScrollBar
		-- print(format("OnScrollRangeChanged() xrange: %d, yrange: %d, scrollbar value: %d, height: %d"
			-- , xrange, yrange, scrollBar:GetValue(), scrollBar:GetHeight()))
		
		if ( not yrange ) then
			yrange = frame:GetVerticalScrollRange()
		end

		-- hard limit the YRange
		if scrollBar.maxYRange and yrange > scrollBar.maxYRange then 
			yrange = scrollBar.maxYRange
		end
		
		local value = scrollBar:GetValue()
		if ( value > yrange ) then
			value = yrange
		end
		
		scrollBar:SetMinMaxValues(0, yrange)
		scrollBar:SetValue(value)
		
		-- If the scrollbar must be hidden, just hide it and stop
		if frame.scrollBarHideable then
			scrollBar:Hide()
			scrollBar.ScrollDownButton:Hide()
			scrollBar.ScrollUpButton:Hide()
			scrollBar.ThumbTexture:Hide()
			return
		end
		
		if ( floor(yrange) == 0 ) then
			if ( frame.scrollBarHideable ) then
				-- scrollBar:Hide()
				-- scrollBar.ScrollDownButton:Hide()
				-- scrollBar.ScrollUpButton:Hide()
				-- scrollBar.ThumbTexture:Hide()
			else
				scrollBar.ScrollDownButton:Disable()
				scrollBar.ScrollUpButton:Disable()
				scrollBar.ScrollDownButton:Show()
				scrollBar.ScrollUpButton:Show()
				
				if ( not frame.noScrollThumb ) then
					scrollBar.ThumbTexture:Show()
				end
			end
		else
			scrollBar.ScrollDownButton:Show()
			scrollBar.ScrollUpButton:Show()
			scrollBar:Show()
			
			if ( not frame.noScrollThumb ) then
				scrollBar.ThumbTexture:Show()
			end
			
			-- The 0.005 is to account for precision errors
			if ( yrange - value > 0.005 ) then
				scrollBar.ScrollDownButton:Enable()
			else
				scrollBar.ScrollDownButton:Disable()
			end
		end
		
		-- Hide/show scrollframe borders
		local top = frame.Top
		local bottom = frame.Bottom
		local middle = frame.Middle
		
		if top and bottom and frame.scrollBarHideable then
			if ( frame:GetVerticalScrollRange() == 0 ) then
				top:Hide()
				bottom:Hide()
			else
				top:Show()
				bottom:Show()
			end
		end
		
		if middle and frame.scrollBarHideable then
			if ( frame:GetVerticalScrollRange() == 0 ) then
				middle:Hide()
			else
				middle:Show()
			end
		end
	end,
	OnMouseWheel = function(frame, delta)
		local scrollBar = frame.ScrollBar
		local scrollStep = scrollBar.scrollStep or scrollBar:GetHeight() / 2
		
		if (delta > 0) then
			scrollBar:SetValue(scrollBar:GetValue() - scrollStep)
		else
			scrollBar:SetValue(scrollBar:GetValue() + scrollStep)
		end
		-- print(format("OnMouseWheel() delta: %d, scrollStep: %d, new value: %d", delta, scrollStep, scrollBar:GetValue()))
	end,
	OnVerticalScroll = function(frame, offset, rowHeight, updateFunction, arg1, arg2, arg3)
		local scrollBar = frame.ScrollBar
		scrollBar:SetValue(offset)
		
		-- print(format("OnVerticalScroll() offset: %d, new value: %d", offset, scrollBar:GetValue()))
		
		frame.offset = floor((offset / rowHeight) + 0.5)

		if updateFunction then
			updateFunction(arg1, arg2, arg3)
		end
	end,
	Update = function(frame, numItems, numToDisplay, buttonHeight)
		-- My own FauxScrollFrame_Update() from SharedUIPanelTemplates.lua
		-- If more than one screen full of skills then show the scrollbar
		
		numToDisplay = numToDisplay or frame.numRows
		buttonHeight = buttonHeight or frame.rowHeight
		
		local scrollBar = frame.ScrollBar

		if numItems > numToDisplay then
			frame:Show()
		else
			scrollBar:SetValue(0)
			frame:Hide()
		end
		
		if not frame:IsShown() then return end
		
		local scrollChildFrame = frame.ScrollChildFrame
		local scrollFrameHeight = 0
		local scrollChildHeight = 0

		if ( numItems > 0 ) then
			scrollFrameHeight = (numItems - numToDisplay) * buttonHeight
			scrollChildHeight = numItems * buttonHeight
			if ( scrollFrameHeight < 0 ) then
				scrollFrameHeight = 0
			end
			scrollChildFrame:Show()
		else
			scrollChildFrame:Hide()
		end
		
		local maxRange = (numItems - numToDisplay) * buttonHeight
		if (maxRange < 0) then
			maxRange = 0
		end
		-- print("setting max range : " .. maxRange)
		scrollBar:SetMinMaxValues(0, maxRange)
		scrollBar:SetValueStep(buttonHeight)
		scrollBar:SetStepsPerPage(numToDisplay-1)
		scrollChildFrame:SetHeight(scrollChildHeight)

		local scrollUpButton = scrollBar.ScrollUpButton
		local scrollDownButton = scrollBar.ScrollDownButton
		
		-- Arrow button handling
		if ( scrollBar:GetValue() == 0 ) then
			scrollUpButton:Disable()
		else
			scrollUpButton:Enable()
		end
		
		if ((scrollBar:GetValue() - scrollFrameHeight) == 0) then
			scrollDownButton:Disable()
		else
			scrollDownButton:Enable()
		end
	end,
	GetRow = function(frame, index)
		--  ex: returns parent["Entry6"]
		local parent = frame:GetParent()
		return parent[frame.rowPrefix..index]
	end,
})
