--[[
	Infield
		A library of functions to keep frames within the UIParent's bounds
		
	Version History <mm>/<dd>/<yy>
		9/8/5
			First release
		10/11/5
			1800 Update
		12/06/5
			Added some checks to make sure a frame has a bottom, top, etc
		12/13/5
			Scaling is now more robust, will work for frames that are simply anchored to other frames.
		12/17/5
			Second curse release
		12/18/5
			Added Infield_AddRescaleAction(function)
				Will execute <function> in the event of the UI Scale changing.  Useful for rescaling anything that uses UIParent as its parent.
		1/3/6
			Updated for 1.9
--]]

local UPDATE_INTERVAL = 1;
local rescaleList = {};

--[[
	Loading Function
--]]

function Infield_OnLoad()
	this:RegisterEvent("PLAYER_LOGIN");
end

--[[
	Event Handler:
		Rescales everything on login, then starts up the check for rescaling
--]]

function Infield_OnEvent(event)
	--perform rescaling actions
	local index;
	for index in rescaleList do
		rescaleList[index]();
	end

	--turn on scale checking
	this.elapsed = 0;
	this.scale = UIParent:GetScale();
	this:Show();
end

--[[
	OnUpdate:
		Checks and sees if the UI Scale has then changed, then performs the actions in rescaleList
--]]

function Infield_OnUpdate(arg1)
	this.elapsed = this.elapsed + arg1;
	
	if(this.elapsed > UPDATE_INTERVAL) then
		if(this.scale ~= UIParent:GetScale()) then
			this.scale = UIParent:GetScale();
			
			--perform rescaling actions
			local index;
			for index in rescaleList do
				rescaleList[index]();
			end
		end
		this.elapsed = 0;
	end
end


--[[
	Public Functions
--]]

--Add a function to execute when the UI scale changes
--This must be added before the PLAYER_LOGIN event takes place to detect the startup rescale.
function Infield_AddRescaleAction(funct)
	table.insert(rescaleList, funct);
end

--Scales frame to scale, repositions if out of bounds
function Infield_Scale(frame, scale)
	local x, y = Infield_AdjCoords(frame, scale);
	
	frame:SetScale(scale);
	if(x) then
		Infield_Place(frame, "TOPLEFT", UIParent, "BOTTOMLEFT", x, y);
	end
end

--Places a frame at a location and repositions it so that it is not outside of the UIParent
--Syntax is similar to Frame:SetScale()
function Infield_Place(frame, point, parent, relPoint, x, y)
	frame:ClearAllPoints();
	frame:SetPoint(point, parent, relPoint, x, y);
	Infield_Reposition(frame, UIParent);
end

--Moves a frame within the bounds of parent if its out of bounds
function Infield_Reposition(frame, parent)
	if( frame:GetBottom() and frame:GetTop() and frame:GetLeft() and frame:GetRight() ) then
		local xoff = 0;
		local yoff = 0;
		local ratio = frame:GetScale();
		
		
		--check and see if the frame is off the screen
		--Y bounds checking
		if (  frame:GetBottom() < 0) then
			yoff = 0 - frame:GetBottom();
		elseif ( frame:GetTop()  > (parent:GetTop() / ratio ) ) then
			yoff = (parent:GetTop() / ratio) - frame:GetTop();
		end

		--X bounds checking
		if ( frame:GetLeft() < 0 ) then
			xoff = 0  - frame:GetLeft();
		elseif ( frame:GetRight()  > ( parent:GetRight() / ratio )  ) then
			xoff = (parent:GetRight() / ratio) - frame:GetRight();
		end
		
		--Reposition if anything was out of bounds
		if( xoff ~= 0 or yoff ~= 0) then
			local x = frame:GetLeft() + xoff;
			local y = frame:GetTop() + yoff;
			
			frame:ClearAllPoints();
			frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", x , y);
		end
	end
end

--[[ 
	"Private" Functions
--]]

--returns the adjusted x and y coordinates for a frame when scaled, keeping the topleft of the frame in the same relative spot
function Infield_AdjCoords(frame, nScale)
	if(not ( frame:GetLeft() and frame:GetTop() ) ) then
		return nil;
	end
	return frame:GetLeft() * frame:GetScale() / nScale, frame:GetTop() * frame:GetScale() / nScale;
end