

if (not Nurfed_Hud) then

	local unitlib = Nurfed_Units:New();
	local layoutlib = Nurfed_HudLayout;
	local utility = Nurfed_Utility:New();

	Nurfed_Hud = {};

	Nurfed_Hud.player = UnitName("player").." - "..GetRealmName();

	Nurfed_Hud.Default = {
		["incombat"] = 1,
		["alpha"] = 0.35,
		["bgalpha"] = 0.3,
		["debuffalpha"] = 0.75,
		["casting"] = 1,
		["blizzcasting"] = 0,
		["comboimg"] = 1,
		["combotxt"] = 0,
		["playerdebuffs"] = 1,
		["targetdebuffs"] = 1,
		["playerdebuffcount"] = 8,
		["targetdebuffcount"] = 8,
		["playerhptext"] = 1,
		["playermptext"] = 1,
		["targethptext"] = 1,
		["targetmptext"] = 1,
		["pethptext"] = 1,
		["petmptext"] = 1,
		["playerhpformat"] = "$p $c | $m",
		["playermpformat"] = "$c | $m",
		["targethpformat"] = "$p $c | $m",
		["targetmpformat"] = "$c | $m",
		["pethpformat"] = "$p $c | $m",
		["petmpformat"] = "$c | $m",
	};

	Nurfed_Hud.CastingEvents = {
		"SPELLCAST_START",
		"SPELLCAST_STOP",
		"SPELLCAST_FAILED",
		"SPELLCAST_INTERRUPTED",
		"SPELLCAST_DELAYED",
		"SPELLCAST_CHANNEL_START",
		"SPELLCAST_CHANNEL_UPDATE",
	};

	function Nurfed_Hud:New()
		local object = {};
		setmetatable(object, self);
		self.__index = self;
		return object;
	end

	function Nurfed_Hud:GetOption(option)
		if (NURFED_SAVED_HUD[self.player][option]) then
			return NURFED_SAVED_HUD[self.player][option];
		end
		return nil;
	end

	function Nurfed_Hud:SetOption(option, value)
		NURFED_SAVED_HUD[self.player][option] = value;
	end

	function Nurfed_Hud:Init()
		if (self:GetOption("layout") ~= layoutlib.Name) then
			local saved = NURFED_SAVED_HUD[self.player];
			saved["layout"] = layoutlib.Name;
			for k, v in layoutlib.Layout do
				saved[k] = {};
				saved[k] = utility:TableCopy(v);
			end
		end
		DEFAULT_CHAT_FRAME:AddMessage("|cff00ffffNurfed Hud -|r |cffffff00Layout:|r "..layoutlib.Name.." |cffffff00Author:|r "..layoutlib.Author);
		self:InitCastBar("casting");
		self:InitCastBar("blizzcasting");
		self:UpdateLayout();
	end

	function Nurfed_Hud:InitCastBar(option)
		if (option == "casting") then
			this = Nurfed_Hud_Casting;
			this.casting = nil;
			this.holdTime = 0;
		else
			this = CastingBarFrame;
		end

		if (self:GetOption(option) == 1) then
			for k, v in self.CastingEvents do
				this:RegisterEvent(v);
			end
			if (option == "casting") then
				this:SetScript("OnEvent", Nurfed_Hud_CastingOnEvent);
				this:SetScript("OnUpdate", Nurfed_Hud_CastingOnUpdate);
			end
		else
			for k, v in self.CastingEvents do
				this:UnregisterEvent(v);
			end
			this:Hide();
			if (option == "casting") then
				this:SetScript("OnEvent", nil);
				this:SetScript("OnUpdate", nil);
				Nurfed_Hud_CastingTimeText:Hide();
				Nurfed_Hud_CastingNameText:Hide();
			end
		end
	end

	function Nurfed_Hud:UpdateLayout()
		local frame, texture, bg, anchor;
		local saved = NURFED_SAVED_HUD[self.player];
		for k, v in saved do
			frame = getglobal(k);
			texture = getglobal(k.."Texture");
			bg = getglobal(k.."BG");
			if (frame) then
				if (saved[k].height) then
					frame:SetHeight(saved[k].height);
					frame:SetWidth(saved[k].width);
				end
				if (saved[k].relative) then
					anchor = string.upper(saved[k].relative);
				else
					anchor = "CENTER";
				end
				frame:ClearAllPoints();
				frame:SetPoint(anchor,"UIParent",anchor, saved[k].x, saved[k].y);
				if (texture and saved[k].texture) then
					texture:SetTexture("Interface\\AddOns\\Nurfed_Hud\\images\\"..saved[k].texture);
					texture:SetHeight(saved[k].height);
					texture:SetWidth(saved[k].width);
					bg:SetTexture("Interface\\AddOns\\Nurfed_Hud\\images\\"..saved[k].texture);

					if (saved[k].fill) then
						texture:ClearAllPoints();
						if (saved[k].fill == "top" or saved[k].fill == "left") then
							texture:SetPoint("BOTTOMRIGHT", frame,"BOTTOMRIGHT", 0, 0);
						elseif (saved[k].fill == "bottom" or saved[k].fill == "right") then
							texture:SetPoint("TOPLEFT", frame,"TOPLEFT", 0, 0);
						else
							texture:SetPoint("RIGHT", frame,"RIGHT", 0, 0);
						end
					end
				end
			end
		end
		Nurfed_Hud_CPTextText:SetFont("Fonts\\FRIZQT__.TTF", 40, "NORMAL");
		self:UpdateBG();
	end

	function Nurfed_Hud:UpdateBG()
		local alpha = self:GetOption("bgalpha");
		Nurfed_Hud_playerHPBG:SetVertexColor(0, 0, 0, alpha);
		Nurfed_Hud_playerMPBG:SetVertexColor(0, 0, 0, alpha);
		Nurfed_Hud_targetHPBG:SetVertexColor(0, 0, 0, alpha);
		Nurfed_Hud_targetMPBG:SetVertexColor(0, 0, 0, alpha);
		Nurfed_Hud_petHPBG:SetVertexColor(0, 0, 0, alpha);
		Nurfed_Hud_petMPBG:SetVertexColor(0, 0, 0, alpha);
		Nurfed_Hud_CastingBG:SetVertexColor(0, 0, 0, alpha);
	end

	function Nurfed_Hud:UpdateHud()
		self:UpdateHealth("player");
		self:UpdateMana("player");
		self:UpdateManaColor("player");
		self:UpdateAuras("player");
		self:UpdateTarget();
		self:UpdatePet();
		self:UpdateCombo();
	end

	function Nurfed_Hud:UpdatePet()
		self:UpdateHealth("pet");
		self:UpdateMana("pet");
		self:UpdateManaColor("pet");
	end

	function Nurfed_Hud:UpdateTarget()
		self:UpdateHealth("target");
		self:UpdateMana("target");
		self:UpdateManaColor("target");
		self:UpdateAuras("target");
	end

	function Nurfed_Hud:UpdateCombo()
		if (self.Shown) then
			return;
		end
		local i, button;
		local points = GetComboPoints();
		for i = 1, 5 do
			button = getglobal("Nurfed_Hud_CP_"..i);
			if (i <= points and self:GetOption("comboimg") == 1) then
				button:Show();
			else
				button:Hide();
			end
		end

		if (points > 0 and self:GetOption("combotxt") == 1) then
			Nurfed_Hud_CPTextText:SetText(points);
			Nurfed_Hud_CPTextText:SetTextColor(0.2 * points, 0, 0);
		else
			Nurfed_Hud_CPTextText:SetText(nil);
		end
	end

	function Nurfed_Hud:UpdateAuras(unit)
		if (self.Shown) then
			return;
		end
		local i;
		local count = self:GetOption(unit.."debuffcount");
		for i = 1, 16 do
			local debuff, debuffApplications = UnitDebuff(unit, i);
			local button = getglobal("Nurfed_Hud_"..unit.."Debuff_"..i);
			if (debuff and i <= count and self:GetOption(unit.."debuffs") == 1 and self.inCombat) then
				local texture = getglobal(button:GetName().."Texture");
				local debuffcount = getglobal(button:GetName().."Count");
				texture:SetTexture(debuff);
				if (debuffApplications > 1) then
					debuffcount:SetText(debuffApplications);
					debuffcount:Show();
				else
					debuffcount:Hide();
				end
				button:SetAlpha(self:GetOption("debuffalpha"));
				button:Show();
			else
				button:Hide();
			end
		end
	end

	function Nurfed_Hud:TextureCoord(texture, size, fill, value)
		if (fill == "top") then
			texture:SetHeight(size);
			texture:SetTexCoord(0, 1, value, 1);
		elseif (fill == "bottom") then
			texture:SetHeight(size);
			texture:SetTexCoord(0, 1, 1, value);
		elseif (fill == "left") then
			texture:SetWidth(size);
			texture:SetTexCoord(value, 1, 0, 1);
		elseif (fill == "right") then
			texture:SetWidth(size);
			texture:SetTexCoord(1, value, 0, 1);
		elseif (fill == "vertical") then
			texture:SetHeight(size);
			texture:SetTexCoord(0, 1, 0 + (value / 2), 1 - (value / 2));
		elseif (fill == "horizontal") then
			texture:SetWidth(size);
			texture:SetTexCoord(0 + (value / 2), 1 - (value / 2), 0, 1);
		end
	end

	function Nurfed_Hud:FormatText(curr, max, perc, format)
		format = string.gsub(format, "$c", curr);
		format = string.gsub(format, "$m", max);
		format = string.gsub(format, "$p", ceil(perc).."%%");
		return format;
	end

	function Nurfed_Hud:UpdateHealth(unit)
		if (self.Shown) then
			return;
		end
		local frame = getglobal("Nurfed_Hud_"..unit.."HP");
		local text = getglobal("Nurfed_Hud_"..unit.."HPText");
		if (UnitExists(unit)) then
			local info = self:GetOption(frame:GetName());
			local currhp, maxhp, perc, color = unitlib:Health(unit);
			local texture = getglobal(frame:GetName().."Texture");
			local unittext = getglobal("Nurfed_Hud_"..unit.."HPTextText");
			if (self:GetOption(unit.."hptext") == 1) then
				unittext:SetText(self:FormatText(currhp, maxhp, perc, self:GetOption(unit.."hpformat")));
				unittext:SetTextColor(color.r, color.g, color.b);
			else
				unittext:SetText(nil);
			end

			local p = currhp / maxhp;
			local size = info.bar * p;
			local p_h1, p_h2;

			if (info.fill == "top" or info.fill == "bottom" or info.fill == "vertical") then
				p_h1 = info.bar / info.height;
			else
				p_h1 = info.bar / info.width;
			end

			p_h2 = 1 - p_h1;
			self:TextureCoord(texture, size, info.fill, (1-p) * p_h1 + p_h2);
			texture:SetVertexColor(color.r, color.g, color.b);

			if((currhp == maxhp and not self.inCombat and self:GetOption("incombat") == 1) or UnitIsDead(unit)) then
				frame:Hide();
				text:Hide();
			else
				if (not self.inCombat) then
					frame:SetAlpha(self:GetOption("alpha"));
				else
					frame:SetAlpha(1);
				end
				frame:Show();
				text:Show();
			end
		else
			frame:Hide();
			text:Hide();
		end
	end

	function Nurfed_Hud:UpdateMana(unit)
		if (self.Shown) then
			return;
		end
		local frame = getglobal("Nurfed_Hud_"..unit.."MP");
		local text = getglobal("Nurfed_Hud_"..unit.."MPText");
		if (UnitExists(unit) and UnitManaMax(unit) > 0) then
			local info = self:GetOption(frame:GetName());
			local currmp, maxmp, perc = unitlib:Mana(unit);
			local texture = getglobal(frame:GetName().."Texture");
			local unittext = getglobal("Nurfed_Hud_"..unit.."MPTextText");
			if (self:GetOption(unit.."mptext") == 1) then
				unittext:SetText(self:FormatText(currmp, maxmp, perc, self:GetOption(unit.."mpformat")));
			else
				unittext:SetText(nil);
			end

			local p = currmp / maxmp;
			local size = info.bar * p;
			local p_h1, p_h2;

			if (info.fill == "top" or info.fill == "bottom" or info.fill == "vertical") then
				p_h1 = info.bar / info.height;
			else
				p_h1 = info.bar / info.width;
			end

			p_h2 = 1 - p_h1;
			if (currmp > 0) then
				self:TextureCoord(texture, size, info.fill, (1-p) * p_h1 + p_h2);
			else
				self:TextureCoord(texture, size, info.fill, 0);
			end

			if((currmp == maxmp and not self.inCombat and self:GetOption("incombat") == 1) or currmp == 0) then
				frame:Hide();
				text:Hide();
			else
				if (not self.inCombat) then
					frame:SetAlpha(self:GetOption("alpha"));
				else
					frame:SetAlpha(1);
				end
				frame:Show();
				text:Show();
			end
		else
			frame:Hide();
			text:Hide();
		end
	end

	function Nurfed_Hud:UpdateManaColor(unit)
		local color = ManaBarColor[UnitPowerType(unit)];
		local texture = getglobal("Nurfed_Hud_"..unit.."MPTexture");
		local text = getglobal("Nurfed_Hud_"..unit.."MPTextText");
		texture:SetVertexColor(color.r, color.g, color.b);
		text:SetTextColor(color.r, color.g, color.b);
	end

	function Nurfed_Hud:UpdateCasting(curr, max)
		local info = self:GetOption("Nurfed_Hud_Casting");
		local texture = getglobal("Nurfed_Hud_CastingTexture");

		local p = curr / max;
		local size = info.bar * p;
		local p_h1;
		if (info.fill == "top" or info.fill == "bottom" or info.fill == "vertical") then
			p_h1 = info.bar / info.height;
		else
			p_h1 = info.bar / info.width;
		end
		local p_h2 = 1 - p_h1;
		self:TextureCoord(texture, size, info.fill, (1-p) * p_h1 + p_h2);
	end
end