aUF = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.0", "AceDB-2.0", "AceConsole-2.0")
aUF.Layouts = {}

local L = AceLibrary("AceLocale-2.0"):new("ag_UnitFrames")

local print = function(msg) if msg then DEFAULT_CHAT_FRAME:AddMessage(msg) end end

-- SYSTEM

function aUF:OnInitialize()
	self:RegisterDB("aUFDB")
	self:RegisterDefaults('profile', aUF_DEFAULT_OPTIONS)
	
	self:SetupVariables()
	self:UpdateBlizzVisibility()
	self:InitMenu()
	self:RegisterEvents()
	self:LoadStringFormats()
	if UnitInRaid("player") == 1 then
		self:RAID_ROSTER_UPDATE()
	end
	aUF:ScheduleRepeatingEvent("agUF_auraPoolSchedule",self.AuraPool, 0.3, self)
end

function aUF:AuraPool()
	local n = 0
	for k,v in pairs(self.auraUpdatePool) do
		if v == true and self.auraUpdates + n < 5 then
			self.units[k]:UpdateAuras(true)
			n = n + 1
		else
			break
		end
	end
	aUF.auraUpdates = 0
end

function aUF:Reset()
	self:ResetDB("profile")
	self:LoadStringFormats()
	self:CallUnitMethods("Reset")
	self:CallUnitMethods("Reset",nil,nil,nil,"subgroups")
end

function aUF:OnProfileEnable()
	self:CallUnitMethods("Reset")
end

-- EVENT REGISTERING

function aUF:RegisterEvents()
	self:RegisterEvent("PLAYER_LOGIN")
	self:RegisterEvent("PARTY_MEMBERS_CHANGED")
	self:RegisterEvent("RAID_ROSTER_UPDATE")
	self:RegisterEvent("UNIT_PET","PARTY_MEMBERS_CHANGED")
	self:RegisterEvent("PLAYER_TARGET_CHANGED")

	self:RegisterEvent("agUF_UpdateGroups")
end

function aUF:SetupVariables()
	self.auraUpdates = 0
	self.auraUpdatePool = {}
	
	self.feedback = {}
	
	self.imagePath = "Interface\\AddOns\\ag_UnitFrames\\images\\"
	self.fontPath = "Interface\\AddOns\\ag_UnitFrames\\fonts\\"
	
	self.wowClasses = {"player","pet","party","partypet","target","targettarget","raid","raidpet"}
	
	-- Which auras can the player see?
	self.CanDispel = {
		["PRIEST"] = {
			["Magic"] = true,
			["Disease"] = true,
		},
		["SHAMAN"] = {
			["Poison"] = true,
			["Disease"] = true,
		},
		["PALADIN"] = {
			["Magic"] = true,
			["Poison"] = true,
			["Disease"] = true,
		},
		["MAGE"] = {
			["Curse"] = true,
		},
		["DRUID"] = {
			["Curse"] = true,
			["Poison"] = true,
		}
	}
	
	-- Various constants like colors, textures...
	
	self.DebuffColor = {
		["Magic"] = {
			r = 1,
			g = 0,
			b = 0,
		},
		["Disease"] = {
			r = 0.25,
			g = 1,
			b = 0,
		},
		["Poison"] = {
			r = 0,
			g = 0.25,
			b = 1,
		},
		["Curse"] = {
			r = 0.75,
			g = 0,
			b = 0.75,
		}
	}
	
	self.RepColor = {
		[1] = {r = 226/255, g = 45/255, b = 75/255},
		[2] = {r = 226/255, g = 45/255, b = 75/255},
		[3] = {r = 0.75, g = 0.27, b = 0},
		[4] = {r = 1, g = 1, b = 34/255},
		[5] = {r = 0.2, g = 0.8, b = 0.15},
		[6] = {r = 0.2, g = 0.8, b = 0.15},
		[7] = {r = 0.2, g = 0.8, b = 0.15},
		[8] = {r = 0.2, g = 0.8, b = 0.15},
	}
	
	self.HealthColor = {
		r = 0.11,
		g = 0.84,
		b = 0.3,
	}
	
	self.ManaColor = {
		[0] = { r = 48/255, g = 113/255, b = 191/255}, -- Mana
		[1] = { r = 226/255, g = 45/255, b = 75/255}, -- Rage
		[2] = { r = 255/255, g = 210/255, b = 0}, -- Focus
		[3] = { r = 255, g = 220/255, b = 25/255}, -- Energy
		[4] = { r = 0.00, g = 1.00, b = 1.00} -- Happiness
	}
	
	self.Borders = {
		["Classic"] 	= {["texture"] = "Interface\\Tooltips\\UI-Tooltip-Border",["size"] = 16,["insets"] = 5},
		["Nurfed"]	 	= {["texture"] = "Interface\\DialogFrame\\UI-DialogBox-Border",["size"] = 16,["insets"] = 5},
		["Hidden"] 		= {["texture"] = "",["size"] = 0,["insets"] = 3},
	}
	self.Bars	= {
		["Default"]		= self.imagePath.."AceBarFrames.tga",
		["Classic"]		= "Interface\\TargetingFrame\\UI-StatusBar",
		["Smooth"]		= self.imagePath.."smooth.tga",
		["Bumps"]		= self.imagePath.."Bumps.tga",
		["Perl"]		= self.imagePath.."Perl.tga",
		["Gloss"]		= self.imagePath.."Gloss.tga",
		["Wisps"]		= self.imagePath.."Wisps.tga",
		["Bars"]		= self.imagePath.."Bars.tga",
		["Smudge"]	    = self.imagePath.."Smudge.tga",
		["Dabs"]		= self.imagePath.."Dabs.tga",
		["Rain"]		= self.imagePath.."Rain.tga",
		["Hatched"]	    = self.imagePath.."Hatched.tga",
		["Cracked"]	    = self.imagePath.."Cracked.tga",
		["Grid"]		= self.imagePath.."Grid.tga",
		["Button"]		= self.imagePath.."Button.tga",
		["Skewed"]		= self.imagePath.."Skewed.tga",
		["Diagonal"]	= self.imagePath.."Diagonal.tga",
		["Cloud"]		= self.imagePath.."Cloud.tga",
		["Water"]		= self.imagePath.."Water.tga",
		["Charcoal"]	= self.imagePath.."Charcoal.tga",
		["BantoBar"]	= self.imagePath.."BantoBar.tga",
		["DarkBottom"]  = self.imagePath.."DarkBottom.tga",
	}

	self.RaidColors = {
		["DRUID"]	= "|cffff7c0a",
		["HUNTER"]	= "|cffaad372",
		["MAGE"]	= "|cff68ccef",
		["PALADIN"]	= "|cfff48cba",
		["PRIEST"]	= "|cffffffff",
		["ROGUE"]	= "|cfffff468",
		["SHAMAN"]	= "|cfff48cba",
		["WARLOCK"]	= "|cff9382C9",
		["WARRIOR"]	= "|cffc69b6d",
	}

	self.RaidRole = {
		["DRUID"]	= "healer",
		["HUNTER"]	= "dps",
		["MAGE"]	= "dps",
		["PALADIN"]	= "healer",
		["PRIEST"]	= "healer",
		["ROGUE"]	= "dps",
		["SHAMAN"]	= "healer",
		["WARLOCK"]	= "dps",
		["WARRIOR"]	= "tank",
	}
	self.UnitInformation = {
	["name"] = function(u)
		local type = string.gsub(u, "%d", "")
		if self.db.profile[type].RaidColorName and UnitIsPlayer(u) then
			local _,x=UnitClass(u)
			return string.format("%s%s%s",aUF.RaidColors[x] or "",UnitName(u) or "","|cFFFFFFFF")
		else
			return UnitName(u) or ""
		end
	end,
	["status"] = function (u)
		if UnitIsDead(u) then
			return L["Dead"]
		elseif UnitIsGhost(u) then
			return L["Ghost"]
		elseif (not UnitIsConnected(u)) then
			return L["Offline"]
		elseif (UnitAffectingCombat(u)) then
			return L["Combat"]
		elseif (u == "player" and IsResting()) then
			return L["Resting"]
		else
			return ""
		end
	end,
	["statuscolor"] = function (u)
		if UnitIsDead(u) then
			return "|cffff0000"
		elseif UnitIsGhost(u) then
			return "|cff9d9d9d"
		elseif (not UnitIsConnected(u)) then
			return "|cffff8000"
		elseif (UnitAffectingCombat(u)) then
			return "|cffFF0000"
		elseif (u== "player" and IsResting()) then
			return self:GiveHex(UnitReactionColor[4].r, UnitReactionColor[4].g, UnitReactionColor[4].b)
		else
			return ""
		end
	end,
	["happycolor"] = function (u) local x=GetPetHappiness() return ( (x==2) and "|cffFFFF00" or (x==1) and "|cffFF0000" or "" ) end,

	["aghp"] = function(u) return self:Tag_aghp(u) or "" end,
	["agpercenthp"] = function(u) return self:Tag_aghp(u,1) or "" end,
	["agmissinghp"] = function(u) return self:Tag_aghp(u,2) or "" end,
	["agsmarthp"] = function(u) return self:Tag_aghp(u,3) or "" end,
	
	["agmana"] = function(u) return self:Tag_agmana(u) or "" end,
	["agpercentmana"] = function(u) return self:Tag_agmana(u,1) or "" end,
	["agmissingmana"] = function(u) return self:Tag_agmana(u,2) or "" end,
	["agsmartmana"] = function(u) return self:Tag_agmana(u,3) or "" end,
	
	["agclass"] = function (u) if UnitIsPlayer(u) then return (UnitClass(u) or L["Unknown"]) else return (UnitCreatureFamily(u) or UnitCreatureType(u) or "") end end,
	["agrace"] = function (u) if string.find(u,"target") then return UnitRace(u) or "" else return "" end end,
	["agtype"] = function (u) if (UnitIsPlusMob(u)) then return aUF:TargetGetMobType(u) or "" else return "" end end,
	
	["curhp"] = function (u) return UnitHealth(u) or 0 end,
	["maxhp"] = function (u) return UnitHealthMax(u) or 1 end,
	["percenthp"] = function (u) local hpmax = UnitHealthMax(u) return (hpmax ~= 0) and floor((UnitHealth(u) / hpmax) * 100) or 0 end,
	["missinghp"] = function (u) return UnitHealthMax(u) - UnitHealth(u) or 0 end,
	
	["curmana"] = function (u) return UnitMana(u) or 1 end,
	["maxmana"] = function (u) return UnitManaMax(u) or 0 end,
	["percentmana"] = function (u) local mpmax = UnitManaMax(u) return (mpmax ~= 0) and floor((UnitMana(u) / mpmax) * 100) or 0 end,
	["missingmana"] = function (u) return UnitHealthMax(u) - UnitHealth(u) or 0 end,

	["typemana"] = function (u) local p=UnitPowerType(u) return ( (p==1) and L["Rage"] or (p==2) and L["Focus"] or (p==3) and L["Energy"] or L["Mana"] ) end,
	["level"] = function (u) local x = UnitLevel(u) return ((x>0) and x or "??") end,
	["class"] = function (u) return (UnitClass(u) or L["Unknown"]) end,
	["creature"] = function (u) return (UnitCreatureFamily(u) or UnitCreatureType(u) or L["Unknown"]) end,
	["smartclass"] = function (u) if UnitIsPlayer(u) then return self.UnitInformation["class"](u) else return self.UnitInformation["creature"](u) end end,
	["combos"] = function (u) return (GetComboPoints() or 0) end,
	["combos2"] = function (u) return string.rep("@", GetComboPoints()) end,
	["classification"] = function (u)
		if UnitClassification(u) == "rare" then
			return L["Rare"]
		elseif UnitClassification(u) == "eliterare" then
			return L["Rare Elite"]
		elseif UnitClassification(u) == "elite" then
			return L["Elite"]
		elseif UnitClassification(u) == "worldboss" then
			return L["Boss"]
		else
			return ""
		end
	end,
	["faction"] = function (u) return (UnitFactionGroup(u) or "") end,
	["connect"] = function (u) return ( (UnitIsConnected(u)) and "" or L["Offline"] ) end,
	["race"] = function (u) return ( UnitRace(u) or "") end,
	["pvp"] = function (u) return ( UnitIsPVP(u) and "PvP" or "" ) end,
	["plus"] = function (u) return ( UnitIsPlusMob(u) and "+" or "" ) end,
	["sex"] = function (u) local x = UnitSex(u) return ( (x==0) and L["Male"] or (x==1) and L["Female"] or "" ) end,
	["rested"] = function (u) return (GetRestState()==1 and L["Rested"] or "") end,
	["leader"] = function (u) return (UnitIsPartyLeader(u) and L["(L)"] or "") end,
	["leaderlong"] = function (u) return (UnitIsPartyLeader(u) and L["(Leader)"] or "") end,

	["happynum"] = function (u) return (GetPetHappiness() or 0) end,
	["happytext"] = function (u) return ( getglobal("PET_HAPPINESS"..(GetPetHappiness() or 0)) or "" ) end,
	["happyicon"] = function (u) local x=GetPetHappiness() return ( (x==3) and ":)" or (x==2) and ":|" or (x==1) and ":(" or "" ) end,

	["curxp"] = function (u) return (UnitXP(u) or "") end,
	["maxxp"] = function (u) return (UnitXPMax(u) or "") end,
	["percentxp"] = function (u) local x=UnitXPMax(u) if (x>0) then return floor( UnitXP(u)/x*100+0.5) else return 0 end end,
	["missingxp"] = function (u) return (UnitXPMax(u) - UnitXP(u)) end,
	["restedxp"] = function (u) return (GetXPExhaustion() or "") end,

	["tappedbyme"] = function (u) if UnitIsTappedByPlayer("target") then return "*" else return "" end end,
	["istapped"] = function (u) if UnitIsTapped(u) and (not UnitIsTappedByPlayer("target")) then return L["Tapped"] else return "" end end,
	["pvpranknum"] = function (u) if (UnitPVPRank(u) >= 1) then return ((UnitPVPRank(u)-4) or "") else return "" end end,
	["pvprank"] = function (u) if (UnitPVPRank(u) >= 1) then return (GetPVPRankInfo(UnitPVPRank(u), u) or "" ) else return "" end end,
	["fkey"] = function (u)
		local _,_,fkey = string.find(u, "^party(%d)$")
		if u == "player" then
			fkey = 0
		end
		if not fkey then
			return ""
		else
			return "F"..(fkey+1)
		end
	end,
	["white"] = function (u) return "|cFFFFFFFF" end,
	["aggro"] = function (u)
		local x = (UnitReaction("player",u) or 5)
		return self:GiveHex(UnitReactionColor[x].r, UnitReactionColor[x].g, UnitReactionColor[x].b)
	end,
	["difficulty"] = function (u)
		if UnitCanAttack("player",u) then
			local x = (UnitLevel(u)>0) and UnitLevel(u) or 99
			local color = GetDifficultyColor(x)
			return aUF:GiveHex(color.r,color.g,color.b)
		else
			return ""
		end
	end,
	["colormp"] = function (u) local x = ManaBarColor[UnitPowerType(u)] return self:GiveHex(x.r, x.g, x.b) end,
	["inmelee"] = function (u) if PlayerFrame.inCombat then return "|cffFF0000" else return "" end end,
	["incombat"] = function (u) if UnitAffectingCombat(u) then return "|cffFF0000" else return "" end end,
	["raidcolor"] = function (u) local _,x=UnitClass(u) if x and UnitIsPlayer(u) then return (self.RaidColors[x] or "") else return "" end end,
	}

	self.formats = {
		["Health"] = {
			["Absolute"]   = "[aghp]",
			["Difference"] = "[agmissinghp]",
			["Percent"]    = "[agpercenthp]",
			["Smart"]      = "[agsmarthp]",
			["Hide"]       = "",
		},
		["Mana"] = {
			["Absolute"]   = "[agmana]",
			["Difference"] = "[agmissingmana]",
			["Percent"]    = "[agpercentmana]",
			["Smart"]      = "[agsmartmana]",
			["Hide"]       = "",
		},
		["Name"] = {
			["Default"]    = "[name]",
			["Hide"]       = "",
		},
		["Class"] = {
			["Default"]    = "[agtype][difficulty][level][white] [raidcolor][agclass][white] [agrace]",
			["Hide"]       = "",
		}
	}

	self.HelperFunctions = {}
	self.units = {}
	self.subgroups = {}
	self.changedSubgroups = {}
end

-- EVENTS

function aUF:PLAYER_LOGIN()
	aUF:CreateObject("player","player","XP")
	aUF:CreateObject("pet","pet","XP")
	aUF:CreateObject("target","target","Combo")
	aUF:CreateObject("targettarget","targettarget","Metro")
	
	self:PARTY_MEMBERS_CHANGED()
end

function aUF:PLAYER_TARGET_CHANGED()
	if self.units.target then
		self.units.target:UpdateAll()
	end
	if self.units.targettarget then
		if UnitExists("target") then
			self.units.targettarget:Start()
		else
			self.units.targettarget:Stop()
		end
	end
end

function aUF:PARTY_MEMBERS_CHANGED()
	for i = 1,4 do
		if aUF:CheckVisibility("party"..i) == true then
			aUF:CreateObject("party"..i)
		end
		if aUF:CheckVisibility("partypet"..i) == true then
			aUF:CreateObject("partypet"..i)
		end
	end
end

function aUF:RAID_ROSTER_UPDATE()
	for i = 1,40 do
		if aUF:CheckVisibility("raid"..i) == true then
			aUF:CreateObject("raid"..i,"raid"..i,"Raid")
		end
	end
	self:PARTY_MEMBERS_CHANGED()
end

function aUF:agUF_UpdateGroups()
	for name in pairs(self.changedSubgroups) do
		if string.find(name,"party") then
			self.subgroups[name].raid = false
		end
		self.subgroups[name]:Update()
	end
	self.changedSubgroups = {}
end

-- UTILITY FUNCTIONS

function aUF:CreateObject(name,unit,type,db)
	if not self.units[name] then
		if not unit then
			unit = name
		end
		if not type then
			self.units[name] = self.classes.aUFunit:new(name,unit,db)
		else
			self.units[name] = self.classes["aUFunit"..type]:new(name,unit,db)
		end
	end
end

function aUF:FindObjects(sortBy,object)
	local table = {}
	if not object then object = "units" end
	if self[object] then
		for _,v in pairs(self[object]) do
			if v[sortBy] then
				if not table[v[sortBy]] then
					table[v[sortBy]] = {}
				end
				tinsert(table[v[sortBy]],v)
			end
		end
	end
	return table
end

function aUF:CallUnitMethods(func,arg,find,type,object)
	if not func then return end
	if find and type then
		if aUF:FindObjects(type)[find] then
			for _,unitObject in pairs(aUF:FindObjects(type,object)[find]) do
				if unitObject[func] then
					unitObject[func](unitObject,arg)
				end
			end
		end
	else
		if not object then object = "units" end
		if self[object] then
			for _,unitObject in pairs(self[object]) do
				unitObject[func](unitObject,arg)
			end
		end
	end
end

function aUF:CheckVisibility(unit)
	local _,_,type = string.find(unit, "(%a+)")
	
--	if self.db.profile[type].AlwaysShow == true then
--		return true
--	end
	-- Special cases
	-- Hide targettarget if player is targetting self
	if unit == "targettarget" then
		if UnitName("player") == UnitName("target") then
			return false
		end
		-- Hide partyframes in raid
	elseif type == "party" then
		if self.db.profile.RaidHideParty == true and UnitInRaid("player") == 1 then
			return false
		end
	elseif type == "partypet" then
		if self.db.profile.RaidHideParty == true and UnitInRaid("player") == 1 then
			return false
		end
		local parent = string.gsub(unit,"pet","")
		if aUF:CheckVisibility(parent) == false then
			return false
		end
	elseif type == "raidpet" then
		local parent = string.gsub(unit,"pet","")
		if not aUF:CheckVisibility(parent) then
			return false
		end
	end
		
	if (UnitExists(unit) and not self.db.profile[type].HideFrame == true) then
		return true
	end
end

function aUF:UtilFactionColors(unit)
	local r, g, b = 0,0,0
	local a = 0.5
	if ( UnitPlayerControlled(unit) ) then
		if ( UnitCanAttack(unit, "player") ) then
			if ( not UnitCanAttack("player", unit) ) then
				r = self.ManaColor[0].r
				g = self.ManaColor[0].g
				b = self.ManaColor[0].b
			else
				r = self.ManaColor[1].r
				g = self.ManaColor[1].g
				b = self.ManaColor[1].b
			end
		elseif ( UnitCanAttack("player", unit) ) then
				r = self.ManaColor[3].r
				g = self.ManaColor[3].g
				b = self.ManaColor[3].b
		elseif ( UnitIsPVP(unit) ) then
			r = self.HealthColor.r
			g = self.HealthColor.g
			b = self.HealthColor.b
		else
			r = self.ManaColor[0].r
			g = self.ManaColor[0].g
			b = self.ManaColor[0].b
		end
	elseif ( UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) ) or UnitIsDead(unit) then
		r = 0.5
		g = 0.5
		b = 0.5
	else
		local reaction = UnitReaction(unit, "player")
		if ( reaction ) then
			if reaction == 5 or reaction == 6 or reaction == 7 then
				r = self.HealthColor.r
				g = self.HealthColor.g
				b = self.HealthColor.b
			elseif reaction == 4 then
				r = self.ManaColor[3].r
				g = self.ManaColor[3].g
				b = self.ManaColor[3].b
			elseif reaction == 1 or reaction == 2 or reaction == 3 then
				r = self.ManaColor[1].r
				g = self.ManaColor[1].g
				b = self.ManaColor[1].b
			else
				r = UnitReactionColor[reaction].r
				g = UnitReactionColor[reaction].g
				b = UnitReactionColor[reaction].b
			end
		end
	end
	return {r = r,g = g,b = b}
end

function aUF:GiveHex(r,g,b)
	r=r*255
	g=g*255
	b=b*255
	return string.format("|cff%2x%2x%2x", r, g, b) or ""
end

function aUF:GetRaidColors(class)
	if self.RaidColors[class] then
		return self.RaidColors[class]
	else
		return "|r"
	end
end

function aUF:TargetGetMobType(unit)
	local classification = UnitClassification(unit)
	if ( classification == "worldboss" ) then
		return L["Boss"]
	elseif ( classification == "rareelite" ) then
		return L["Rare-Elite"]
	elseif ( classification == "elite" ) then
		return L["Elite"]
	elseif ( classification == "rare" ) then
		return L["Rare"]
	else
		return nil
	end
end

function aUF:UnitDebuff(unit,id,filter)
	local aura, count, t = UnitDebuff(unit,id)
	if filter == 1 then
		local _, eClass = UnitClass("player")
		if ( self.CanDispel[eClass] and self.CanDispel[eClass][t] == true or ( eClass == "PRIEST" and (aura == "Interface\\Icons\\Spell_Holy_AshesToAshes" or aura == "Interface\\Icons\\Spell_Shadow_UnsummonBuilding")) ) then
			return aura, count or 0, t
		end
	else
		return aura, count or 0, t
	end
end

function aUF:FeedbackUpdate()
	local maxalpha = 0.6
	local found
	for objectName,v in pairs(self.feedback) do
		found = true
		local unitOjbect = aUF.units[objectName]
		local elapsedTime = GetTime() - unitOjbect.feedbackStartTime
		if ( elapsedTime < COMBATFEEDBACK_FADEINTIME ) then
			local alpha = maxalpha*(elapsedTime / COMBATFEEDBACK_FADEINTIME)
			unitOjbect.HitIndicator:SetAlpha(alpha)
		elseif ( elapsedTime < (COMBATFEEDBACK_FADEINTIME + COMBATFEEDBACK_HOLDTIME) ) then
			unitOjbect.HitIndicator:SetAlpha(maxalpha)
		elseif ( elapsedTime < (COMBATFEEDBACK_FADEINTIME + COMBATFEEDBACK_HOLDTIME + COMBATFEEDBACK_FADEOUTTIME) ) then
			local alpha = maxalpha - maxalpha*((elapsedTime - COMBATFEEDBACK_HOLDTIME - COMBATFEEDBACK_FADEINTIME) / COMBATFEEDBACK_FADEOUTTIME)
			unitOjbect.HitIndicator:SetAlpha(alpha)
		else
			unitOjbect.HitIndicator:Hide()
			aUF.feedback[objectName] = nil
		end
	end
	if not found then 
		self:CancelScheduledEvent("agUF_CombatSchedule")
	end
end

-- Dewdrop stuff

function aUF:CreateMenu()
	self.dewdrop = AceLibrary("Dewdrop-2.0")

	local unitTable = {}
	unitTable.UnitHeader = {
		name = L["unitsettings"],
		type = 'header',
		order = 1,
	}
	for order,unit in ipairs(self.wowClasses) do
		unitTable[unit] = aUF:CreateDewdrop(unit,(order + 1),true)
	end
	
	local agDewdropMenu = {
		type= 'group',
		args = {
			AddonHeader = {
				name = L["addonname"],
				type = 'header',
				order = 1,
			},
			Units = {
				name = L["units"],
				type = 'group',
				desc = L["UnitDesc"],
				args = unitTable,
				order = 2,
			},
			Borders = {
				name = L["borders"],
				type = 'text',
				desc = L["BordersDesc"],
				get = function()
					return self.db.profile.BorderStyle
				end,
				set = function(option)
					self.db.profile.BorderStyle = option
					self:CallUnitMethods("BorderBackground")
					self:CallUnitMethods("BorderBackground",nil,nil,nil,"subgroups")
				end,
				validate = {"Classic", "Nurfed", "Hidden"},
				order = 3,
			},
			FrameColors = {
				type= 'group',
				name = L["framecolors"],
				desc = L["framecolorsdesc"],
				args = {
					partybg = {
						name = L["partybg"],
						type = 'color',
						desc = L["partybgdesc"],
						hasAlpha = true,
						get = function()
							return self.db.profile.PartyFrameColors.r, self.db.profile.PartyFrameColors.g, self.db.profile.PartyFrameColors.b, self.db.profile.PartyFrameColors.a
						end,
						set = function(r, g, b, a)
							self.db.profile.PartyFrameColors.r, self.db.profile.PartyFrameColors.g, self.db.profile.PartyFrameColors.b, self.db.profile.PartyFrameColors.a = r, g, b, a
							self:CallUnitMethods("BorderBackground")
							self:CallUnitMethods("BorderBackground",nil,nil,nil,"subgroups")
						end,
						order = 1,
					},
					targetbg = {
						name = L["targetbg"],
						type = 'color',
						desc = L["targetbgdesc"],
						hasAlpha = true,
						get = function()
							return self.db.profile.TargetFrameColors.r, self.db.profile.TargetFrameColors.g, self.db.profile.TargetFrameColors.b, self.db.profile.TargetFrameColors.a
						end,
						set = function(r, g, b, a)
							self.db.profile.TargetFrameColors.r, self.db.profile.TargetFrameColors.g, self.db.profile.TargetFrameColors.b, self.db.profile.TargetFrameColors.a = r, g, b, a
							self:CallUnitMethods("BorderBackground")
							self:CallUnitMethods("BorderBackground",nil,nil,nil,"subgroups")
						end,
						order = 2,
					},
					border = {
						name = L["bordercolor"],
						type = 'color',
						desc = L["bordercolordesc"],
						hasAlpha = true,
						get = function()
							return self.db.profile.FrameBorderColors.r, self.db.profile.FrameBorderColors.g, self.db.profile.FrameBorderColors.b, self.db.profile.FrameBorderColors.a
						end,
						set = function(r, g, b, a)
							self.db.profile.FrameBorderColors.r, self.db.profile.FrameBorderColors.g, self.db.profile.FrameBorderColors.b, self.db.profile.FrameBorderColors.a = r, g, b, a
							self:CallUnitMethods("BorderBackground")
							self:CallUnitMethods("BorderBackground",nil,nil,nil,"subgroups")
						end,
						order = 3,
					},
				},
				order = 4,
			},
			BarColors = {
				type= 'group',
				args = {
					Health = {
						name = L["health"],
						type = 'color',
						desc = L["healthDesc"],
						get = function()
							return self.db.profile.HealthColor.r, self.db.profile.HealthColor.g, self.db.profile.HealthColor.b
						end,
						set = function(r, g, b)
							self.db.profile.HealthColor.r, self.db.profile.HealthColor.g, self.db.profile.HealthColor.b = r, g, b
							self:CallUnitMethods("StatusBarsColor")
						end,
						order = 1,
					},
					Mana = {
						name = L["mana"],
						type = 'color',
						desc = L["manaDesc"],
						get = function()
							return self.db.profile.ManaColor[0].r, self.db.profile.ManaColor[0].g, self.db.profile.ManaColor[0].b
						end,
						set = function(r, g, b)
							self.db.profile.ManaColor[0].r, self.db.profile.ManaColor[0].g, self.db.profile.ManaColor[0].b = r, g, b
							self:CallUnitMethods("StatusBarsColor")
						end,
						order = 2,
					},
					Rage = {
						name = L["rage"],
						type = 'color',
						desc = L["rageDesc"],
						get = function()
							return self.db.profile.ManaColor[1].r, self.db.profile.ManaColor[1].g, self.db.profile.ManaColor[1].b
						end,
						set = function(r, g, b)
							self.db.profile.ManaColor[1].r, self.db.profile.ManaColor[1].g, self.db.profile.ManaColor[1].b = r, g, b
							self:CallUnitMethods("StatusBarsColor")
						end,
						order = 3,
					},
					Energy = {
						name = L["energy"],
						type = 'color',
						desc = L["energyDesc"],
						get = function()
							return self.db.profile.ManaColor[3].r, self.db.profile.ManaColor[3].g, self.db.profile.ManaColor[3].b
						end,
						set = function(r, g, b)
							self.db.profile.ManaColor[3].r, self.db.profile.ManaColor[3].g, self.db.profile.ManaColor[3].b = r, g, b
							self:CallUnitMethods("StatusBarsColor")
						end,
						order = 4,
					},
					PetFocus = {
						name = L["petfocus"],
						type = 'color',
						desc = L["petfocusDesc"],
						get = function()
							return self.db.profile.ManaColor[2].r, self.db.profile.ManaColor[2].g, self.db.profile.ManaColor[2].b
						end,
						set = function(r, g, b)
							self.db.profile.ManaColor[2].r, self.db.profile.ManaColor[2].g, self.db.profile.ManaColor[2].b = r, g, b
							self:CallUnitMethods("StatusBarsColor")
						end,
						order = 5,
					},
				},
				order = 5,
				name = L["barcolors"],
				desc = L["barcolorsDesc"],
			},
			BarStyle = {
				name = L["barstyle"],
				type = 'text',
				desc = L["BarStyleDesc"],
				get = function()
					return self.db.profile.BarStyle
				end,
				set = function(option)
					self.db.profile.BarStyle = option
					self:CallUnitMethods("BarTexture")
				end,
				validate = {"Classic", "Default","Smooth", "BantoBar", "Bars", "Bumps", "Button", "Charcoal", "Cloud", "Cracked", "Dabs", "DarkBottom", "Diagonal", "Gloss", "Grid", "Hatched", "Perl", "Rain", "Skewed", "Smudge", "Water", "Wisps"},
				order = 6,
			},
			ShowPvPIcon = {
				name = L["pvpicon"],
				type = 'toggle',
				desc = L["ShowPVPIconDesc"],
				get = function()
					return self.db.profile.ShowPvPIcon
				end,
				set = function(option)
					self.db.profile.ShowPvPIcon = option
					self:CallUnitMethods("UpdatePvP",true)
				end,
				order = 7,
			},
			ShowGroupIcons = {
				name = L["groupicon"],
				type = 'toggle',
				desc = L["ShowGroupIconsDesc"],
				get = function()
					return self.db.profile.ShowGroupIcons
				end,
				set = function(option)
					self.db.profile.ShowGroupIcons = option
					self:CallUnitMethods("LabelsCheckLeader")
				end,
				order = 8,
			},
			HighlightSelected = {
				name = L["highlightselected"],
				type = 'toggle',
				desc = L["HighlightSelectedDesc"],
				get = function()
					return self.db.profile.HighlightSelected
				end,
				set = function(option)
					self.db.profile.HighlightSelected = option
				end,
				order = 9,
			},
			Locked = {
				name = L["lock"],
				type = 'toggle',
				desc = L["LockedDesc"],
				get = function()
					return self.db.profile.Locked
				end,
				set = function(option)
					self.db.profile.Locked = option
				end,
				order = 12,
			},
		}
	}
	self.dewdrop:InjectAceOptionsTable(self, agDewdropMenu)
	return agDewdropMenu
end

function aUF:InitMenu()
	if not self.menu then
		self.menu = aUF:CreateMenu()
	end
	
	local agSlashMenu = {
		type = "group",
		args = {
			config = {
				name = L["config"],
				desc = L["configdesc"],
				type = 'execute',
				func = function()
					self.dewdrop:Open(UIParent, 'children', function() self.dewdrop:FeedAceOptionsTable(self.menu) end,'cursorX', true, 'cursorY', true)
				end,
			},
			reset = {
				name = L["reset"],
				desc = L["resetdesc"],
				type = 'execute',
				func = function()
					self:Reset()
				end,
			}
		}
	}
	
	self:RegisterChatCommand({ "/aguf", "/ag_unitframes" }, agSlashMenu )
end

function aUF:CreateDewdrop(class,order,mainmenu)
	--local class = type
	local prettyname = L[class]

	local strings = {"Health","Mana","Name","Class"}
	local stringArgs = {}

	for k,v in pairs(strings) do
		local name = v
		local order = k
		local validate
		if v == "Health" or v == "Mana" then
			validate = {"Absolute", "Difference", "Percent", "Smart","Custom", "Hide"}
		else
			validate = {"Default","Custom", "Hide"}
		end
		stringArgs[v] = {
			name = string.format(L["%s Text"], L[name]),
			type = 'group',
			desc = L["UnitDesc"],
			order = order,
			args = {
				StatusTextStyle = {
					name = L["Style"],
					type = 'text',
					desc = L["StatusTextDesc"],
					get = function()
						return self.db.profile[class][name.."Style"]
					end,
					set = function(option)
						self.db.profile[class][name.."Style"] = option
						
						self:SetStringFormats(class)
						self:CallUnitMethods("UpdateTextStrings",nil,class,"type")
					end,
					validate = validate,
					order = 1,
				},
				HealthCustom = {
					name = L["Custom"],
					type = 'text',
					desc = L["StatusTextDesc"],
					get = function()
						return self.db.profile[class][name.."Format"]
					end,
					set = function(option)
						self.db.profile[class][name.."Format"] = option
						
						self:SetStringFormats(class)
						self:CallUnitMethods("UpdateTextStrings",nil,class,"type")
					end,
					usage = "",
					order = 2,
				}
			}
		}
	end

	local table = {
		name = prettyname,
		type = 'group',
		desc = string.format(L["%s Settings"], prettyname),
		order = order,
		args = {
			UnitHeader = {
				name = string.format(L["layoutsettings"], prettyname),
				type = 'header',
				order = 1,
			},
			FrameStyle = {
				name = L["framestyle"],
				type = 'text',
				desc = L["FrameStyleDesc"],
				validate = {},
				get = function()
					return self.db.profile[class].FrameStyle
				end,
				set = function(option)
					self.db.profile[class].FrameStyle = option
					self:CallUnitMethods("ApplyTheme",nil,class,"type")
					self:CallUnitMethods("UpdateName",true,class,"type")
				end,
				order = 2,
			},

			Width = {
				name = L["widthadjust"],
				type = 'range',
				desc = L["widthadjustDesc"],
				min = 50,
				max = 400,
				step = 1,
				get = function()
					return self.db.profile[class].Width
				end,
				set = function(option)
					self.db.profile[class].Width = option
					self:CallUnitMethods("SetWidth",nil,class,"type")
				end,
				order = 3,
			},
			
			StatusTextStyle = {
				name = L["Status Text"],
				type = 'group',
				desc = L["UnitDesc"],
				order = 5,
				args = stringArgs,
			},
			Scale = {
				name = L["scale"],
				type = 'range',
				desc = L["ScaleDesc"],
				min = 0.5,
				max = 2,
				step = 0.01,
				isPercent = true,
				get = function()
					return self.db.profile[class].Scale
				end,
				set = function(option)
					self.db.profile[class].Scale = option
					self:CallUnitMethods("LoadScale",nil,class,"type")
					self:CallUnitMethods("LoadPosition",nil,class,"type")
				end,
				order = 7,
			},
			ClassColorBars = {
				name = L["classcolorbar"],
				type = 'toggle',
				desc = L["ClassColorBarsDesc"],
				get = function()
					return self.db.profile[class].ClassColorBars
				end,
				set = function(option)
					self.db.profile[class].ClassColorBars = option
					self:CallUnitMethods("StatusBarsColor",nil,class,"type")
				end,
				order = 20,
			},
			RaidColorName = {
				name = L["raidcolorname"],
				type = 'toggle',
				desc = L["RaidColorNameDesc"],
				get = function()
					return self.db.profile[class].RaidColorName
				end,
				set = function(option)
					self.db.profile[class].RaidColorName = option
					self:CallUnitMethods("UpdateTextStrings",nil,class,"type")
				end,
				order = 21,
			},
			ShowCombat = {
				name = L["showcombat"],
				type = 'toggle',
				desc = L["ShowCombatDesc"],
				get = function()
					return self.db.profile[class].ShowCombat
				end,
				set = function(option)
					self.db.profile[class].ShowCombat = option
				end,
				order = 23,
			},
			ShowInCombatIcon = {
				name = L["showincombat"],
				type = 'toggle',
				desc = L["ShowInCombatDesc"],
				get = function ()
					return self.db.profile[class].ShowInCombatIcon
				end,
				set = function(option)
					self.db.profile[class].ShowInCombatIcon = option
				end,
				order = 24,
			},
			ShowRaidTargetIcon = {
				name = L["showraidicon"],
				type = 'toggle',
				desc = L["ShowRaidIconDesc"],
				get = function ()
					return self.db.profile[class].ShowRaidTargetIcon
				end,
				set = function(option)
					self.db.profile[class].ShowRaidTargetIcon = option
					self:CallUnitMethods("UpdateRaidTargetIcon",true,class,"type")
				end,
				order = 25,
			},
			LongStatusbars = {
				name = L["longbars"],
				type = 'toggle',
				desc = L["LongBarsDesc"],
				get = function()
					return self.db.profile[class].LongStatusbars
				end,
				set = function(option)
					self.db.profile[class].LongStatusbars = option
					self:CallUnitMethods("ApplyTheme",nil,class,"type")
				end,
				order = 26,
			},
			HideMana = {
				name = L["hidemana"],
				type = 'toggle',
				desc = L["HideManaDesc"],
				get = function()
					return self.db.profile[class].HideMana
				end,
				set = function(option)
					self.db.profile[class].HideMana = option
					self:CallUnitMethods("ApplyTheme",nil,class,"type")
					self:CallUnitMethods("UpdateName",true,class,"type")
				end,
				order = 27,
			},
			HideFrame = {
				name = L["hideframe"],
				type = 'toggle',
				desc = L["HideFrameDesc"],
				get = function()
					return self.db.profile[class].HideFrame
				end,
				set = function(option)
					self.db.profile[class].HideFrame = option
					self:RAID_ROSTER_UPDATE()
					self:CallUnitMethods("UpdateAll",nil,class,"type")
				end,
				order = 29,
			},
			Spacing1 = {
				name = " ",
				type = 'header',
				order = 35,
			},
			AuraHeader = {
				name = L["aurasettings"],
				type = 'header',
				order = 39,
			},
			AuraStyle = {
				name = L["aurastyle"],
				type = 'text',
				desc = L["AuraStyleDesc"],
				get = function()
					return self.db.profile[class].AuraStyle
				end,
				set = function(option)
					self.db.profile[class].AuraStyle = option
					self:CallUnitMethods("UpdateAuras",true,class,"type")
					self:CallUnitMethods("AuraPosition",true,class,"type")
				end,
				validate = {OneLine = L["oneline"], TwoLines = L["twolines"], Hide = L["hide"]},
				order = 40,
			},
			AuraPos = {
				name = L["aurapos"],
				type = 'text',
				desc = L["AuraPosDesc"],
				get = function()
					return self.db.profile[class].AuraPos
				end,
				set = function(option)
					self.db.profile[class].AuraPos = option
					self:CallUnitMethods("UpdateAuras",true,class,"type")
					self:CallUnitMethods("AuraPosition",true,class,"type")
				end,
				validate = {"Right", "Left", "Above", "Below"},
				order = 41,
			},
			DebuffColoring = {
				name = L["debuffcoloring"],
				type = 'toggle',
				desc = L["DebuffColoringDesc"],
				get = function()
					return self.db.profile[class].AuraDebuffC
				end,
				set = function(option)
					self.db.profile[class].AuraDebuffC = option
					self:CallUnitMethods("UpdateAuras",true,class,"type")
				end,
				order = 42,
			},
			AuraFilter = {
				name = L["aurafilter"],
				type = 'toggle',
				desc = L["AuraFilterDesc"],
				get = function()
					if self.db.profile[class].AuraFilter == 1 then
						return true
					else
						return false
					end
				end,
				set = function(option)
					if option == true then
						self.db.profile[class].AuraFilter = 1
					else
						self.db.profile[class].AuraFilter = 0
					end
					self:CallUnitMethods("UpdateAuras",true,class,"type")
				end,
				order = 43,
			}
		}
	}
	-- Inject themes from the theme table
	local themetable = {}
	for k, v in pairs(self.Layouts) do
		tinsert(themetable,k)
	end
	table.args.FrameStyle.validate = themetable

	-- PLAYER/PET
	--[[
	if class == "player" then
		local ShowRestingIcon = {
				name = L["showresting"],
				type = 'toggle',
				desc = L["ShowRestingDesc"],
				get = function()
					return self.db.profile[class].ShowRestingIcon
				end,
				set = function(option)
					self.db.profile[class].ShowRestingIcon = option
					self:CallUnitMethods("UpdateResting",nil,class,"type")
				end,
				order = 26,
			}
		table.args.ShowRestingIcon = ShowRestingIcon
	end
	]]
	if class == "player" or class == "pet" then
		local ShowXP = {
				name = L["showxp"],
				type = 'toggle',
				desc = L["ShowXPDesc"],
				get = function()
					return self.db.profile[class].ShowXP
				end,
				set = function(option)
					self.db.profile[class].ShowXP = option
					self:CallUnitMethods("ApplyTheme",nil,class,"type")
				end,
				order = 26,
			}
		table.args.ShowXP = ShowXP
	end

	if class == "pet" then
		local PetGrouping = {
				name = L["petgrouping"],
				type = 'text',
				desc = L["PetGroupingDesc"],
				get = function()
					return self.db.profile.PetGrouping
				end,
				set = function(option)
					self.db.profile.PetGrouping = option
					self:CallUnitMethods("UpdateAll")
				end,
				validate = {["withplayer"] = L["withplayer"], ["nogroup"] = L["nogroup"]},
				order = 6,
			}
		table.args.PetGrouping = PetGrouping
	end
	
	if class == "pet" or class == "partypet" or class == "raidpet" then
		table.args.RaidColorName = nil
		table.args.ClassColorBars = nil
	end
	
	-- TARGET
	if string.find(class,"target") then	
		local TargetShowHostile = {
				name = L["targetshowhostile"],
				type = 'toggle',
				desc = L["TargetHostileDesc"],
				get = function()
					return self.db.profile.TargetShowHostile
				end,
				set = function(option)
					self.db.profile.TargetShowHostile = option
					self:CallUnitMethods("StatusBarsColor",nil,class,"type")
				end,
				order = 22,
			}
		table.args.TargetShowHostile = TargetShowHostile
	end

	-- PARTY
	if class == "party" then
		local RaidHideParty = {
				name = L["raidhideparty"],
				type = 'toggle',
				desc = L["RaidHidePartyDesc"],
				get = function()
					return self.db.profile.RaidHideParty
				end,
				set = function(option)
					self.db.profile.RaidHideParty = option
					self:CallUnitMethods("UpdateAll",nil,"party","type")
					self:CallUnitMethods("UpdateAll",nil,"partypet","type")
				end,
				order = 28,
			}
		table.args.RaidHideParty = RaidHideParty

		local PartyGrouping = {
				name = L["partygrouping"],
				type = 'text',
				desc = L["PartyGroupingDesc"],
				get = function()
					return self.db.profile.PartyGrouping
				end,
				set = function(option)
					self.db.profile.PartyGrouping = option
					self:PARTY_MEMBERS_CHANGED()
					self:CallUnitMethods("UpdateAll")
				end,
				validate = {["withplayer"] = L["withplayer"], ["withoutplayer"] = L["withoutplayer"], ["nogroup"] = L["nogroup"]},
				order = 6,
			}
		table.args.PartyGrouping = PartyGrouping
	end
	
	-- RAID
	if class == "raid" then
		local RaidGrouping = {
				name = L["raidgrouping"],
				type = 'text',
				desc = L["RaidGroupingDesc"],
				get = function()
					return self.db.profile.RaidGrouping
				end,
				set = function(option)
					self.db.profile.RaidGrouping = option
					self:CallUnitMethods("UpdateAll")
				end,
				validate = {["bysubgroup"] = L["bysubgroup"], ["byclass"] = L["byclass"], ["byrole"] = L["byrole"], ["nogroup"] = L["nogroup"], ["onebiggroup"] = L["onebiggroup"]},
				order = 6,
			}
		table.args.RaidGrouping = RaidGrouping
	end
	
	if not mainmenu then
		table.args.UnitHeader.name = string.format(L["frame"], L[class])
		local EndSpacing = {
			name = " ",
			type = 'header',
			order = 51,
		}
		table.args.EndSpacing = EndSpacing
	end
	
	return table
end

function aUF:LoadStringFormats()
	for order,unit in ipairs(self.wowClasses) do
		self:SetStringFormats(unit)
	end
end

function aUF:SetStringFormats(type)
	local db = self.db.profile[type]
	local strings = {"Health","Mana","Name","Class"}
	if not aUF.HelperFunctions[type] then
		aUF.HelperFunctions[type] = {}
	end

	for k,v in pairs(strings) do
		local format
		if db[v.."Style"] == "Custom" then
				format = db[v.."Format"]
		else
			format = self.formats[v][db[v.."Style"]]
		end
		aUF.HelperFunctions[type][v.."Text"] = self:Parse(format)
	end
end


-- Clads code-- Clads code-- Clads code-- Clads code
-- Clads code-- Clads code-- Clads code-- Clads code

-- Code Begins here
local work = {}
local strgsub, strsub, strgfind, strformat, strfind = string.gsub, string.sub, string.gfind, string.format, string.find

function aUF:Parse(format)
	if not format then
		return nil
	end

	local formatArgs, formatString = {}

	for s,data,e in strgfind(format, "()(%b[])()") do
		local tag = strsub(data, 2, -2)
		local func = aUF:GetTagFunction(tag)
		if func then
			table.insert(formatArgs, func)
		else
			error(strformat("\"%s\" is not a valid format tag.", data))
		end
	end

	formatString = strgsub(format, "%%", "%%%%")
	formatString = strgsub(formatString, "%b[]", "%%s")

	-- Lets avoid unpacking extra results
	local num = table.getn(formatArgs)
	local tmp = work[num]
	if not tmp then
		tmp = {}
		work[num] = tmp
	end

	if num == 0 then
		return function(unit, fontstring)
			fontstring:SetText(formatString)
		end
	else
		return function(unit, fontstring)
			for i,func in ipairs(formatArgs) do 
				work[i] = func(unit)
			end
			fontstring:SetText(strformat(formatString, unpack(work)))
		end
	end
end

local helpers = {}

function aUF:GetTagFunction(tag)
	-- Check if this is just a unit tag
	if aUF.UnitInformation[tag] then return aUF.UnitInformation[tag] end

	local s,e,tag,args = strfind(tag, "^(%a+)%s+(.*)$")
	if not tag then
		-- Not a pattern we can recognize
		return nil
	end

	-- Bind the unit function to a local for closure purposes
	local func = aUF.UnitInformation[tag]
	if not func then
		-- Not a tag we support
		return nil
	end
	local _,_,width = strfind(args, "^(%d+)$")
	if width then
		local id = strformat("%s-%d", tag, width)
		local hFunc = helpers[id]
		if not hFunc then
			hFunc = function(unit)
				return strsub(func(unit), 1, width)
			end
			helpers[id] = hFunc
		end
		return hFunc
	end

	local _,_,oc,ec = strfind(args, "^(.)(.)$")
	if oc then
		local id = strformat("%s-%s%s", tag, oc, ec)
		local hFunc = helpers[id]
		if not hFunc then
			hFunc = function(unit)
				local t = func(unit)
				if t ~= "" then return
					strformat("%s%s%s",oc,t,ec)
				else
					return t
				end
			end
			helpers[id] = hFunc
		end
		return hFunc
	end
end

function aUF:Tag_agmana(unit,flag)
	local currValue,maxValue = UnitMana(unit),UnitManaMax(unit)
	if maxValue == 0 then
		return ""
	end
	local perc = currValue/maxValue * 100	
	local manaDiff = maxValue - currValue	
	local text = ""
	
	if ( not UnitExists(unit) or UnitIsDead(unit) or UnitIsGhost(unit) or not UnitIsConnected(unit) ) then
		return ""
	end
	if currValue > maxValue then
		maxValue = currValue
	end
	if currValue > 9999 then
		currValue = string.format("%.1fk", currValue / 1000)
	end
	if maxValue > 9999 then
		maxValue = string.format("%.1fk", maxValue / 1000)
	end
	
	if flag == 1 then
		return string.format("%.0f%%", perc)
	elseif flag == 2 then
		if manaDiff > 9999 then
			manaDiff = string.format("%.1fk", manaDiff / 1000)
		end
		return (currValue.."|cffff7f7f-"..manaDiff.."|r")
	elseif flag == 3 then
		return currValue	
	else
		return (currValue.."/"..maxValue)
	end
	
	return text
end
	
function aUF:Tag_aghp(unit,flag)
	local currValue,maxValue = UnitHealth(unit),UnitHealthMax(unit)
	if maxValue == 0 then
		return ""
	end
	local perc = currValue/maxValue * 100
	local text = ""
	local MHfound = false
	if ( UnitIsDead(unit) ) then
		return L["dead"]
	elseif ( UnitIsGhost(unit) ) then
		return L["ghost"]
	elseif ( not UnitIsConnected(unit) or maxValue == 1 ) then
		return L["disc"]
	end
	if (MobHealth3 and not UnitIsFriend("player", unit) ) then
		currValue,maxValue,MHfound = MobHealth3:GetUnitHealth(unit, currValue,maxValue)
	end
	if currValue > maxValue then
		maxValue = currValue
	end
	local hpDiff = maxValue - currValue
	if currValue > 9999 then
		currValue = string.format("%.1fk", currValue / 1000)
	end
	if maxValue > 9999 then
		maxValue = string.format("%.1fk", maxValue / 1000)
	end
	
	if not flag and MHfound and not UnitIsFriend("player", unit) then
		return currValue .." (".. perc .."%)"
	end
	
	if not (flag == 1) and (MHfound or unit == "pet" or unit == "player" or UnitInParty(unit) or UnitInRaid(unit)) then
		if flag == 2 then
			if hpDiff > 0 then
				if hpDiff > 9999 then
					hpDiff = string.format("%.1fk", hpDiff / 1000)
				end
				return (currValue.."|cffff7f7f-"..hpDiff.."|r")
			else
				return currValue
			end
		elseif flag == 3 and hpDiff > 0 then
			if hpDiff > 9999 then
				hpDiff = string.format("%.1fk", hpDiff / 1000)
			end
			return "|cffff7f7f-"..hpDiff.."|r"
		elseif flag == 3 then
			return ""
		else
			return (currValue.."/"..maxValue)
		end
	else
		return string.format("%.0f%%", perc)
	end
	return text
end






-- Blizzard hide and show

function aUF:UpdateBlizzVisibility()
	if aUF.db.profile.BlizFramesVisibility.HidePlayerFrame == true then
		aUF:HideBlizzPlayer()
	else
		aUF:ShowBlizzPlayer()
	end
	if aUF.db.profile.BlizFramesVisibility.HidePartyFrame == true then
		aUF:HideBlizzParty()
	else
		aUF:ShowBlizzParty()
	end
	if aUF.db.profile.BlizFramesVisibility.HideTargetFrame == true then
		aUF:HideBlizzTarget()
	else
		aUF:ShowBlizzTarget()
	end
end

function aUF:HideBlizzPlayer()
	PlayerFrame:UnregisterEvent("UNIT_LEVEL")
	PlayerFrame:UnregisterEvent("UNIT_COMBAT")
	PlayerFrame:UnregisterEvent("UNIT_SPELLMISS")
	PlayerFrame:UnregisterEvent("UNIT_PVP_UPDATE")
	PlayerFrame:UnregisterEvent("UNIT_MAXMANA")
	PlayerFrame:UnregisterEvent("PLAYER_ENTER_COMBAT")
	PlayerFrame:UnregisterEvent("PLAYER_LEAVE_COMBAT")
	PlayerFrame:UnregisterEvent("PLAYER_UPDATE_RESTING")
	PlayerFrame:UnregisterEvent("PARTY_MEMBERS_CHANGED")
	PlayerFrame:UnregisterEvent("PARTY_LEADER_CHANGED")
	PlayerFrame:UnregisterEvent("PARTY_LOOT_METHOD_CHANGED")
	PlayerFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
	PlayerFrame:UnregisterEvent("PLAYER_REGEN_DISABLED")
	PlayerFrame:UnregisterEvent("PLAYER_REGEN_ENABLED")
	PlayerFrameHealthBar:UnregisterEvent("UNIT_HEALTH")
	PlayerFrameHealthBar:UnregisterEvent("UNIT_MAXHEALTH")
	PlayerFrameManaBar:UnregisterEvent("UNIT_MANA")
	PlayerFrameManaBar:UnregisterEvent("UNIT_RAGE")
	PlayerFrameManaBar:UnregisterEvent("UNIT_FOCUS")
	PlayerFrameManaBar:UnregisterEvent("UNIT_ENERGY")
	PlayerFrameManaBar:UnregisterEvent("UNIT_HAPPINESS")
	PlayerFrameManaBar:UnregisterEvent("UNIT_MAXMANA")
	PlayerFrameManaBar:UnregisterEvent("UNIT_MAXRAGE")
	PlayerFrameManaBar:UnregisterEvent("UNIT_MAXFOCUS")
	PlayerFrameManaBar:UnregisterEvent("UNIT_MAXENERGY")
	PlayerFrameManaBar:UnregisterEvent("UNIT_MAXHAPPINESS")
	PlayerFrameManaBar:UnregisterEvent("UNIT_DISPLAYPOWER")
	PlayerFrame:UnregisterEvent("UNIT_NAME_UPDATE")
	PlayerFrame:UnregisterEvent("UNIT_PORTRAIT_UPDATE")
	PlayerFrame:UnregisterEvent("UNIT_DISPLAYPOWER")
	PlayerFrame:Hide()
end

function aUF:ShowBlizzPlayer()
	PlayerFrame:RegisterEvent("UNIT_LEVEL")
	PlayerFrame:RegisterEvent("UNIT_COMBAT")
	PlayerFrame:RegisterEvent("UNIT_SPELLMISS")
	PlayerFrame:RegisterEvent("UNIT_PVP_UPDATE")
	PlayerFrame:RegisterEvent("UNIT_MAXMANA")
	PlayerFrame:RegisterEvent("PLAYER_ENTER_COMBAT")
	PlayerFrame:RegisterEvent("PLAYER_LEAVE_COMBAT")
	PlayerFrame:RegisterEvent("PLAYER_UPDATE_RESTING")
	PlayerFrame:RegisterEvent("PARTY_MEMBERS_CHANGED")
	PlayerFrame:RegisterEvent("PARTY_LEADER_CHANGED")
	PlayerFrame:RegisterEvent("PARTY_LOOT_METHOD_CHANGED")
	PlayerFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
	PlayerFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
	PlayerFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
	PlayerFrameHealthBar:RegisterEvent("UNIT_HEALTH")
	PlayerFrameHealthBar:RegisterEvent("UNIT_MAXHEALTH")
	PlayerFrameManaBar:RegisterEvent("UNIT_MANA")
	PlayerFrameManaBar:RegisterEvent("UNIT_RAGE")
	PlayerFrameManaBar:RegisterEvent("UNIT_FOCUS")
	PlayerFrameManaBar:RegisterEvent("UNIT_ENERGY")
	PlayerFrameManaBar:RegisterEvent("UNIT_HAPPINESS")
	PlayerFrameManaBar:RegisterEvent("UNIT_MAXMANA")
	PlayerFrameManaBar:RegisterEvent("UNIT_MAXRAGE")
	PlayerFrameManaBar:RegisterEvent("UNIT_MAXFOCUS")
	PlayerFrameManaBar:RegisterEvent("UNIT_MAXENERGY")
	PlayerFrameManaBar:RegisterEvent("UNIT_MAXHAPPINESS")
	PlayerFrameManaBar:RegisterEvent("UNIT_DISPLAYPOWER")
	PlayerFrame:RegisterEvent("UNIT_NAME_UPDATE")
	PlayerFrame:RegisterEvent("UNIT_PORTRAIT_UPDATE")
	PlayerFrame:RegisterEvent("UNIT_DISPLAYPOWER")
	PlayerFrame:Show()
end

function aUF:HideBlizzParty()
	self:Hook("RaidOptionsFrame_UpdatePartyFrames", function() end)
	for i=1,4 do
		local frame = getglobal("PartyMemberFrame"..i)
		frame:UnregisterAllEvents()
		frame:Hide()
	end
end

function aUF:ShowBlizzParty()
	self:Unhook("RaidOptionsFrame_UpdatePartyFrames")
	for i=1,4 do
		local frame = getglobal("PartyMemberFrame"..i)
		frame:RegisterEvent("PARTY_MEMBERS_CHANGED")
		frame:RegisterEvent("PARTY_LEADER_CHANGED")
		frame:RegisterEvent("PARTY_MEMBER_ENABLE")
		frame:RegisterEvent("PARTY_MEMBER_DISABLE")
		frame:RegisterEvent("PARTY_LOOT_METHOD_CHANGED")
		frame:RegisterEvent("UNIT_PVP_UPDATE")
		frame:RegisterEvent("UNIT_AURA")
		frame:RegisterEvent("UNIT_PET")
		frame:RegisterEvent("VARIABLES_LOADED")
		frame:RegisterEvent("UNIT_NAME_UPDATE")
		frame:RegisterEvent("UNIT_PORTRAIT_UPDATE")
		frame:RegisterEvent("UNIT_DISPLAYPOWER")

		UnitFrame_OnEvent("PARTY_MEMBERS_CHANGED")

		PartyMemberFrame_UpdateMember()
	end
end

function aUF:HideBlizzTarget()
	TargetFrame:UnregisterEvent("PLAYER_TARGET_CHANGED")
	TargetFrame:UnregisterEvent("UNIT_HEALTH")
	TargetFrame:UnregisterEvent("UNIT_LEVEL")
	TargetFrame:UnregisterEvent("UNIT_FACTION")
	TargetFrame:UnregisterEvent("UNIT_CLASSIFICATION_CHANGED")
	TargetFrame:UnregisterEvent("UNIT_AURA")
	TargetFrame:UnregisterEvent("PLAYER_FLAGS_CHANGED")
	TargetFrame:UnregisterEvent("PARTY_MEMBERS_CHANGED")
	TargetFrame:Hide()
	
	ComboFrame:UnregisterEvent("PLAYER_TARGET_CHANGED")
	ComboFrame:UnregisterEvent("PLAYER_COMBO_POINTS")
end

function aUF:ShowBlizzTarget()
	TargetFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
	TargetFrame:RegisterEvent("UNIT_HEALTH")
	TargetFrame:RegisterEvent("UNIT_LEVEL")
	TargetFrame:RegisterEvent("UNIT_FACTION")
	TargetFrame:RegisterEvent("UNIT_CLASSIFICATION_CHANGED")
	TargetFrame:RegisterEvent("UNIT_AURA")
	TargetFrame:RegisterEvent("PLAYER_FLAGS_CHANGED")
	TargetFrame:RegisterEvent("PARTY_MEMBERS_CHANGED")
	TargetFrame:Show()
	
	ComboFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
	ComboFrame:RegisterEvent("PLAYER_COMBO_POINTS")
end


function aUF:tonum(val, base)
	return tonumber((val or 0), base) or 0
end

function aUF:round(num)
	return floor(aUF:tonum(num)+.5)
end
