local E = select(2, ...) -- Engine
local CO,LOC,UF,AB,LT,AUR,TT = E:LoadModules("Config", "Locale", "Unitframes", "Actionbars", "Layout", "Auras", "Tooltip")

local _
local HiddenFrame = CreateFrame("Frame", nil, E.Parent)

E.FrameFadeTime = 1
E.Frames = {}
E.Fonts = {}

E.FrameStratas = {
	[1] = "BACKGROUND",
	[2] = "LOW",
	[3] = "MEDIUM",
	[4] = "HIGH",
	[5] = "DIALOG",
	[6] = "FULLSCREEN",
	[7] = "FULLSCREEN_DIALOG",
	[8] = "TOOLTIP",
}

do
	HiddenFrame:Hide()
end

-- type, name, strata, sizeX, sizeY, {point, relativeFrame, relativePoint, offsetX, offsetY}, parent, enablemouse, enablemousewheel, enablekeyboard
function E:NewFrame(type, name, strata, sizeX, sizeY, point, parent, enablemouse, enablemousewheel, enablekeyboard, template)
	
	local Frame
	
	if not type then type = "Frame" end
	if not parent then parent = E.Parent end
	if not point then point = {"CENTER", parent, "CENTER", 0, 0} end
	if not enablemouse then enablemouse = false end
	if not enablemousewheel then enablemousewheel = false end
	if not enablekeyboard then enablekeyboard = false end
	if not sizeX then sizeX = parent:GetWidth() end
	if not sizeY then sizeY = parent:GetHeight() end
	
	Frame = CreateFrame(type, name, parent)
	
	if name then
		E.Frames[name] = Frame
	end
	
	
	if point then Frame:SetPoint(point[1], point[2], point[3], point[4], point[5]) end
	if strata then Frame:SetFrameStrata(strata) end
	if sizeY then Frame:SetWidth(sizeX) end
	if sizeY then Frame:SetHeight(sizeY) end
	if parent then Frame:SetParent(parent) end
	
	Frame:EnableMouse(enablemouse)
	Frame:EnableMouseWheel(enablemousewheel)
	Frame:EnableKeyboard(enablekeyboard)
	-- Frame:SetBackdropColor(50, 50, 0, 1)
	
	return Frame
end

function E:InitializeFontFrame(Frame, DrawLayer, Font, FontSize, FontColor, FontAlpha, Offset, DefaultText, Width, Height, Parent, Anchor, ShadowOffset)

	if not FontColor then FontColor = {0.9, 0.9, 0.9} end
	if not ShadowOffset then ShadowOffset = {1, 1} end
	if not Font then Font = "FRIZQT__.TTF" end
	if not FontSize then FontSize = 16 end
	if not Offset then Offset = {0, 0} end
	if not DrawLayer then DrawLayer = "OVERLAY" end
	if not Parent then Parent = E.Parent end
	if not Anchor then Anchor = "CENTER" end
	if not Width then Width = Parent:GetWidth() end
	if not Height then Height = Parent:GetHeight() end
	
	Frame:ClearAllPoints()
	Frame:SetTextColor(FontColor[1], FontColor[2], FontColor[3], FontAlpha)
	Frame:SetShadowOffset(ShadowOffset[1], ShadowOffset[2])
	Frame:SetFont("Fonts\\" .. Font, FontSize)
	Frame:SetPoint(Anchor, Parent, Anchor, Offset[1], Offset[2])
	Frame:SetText(DefaultText)
	Frame:SetDrawLayer(DrawLayer)
	Frame:SetWidth(Width)
	Frame:SetHeight(Height)
end

-- The return value and E.Fonts[Name] allows access to typical Frame and Font methods
function E:NewFont(Name, Layer, Parent)
	local Frame 	= E:NewFrame("Frame", Name, _, _, _, _, Parent)
	
	Frame			=	Frame:CreateFontString(Name, Layer)
	E:InitializeFontFrame(Frame, Layer, _, _, _, _, {0, 0}, "Hello world", _, _, Parent)
	E.Fonts[Name] = Frame
	
	return Frame
end

-- Reposition Frame entirely
function E:RepositionFrame(Frame, Point, OffsetX, OffsetY, Parent)
	
	local _
	
	if not Parent then
		_, Parent, _ = Frame:GetPoint(Frame:GetNumPoints())
	end
	Frame:ClearAllPoints()
	Frame:SetPoint(Point, Parent, Point, OffsetX, OffsetY)
end

-- Move frame relative to its parent
function E:MoveFrame(Frame, OffsetX, OffsetY)
	local Point, RelativeTo, RelativePoint = Frame:GetPoint(Frame:GetNumPoints())
	Frame:SetPoint(Point, RelativeTo, RelativePoint, OffsetX, OffsetY)
end

-- Push frame relative from its current location
function E:PushFrame(Frame, PushX, PushY)
	local Point, RelativeTo, RelativePoint, OffsetX, OffsetY = Frame:GetPoint(Frame:GetNumPoints())
	if not OffsetX then OffsetX = 0 end
	if not OffsetY then OffsetY = 0 end
	Frame:SetPoint(Point, RelativeTo, RelativePoint, OffsetX + PushX, OffsetY + PushY)
end

function E:SetFramePoint(Frame, Point)
	local _, RelativeTo = Frame:GetPoint(Frame:GetNumPoints())
	
	Frame:SetPoint(Point, RelativeTo, Point)
end

------------------------
-- To correctly update a font, we have to set the font info with this method first.
-- When ready to update, it is followed by E:UpdateFont(FrameName)
-- If no or less than the maximum amount of arguments are passed, all info will be retrieved automatically
-- This is potentially extremely CPU-intensive, since we are probably iterating through every single font (About 200 frames)
----- @PARAM
--------	Frame(object):		Font object to to update
--------	fontName(str):		Font type. It is spcified by a full path (such as )
--------	fontFlags(str):		Additional info such as "OUTLINE, MONOCHROME"
--------	fontHeight(num):	The Font Height in px
--------	fontColor(table):	A table to represent the r,g,b colors and alpha values in that order. Values range from 0 to 1
----- @RETURN
--------	NONE
------------------------

function E:SetFontInfo(Frame, fontName, fontFlags, fontHeight, fontColor)
	
	if not Frame then return end
	
	local FontInfo = {}
	
	-- Get current values from font if not specified. This is to allow a more dynamic flow
	if not fontName or not fontFlags or not fontHeight or not fontColor then FontInfo = E:GetFontInfo(Frame) end
	
	if not fontName then fontName 		= FontInfo["fontName"] end
	if not fontFlags then fontFlags 	= FontInfo["fontFlags"] end
	if not fontHeight then fontHeight 	= FontInfo["fontHeight"] end
	if not fontColor then fontColor 	= {FontInfo["r"],FontInfo["g"],FontInfo["b"],FontInfo["a"]} end
	
	Frame["fontName"]	=	fontName
	Frame["fontFlags"]	=	fontFlags
	Frame["fontHeight"]	=	fontHeight
	Frame["r"]			=	fontColor[1]
	Frame["g"]			=	fontColor[2]
	Frame["b"]			=	fontColor[3]
	Frame["a"]			=	fontColor[4]
end

function E:GetFontInfo(Frame)
	
	local Data = {}
	local fontName, fontHeight, fontFlags = Frame:GetFont()
	local r, g, b, a = Frame:GetTextColor()
	
	Data["fontName"] 	= fontName
	Data["fontHeight"] 	= fontHeight
	Data["fontFlags"]	= fontFlags
	Data["r"] 			= r
	Data["g"] 			= g
	Data["b"] 			= b
	Data["a"] 			= a
	
	return Data
end

-- Update Font with values stored within
function E:UpdateFont(Frame)
	
	if Frame ~= nil then				
		Frame:SetFont(Frame["fontName"], Frame["fontHeight"] * 1, Frame["fontFlags"])
		Frame:SetTextColor(Frame["r"], Frame["g"], Frame["b"], Frame["a"])
	else
		return
	end
end

-- Move a font container frame properly
function E:SetFontFramePoint(Frame, Point)
	Frame:ClearAllPoints()
	Frame:SetPoint(Point,Frame:GetParent())
	Frame:SetJustifyH(Point)
end

-- Parent Frame 
function E:MergeFrames(Source, Target)
	Source:SetParent(Target)
	Source:SetAllPoints(Target)
	--E:debugprint(E:GetFrameName(Target) .. " is now a parent of " .. E:GetFrameName(Source))
end

function E:GetFrameName(Frame)
	return Frame:GetName()
end

function E:GetFramePosition(Frame)
	local _,_,_,offsetX,offsetY = Frame:GetPoint()
	return offsetX,offsetY
end

function E:UpdateBlendmode(Frame, Blendmode)
	Frame:GetStatusBarTexture():SetBlendMode(Blendmode)
end

function E:GetFrameLevel(Frame)
	if not Frame then Frame = E.Frames[Frame] end
	if Frame:GetFrameType() then
		return Frame:GetFrameLevel()
	else
		return 1
	end
end

function E:SetModelInfo(Frame, Info, Value)
	
	if Info == "SetPortraitZoom" then
		Frame:SetPortraitZoom(Value)
	elseif Info == "SetCamDistanceScale" then
		Frame:SetCamDistanceScale(Value)
	elseif Info == "SetRotation" then
		Frame:SetRotation(Value)
	elseif Info == "SetDisplayInfo" then
		Frame:SetDisplayInfo(Value)
	elseif Info == "SetUnit" and UnitExists(Value) then -- When Unit REALLY exists!
		Frame:SetUnit(Value)
	elseif Info == "ClearUnit" then
		Frame:ClearModel()
	end
end

function E:ToggleFrame(Frame, State, Fade)
	Fade = Fade or false

	if State == false then
		if Frame:GetAlpha() ~= 0 and Fade == true then
			UIFrameFadeOut(Frame, E.FrameFadeTime, Frame:GetAlpha(), 0) -- To make sure, we never constantly repeat the fade from 1 to 0, fade from current alpha
		end
		if Frame:GetAlpha() == 0 or Fade == false then
			Frame:Hide()
			Frame:SetAlpha(0)
		end
	end
	if State == true then
		if Frame:GetAlpha() ~= 1 and Fade == true then
			UIFrameFadeOut(Frame, E.FrameFadeTime, Frame:GetAlpha(), 1) -- To make sure, we never constantly repeat the fade from 1 to 0, fade from current alpha
		end
		if Frame:GetAlpha() == 1 or Fade == false then
			Frame:Show()
			Frame:SetAlpha(1)
		end
	end
end

function E:Remove(Frame)
	if Frame.UnregisterAllEvents then
		Frame:UnregisterAllEvents()
		-- Frame:SetParent(HiddenFrame)
	else
		Frame.Show = Frame.Hide
	end

	Frame:Hide()
	Frame:SetScript("OnShow", function(self) self:Hide() end)
end

function E:SetFrameBorder(F, S, R, G, B, A)
	if S then
		F:SetBackdrop({ edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = S, tile = true})
	end
	if R and G and B and A then
		F:SetBackdropBorderColor(R, G, B, A)
	end
end