local MAX_BUFFS = 6
local L = AceLibrary("AceLocale-2.2"):new("GridBuffIcons2")
local SML = AceLibrary:HasInstance("SharedMedia-1.0") and AceLibrary("SharedMedia-1.0") or nil
local AceOO = AceLibrary("AceOO-2.0")
local RL = AceLibrary("Roster-2.1")

local petbars = false

GridBuffIcon2Status = GridStatus:NewModule("GridBuffIcon2Status")

GridBuffIcon2Status.menuName = L["Buff Icons2"]

GridBuffIcon2Status.defaultDB = {
	debug = false,
	iconsize = 8,
	offsetx = 9,
	offsety = 0,
	alpha = 0.8,
	iconnum = 3,
	iconperrow = 0,
	showbuff = true, 
	bufffilter = true,
	orientation = "VERTICAL",
	anchor = "TOPLEFT",
	color = { r = 0, g = 0.5, b = 1.0, a = 1.0 },
	ecolor = { r = 1, g = 1, b = 0, a = 1.0 },
	rcolor = { r = 1, g = 0, b = 0, a = 1.0 },
	unit_buff_icons2 = {
		color = { r=1, g=1, b=1, a=1 },
		text = "BuffIcons2",
		enable = false,
		priority = 30,
		range = false
	} 
}

GridBuffIcon2Status.options = false

local buff_icons_options = {
	["Show Buff Not Debuff"] = {
		order = 50,
		type = "toggle",
		name = L["Show Buff instead of Debuff"],
		desc = L["If selected, the icons will present unit buffs instead of debuffs."],
		get = function()
			return GridBuffIcon2Status.db.profile.showbuff;
		end,
		set = function(v)
			GridBuffIcon2Status.db.profile.showbuff = v;
			GridBuffIcon2Status:UpdateAllUnitsBuffs();
		end,
	},
	["Buff Filter"] = {
		order = 50,
		type = "toggle",
		name = L["Only castable/removable"],
		desc = L["If selected, only shows the buffs you can cast or the debuffs you can remove."],
		get = function()
			return GridBuffIcon2Status.db.profile.bufffilter;
		end,
		set = function(v)
			GridBuffIcon2Status.db.profile.bufffilter = v;
			GridBuffIcon2Status:UpdateAllUnitsBuffs();
		end,
	},
	["Icons size"] = {
		order = 55,
		type = "range",
		name = L["Icons Size"],
		desc = L["Size for each buff icon"],
		max = 16,
		min = 5,
		step = 1,
		get = function () return GridBuffIcon2Status.db.profile.iconsize end,
		set = function(v)
			GridBuffIcon2Status.db.profile.iconsize = v;
			GridFrame:WithAllFrames(function (f) f:SetIconSize(v) end)
		end
	},
	["Offset X"] = {
		order = 60,
		type = "range",
		name = L["Offset X"],
		desc = L["X-axis offset from the selected anchor point, minus value to move inside."],
		max = 20,
		min = -20,
		step = 1,
		get = function () return GridBuffIcon2Status.db.profile.offsetx end,
		set = function(v)
			GridBuffIcon2Status.db.profile.offsetx = v;
			GridFrame:WithAllFrames(function (f) f:ReSetPosition() end)
		end
	},
	["Offset Y"] = {
		order = 65,
		type = "range",
		name = L["Offset Y"],
		desc = L["Y-axis offset from the selected anchor point, minus value to move inside."],
		max = 20,
		min = -20,
		step = 1,
		get = function () return GridBuffIcon2Status.db.profile.offsety end,
		set = function(v)
			GridBuffIcon2Status.db.profile.offsety = v;
			GridFrame:WithAllFrames(function (f) f:ReSetPosition() end)
		end
	},
	["Alpha"] = {
		order = 70,
		type = "range",
		name = L["Alpha"],
		desc = L["Alpha value for each buff icon"],
		max = 1,
		min = 0.1,
		step = 0.1,
		get = function () return GridBuffIcon2Status.db.profile.alpha end,
		set = function(v)
			GridBuffIcon2Status.db.profile.alpha = v;
			GridFrame:WithAllFrames(function (f) f:ReSetAlpha() end)
		end
	},
	["Icon Numbers"] = {
		order = 75,
		type = "range",
		name = L["Icon Numbers"],
		desc = L["Max icons to show."],
		max = MAX_BUFFS,
		min = 1,
		step = 1,
		get = function()
			return GridBuffIcon2Status.db.profile.iconnum;
		end,
		set = function(v)
			GridBuffIcon2Status.db.profile.iconnum = v;
			GridBuffIcon2Status:UpdateAllUnitsBuffs();
		end,
	},
	["Icons Per Row"] = {
		order = 75,
		type = "range",
		name = L["Icons Per Row"],
		desc = L["Sperate icons in several rows."],
		max = MAX_BUFFS,
		min = 0,
		step = 1,
		get = function()
			return GridBuffIcon2Status.db.profile.iconperrow;
		end,
		set = function(v)
			GridBuffIcon2Status.db.profile.iconperrow = v;
			GridFrame:WithAllFrames(function (f) f:ReSetPosition() end);
		end,
	},
	["orientation"] = {
		order = 80;
		type = "text",
		name = L["Orientation of Icon"],
		desc = L["Set icons list orientation."],
		get = function ()
			      return GridBuffIcon2Status.db.profile.orientation
			end,
		set = function (v)
			      GridBuffIcon2Status.db.profile.orientation = v
			      GridFrame:WithAllFrames(function (f) f:ReSetPosition() end)
			end,
		validate={["HORIZONTAL"] = L["HORIZONTAL"], ["VERTICAL"] = L["VERTICAL"]}
	},
	["anchor"] = {
		order = 80;
		type = "text",
		name = L["Anchor Point"],
		desc = L["Anchor point of the first icon."],
		get = function ()
			      return GridBuffIcon2Status.db.profile.anchor
			end,
		set = function (v)
			      GridBuffIcon2Status.db.profile.anchor = v
			      GridFrame:WithAllFrames(function (f) f:ReSetPosition() end)
			end,
		validate={["TOPRIGHT"] = L["TOPRIGHT"], ["TOPLEFT"] = L["TOPLEFT"], ["BOTTOMLEFT"] = L["BOTTOMLEFT"], ["BOTTOMRIGHT"] = L["BOTTOMRIGHT"]}
	},
}
--local statusmap = GridFrame.db.profile.statusmap
local statusmap = GridFrame.defaultDB.statusmap
if not statusmap["bufficons2"] then 
	statusmap["bufficons2"] = {
		unit_buff_icons2 = true,
	}
end

if(GridFrame and GridFrame.db and GridFrame.db.profile) then
	statusmap = GridFrame.db.profile.statusmap
	if ( not statusmap["bufficons2"] ) then
		statusmap["bufficons2"] = {
			unit_buff_icons2 = true,
		}
	end
end

-- hooking stuff, taken from GridSideIndicators
local GridFrameClass = AceOO.Class(GridFrame.frameClass)

local _frameClass = nil
if ( not _frameClass ) then
	_frameClass = GridFrame.frameClass
	GridFrame.frameClass = GridFrameClass
end

function GridFrameClass.prototype:SetIndicator(indicator, color, text, value, maxValue, texture)
	if indicator == "bufficons2" then
		if not self.frame[indicator] then
			self:CreateIndicator(indicator)
		end
	end
	GridFrameClass.super.prototype.SetIndicator(self,indicator, color, text, value, maxValue, texture)
end

function GridFrameClass.prototype:CreateIndicator(indicator)
	GridFrameClass.super.prototype.CreateIndicator(self, indicator)
	if indicator == "bufficons2" then
		local f = self.frame
		local texture = SML and SML:Fetch("statusbar", GridFrame.db.profile.texture) or "Interface\\Addons\\Grid\\gradient32x32"
		local side = GridBuffIcon2Status.db.profile.side

		f.BuffIcons2 = {};
		for i=1, MAX_BUFFS do
			f.BuffIcons2[i] = f.Bar:CreateTexture("BuffIcon2"..i, "OVERLAY");
			f.BuffIcons2[i]:SetTexCoord(0.05, 0.95, 0.05, 0.95)
			f.BuffIcons2[i]:SetTexture(1,1,1,0)
		end

		self:SetIconSize(nil);
		self:ReSetPosition();
		self:ReSetAlpha();

	end
end

function GridFrameClass.prototype:SetIconSize(size)
	GridFrameClass.super.prototype.SetIconSize(self, GridFrame.db.profile.iconSize)
	local f = self.frame;
	if(f.BuffIcons2) then
		for _,v in pairs(f.BuffIcons2) do
			v:SetWidth(GridBuffIcon2Status.db.profile.iconsize);
			v:SetHeight(GridBuffIcon2Status.db.profile.iconsize);
		end
	end
end

function GridFrameClass.prototype:ReSetPosition()
	if(GridFrameClass.super.prototype.ReSetPosition) then GridFrameClass.super.prototype.ReSetPosition(self); end;
	local f = self.frame;
	local xadjust = 1;
	local yadjust = 1;
	local p = GridBuffIcon2Status.db.profile;
	if(string.find(p.anchor, "BOTTOM")) then yadjust = -1; end;
	if(string.find(p.anchor, "LEFT")) then xadjust = -1; end;
	if(f.BuffIcons2) then
		for k,v in pairs(f.BuffIcons2) do
			v:ClearAllPoints();
			if(k==1) then
				v:SetPoint(p.anchor, f, p.anchor, xadjust * p.offsetx, yadjust * p.offsety)
			elseif(p.iconperrow and p.iconperrow>0 and (k-1)%p.iconperrow==0) then
				if(p.orientation == "VERTICAL") then
					if(string.find(p.anchor, "RIGHT")) then
						if(p.offsetx<=0) then
							v:SetPoint("RIGHT", f.BuffIcons2[k-p.iconperrow], "LEFT", 0, 0);
						else
							v:SetPoint("LEFT", f.BuffIcons2[k-p.iconperrow], "RIGHT", 0, 0);
						end
					elseif(string.find(p.anchor, "LEFT")) then
						if(p.offsetx<=0) then
							v:SetPoint("LEFT", f.BuffIcons2[k-p.iconperrow], "RIGHT", 0, 0);
						else
							v:SetPoint("RIGHT", f.BuffIcons2[k-p.iconperrow], "LEFT", 0, 0);
						end
					end
				else
					if(string.find(p.anchor, "TOP")) then
						if(p.offsety<=0) then
							v:SetPoint("TOP", f.BuffIcons2[k-p.iconperrow], "BOTTOM", 0, 0);
						else
							v:SetPoint("BOTTOM", f.BuffIcons2[k-p.iconperrow], "TOP", 0, 0);
						end
					elseif(string.find(p.anchor, "BOTTOM")) then
						if(p.offsety<=0) then
							v:SetPoint("BOTTOM", f.BuffIcons2[k-p.iconperrow], "TOP", 0, 0);
						else
							v:SetPoint("TOP", f.BuffIcons2[k-p.iconperrow], "BOTTOM", 0, 0);
						end
					end
				end
			else
				if(p.orientation == "VERTICAL") then
					if(string.find(p.anchor, "BOTTOM")) then
						v:SetPoint("BOTTOM", f.BuffIcons2[k-1], "TOP", 0, 0);
					else
						v:SetPoint("TOP", f.BuffIcons2[k-1], "BOTTOM", 0, 0);
					end
				else
					if(string.find(p.anchor, "LEFT")) then
						v:SetPoint("LEFT", f.BuffIcons2[k-1], "RIGHT", 0, 0);
					else
						v:SetPoint("RIGHT", f.BuffIcons2[k-1], "LEFT", 0, 0);
					end
				end
			end
		end
	end
end

function GridFrameClass.prototype:ReSetAlpha()
	if(GridFrameClass.super.prototype.ReSetAlpha) then GridFrameClass.super.prototype.ReSetAlpha(self); end;
	local f = self.frame;
	if(f.BuffIcons2) then
		for k,v in pairs(f.BuffIcons2) do
			v:SetAlpha( GridBuffIcon2Status.db.profile.alpha );
		end
	end
end

function GridBuffIcon2Status:OnInitialize()
	self.super.OnInitialize(self)
	self:RegisterStatus('unit_buff_icons2',L["Buff Icons2"], buff_icons_options, true)

	--hook the enable option
	GridStatus.options.args["unit_buff_icons2"].args["enable"].set = function (value)
		GridBuffIcon2Status.db.profile["unit_buff_icons2"].enable = value;
		if(value)then
			GridBuffIcon2Status:UpdateAllUnitsBuffs();
		else
			for k,v in pairs(GridFrame.registeredFrames) do
				if(v.frame.BuffIcons2) then
					for i=1, MAX_BUFFS do v.frame.BuffIcons2[i]:SetTexture(nil); end
				end
			end
		end
	end;
end

function GridBuffIcon2Status:OnEnable()

	self:RegisterEvent("UNIT_AURA")
	self:RegisterEvent("Grid_UnitJoined")
	self:RegisterEvent("PARTY_MEMBERS_CHANGED")

	self:UpdateAllUnitsBuffs();
end

function GridBuffIcon2Status:UNIT_AURA(unitid)
	if(not GridBuffIcon2Status.db.profile["unit_buff_icons2"].enable) then return; end;
	local u = RL:GetUnitObjectFromUnit(unitid);
	if(not u or string.find(unitid, "pet")) then return; end;
	--self.core:SendStatusGained(u.name, "unit_buff_icons2", 99, nil,nil,nil,cur,max,nil)
	for k,v in pairs(GridFrame.registeredFrames) do
		if v.unitName == u.name then
			for i=1, MAX_BUFFS do
				if(not v.frame.BuffIcons2) then
					v:CreateIndicator("bufficons2");
				end
				v.frame.BuffIcons2[i]:SetTexture(nil);
				if(GridBuffIcon2Status.db.profile.iconnum >= i) then
					local name, rank, iconTexture, count, duration, timeLeft;
					if GridBuffIcon2Status.db.profile.showbuff then 
						name, rank, iconTexture, count, duration, timeLeft = UnitBuff(unitid, i, GridBuffIcon2Status.db.profile.bufffilter);
					else
						name, rank, iconTexture, count, duration, timeLeft = UnitDebuff(unitid,i, GridBuffIcon2Status.db.profile.bufffilter);
					end
					if(name) then
						v.frame.BuffIcons2[i]:SetTexture(iconTexture);
					end
				end
			end
		end
	end
end

function GridBuffIcon2Status:Grid_UnitJoined(name,unitid)
	for k,v in pairs(GridFrame.registeredFrames) do
		if v.unitName == name then
			v.unitid = unitid
			self:UNIT_AURA(unitid)
		end
	end
end

function GridBuffIcon2Status:PARTY_MEMBERS_CHANGED()
	self:UpdateAllUnitsBuffs();
end

function GridBuffIcon2Status:UpdateAllUnitsBuffs()
	for u in RL:IterateRoster() do
		self:UNIT_AURA(u.unitid);
	end
	self:UNIT_AURA("player");
end

function GridBuffIcon2Status:UpdateAllUnitsBuffs()
	for u in RL:IterateRoster() do
		self:UNIT_AURA(u.unitid);
	end
	self:UNIT_AURA("player");
end