local AceGUI = LibStub("AceGUI-3.0")

-------------
-- Widgets --
-------------
--[[
	Widgets must provide the following functions
		Acquire() - Called when the object is aquired, should set everything to a default hidden state
		Release() - Called when the object is Released, should remove any anchors and hide the Widget
		
	And the following members
		frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
		type - the type of the object, same as the name given to :RegisterWidget()
		
	Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
	It will be cleared automatically when a widget is released
	Placing values directly into a widget object should be avoided
	
	If the Widget can act as a container for other Widgets the following
		content - frame or derivitive that children will be anchored to
		
	The Widget can supply the following Optional Members


]]

--------------------------
-- Scroll Frame		    --
--------------------------
do
	local Type = "ScrollFrame"
	local Version = 6
	
	local function OnAcquire(self)

	end
	
	local function OnRelease(self)
		self.frame:ClearAllPoints()
		self.frame:Hide()
		self.status = nil
		for k in pairs(self.localstatus) do
			self.localstatus[k] = nil
		end
		self.scrollframe:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT",0,0)
		self.scrollbar:Hide()
		self.scrollBarShown = nil
		self.content.height, self.content.width = nil, nil
	end
	
	local function SetScroll(self, value)
		
		local status = self.status or self.localstatus
		
		local frame, child = self.scrollframe, self.content
		local viewheight = frame:GetHeight()
		local height = child:GetHeight()
		local offset
		if viewheight > height then
			offset = 0
		else
			offset = floor((height - viewheight) / 1000.0 * value)
		end
		child:ClearAllPoints()
		child:SetPoint("TOPLEFT",frame,"TOPLEFT",0,offset)
		child:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,offset)
		status.offset = offset
		status.scrollvalue = value
	end
	
	local function MoveScroll(self, value)
		local status = self.status or self.localstatus
		local frame, child = self.scrollframe, self.content
		local height, viewheight = frame:GetHeight(), child:GetHeight()
		if height > viewheight then
			self.scrollbar:Hide()
		else
			self.scrollbar:Show()
			local diff = height - viewheight
			local delta = 1
			if value < 0 then
				delta = -1
			end
			self.scrollbar:SetValue(math.min(math.max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
		end
	end
	
	
	local function FixScroll(self)
		if self.updateLock then return end
		self.updateLock = true
		local status = self.status or self.localstatus
		local frame, child = self.scrollframe, self.content
		local height, viewheight = frame:GetHeight(), child:GetHeight()
		local offset = status.offset
		if not offset then
			offset = 0
		end
		local curvalue = self.scrollbar:GetValue()
		if viewheight < height then
			if self.scrollBarShown then
				self.scrollBarShown = nil
				self.scrollbar:Hide()
				self.scrollbar:SetValue(0)
				self.scrollframe:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT",0,0)
				self:DoLayout()
			end
		else
			if not self.scrollBarShown then
				self.scrollBarShown = true
				self.scrollbar:Show()
				self.scrollframe:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT",-20,0)
				self:DoLayout()
			end
			local value = (offset / (viewheight - height) * 1000)
			if value > 1000 then value = 1000 end
			self.scrollbar:SetValue(value)
			self:SetScroll(value)
			if value < 1000 then
				child:ClearAllPoints()
				child:SetPoint("TOPLEFT",frame,"TOPLEFT",0,offset)
				child:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,offset)
				status.offset = offset
			end
		end
		self.updateLock = nil
	end

	local function OnMouseWheel(this,value)
		this.obj:MoveScroll(value)
	end

	local function OnScrollValueChanged(this, value)
		this.obj:SetScroll(value)
	end
	
	local function FixScrollOnUpdate(this)
		this:SetScript("OnUpdate", nil)
		this.obj:FixScroll()
	end
	local function OnSizeChanged(this)
		this:SetScript("OnUpdate", FixScrollOnUpdate)
		--this.obj:FixScroll()
	end
	
	local function LayoutFinished(self,width,height)
		self.content:SetHeight(height or 0 + 20)
		self:FixScroll()
	end
	
	-- called to set an external table to store status in
	local function SetStatusTable(self, status)
		assert(type(status) == "table")
		self.status = status
		if not status.scrollvalue then
			status.scrollvalue = 0
		end
	end
	
	
	local createdcount = 0
	
	local function OnWidthSet(self, width)
		local content = self.content
		content.width = width
	end
	
	
	local function OnHeightSet(self, height)
		local content = self.content
		content.height = height
	end
	
	local function Constructor()
		local frame = CreateFrame("Frame",nil,UIParent)
		local self = {}
		self.type = Type
	
		self.OnRelease = OnRelease
		self.OnAcquire = OnAcquire
		
		self.MoveScroll = MoveScroll
		self.FixScroll = FixScroll
		self.SetScroll = SetScroll
		self.LayoutFinished = LayoutFinished
		self.SetStatusTable = SetStatusTable
		self.OnWidthSet = OnWidthSet
		self.OnHeightSet = OnHeightSet
		
		self.localstatus = {} 	
		self.frame = frame
		frame.obj = self

		--Container Support
		local scrollframe = CreateFrame("ScrollFrame",nil,frame)
		local content = CreateFrame("Frame",nil,scrollframe)
		createdcount = createdcount + 1
		local scrollbar = CreateFrame("Slider",("AceConfigDialogScrollFrame%dScrollBar"):format(createdcount),scrollframe,"UIPanelScrollBarTemplate")
		local scrollbg = scrollbar:CreateTexture(nil,"BACKGROUND")
		scrollbg:SetAllPoints(scrollbar)
		scrollbg:SetTexture(0,0,0,0.4)
		self.scrollframe = scrollframe
		self.content = content
		self.scrollbar = scrollbar
		
		scrollbar.obj = self
		scrollframe.obj = self
		content.obj = self
		
		scrollframe:SetScrollChild(content)
		scrollframe:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
		scrollframe:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT",0,0)
		scrollframe:EnableMouseWheel(true)
		scrollframe:SetScript("OnMouseWheel", OnMouseWheel)
		scrollframe:SetScript("OnSizeChanged", OnSizeChanged)
		
		
		content:SetPoint("TOPLEFT",scrollframe,"TOPLEFT",0,0)
		content:SetPoint("TOPRIGHT",scrollframe,"TOPRIGHT",0,0)
		content:SetHeight(400)
		
		scrollbar:SetPoint("TOPLEFT",scrollframe,"TOPRIGHT",4,-16)
		scrollbar:SetPoint("BOTTOMLEFT",scrollframe,"BOTTOMRIGHT",4,16)
		scrollbar:SetScript("OnValueChanged", OnScrollValueChanged)
		scrollbar:SetMinMaxValues(0,1000)
		scrollbar:SetValueStep(1)
		scrollbar:SetValue(0)
		scrollbar:SetWidth(16)
		scrollbar:Hide()
		
		self.localstatus.scrollvalue = 0
		

		--self:FixScroll()
		AceGUI:RegisterAsContainer(self)
		--AceGUI:RegisterAsWidget(self)
		return self
	end
	
	AceGUI:RegisterWidgetType(Type,Constructor,Version)
end
