
local function UnitBuffByID(unit,buffID)
	local name, spellId, _
	for i = 1,40 do
		name, _, _, _, _, _, _, _, _, _, spellId = UnitBuff(unit, i) 
		if not name then
			return
		end
		if name and tonumber(spellId) == tonumber(buffID) then
			return UnitBuff(unit, i) 
		end
	end
end

local function GetRangeToRaidMember(unit)
	if not WorldMapFrame:IsVisible() then
		SetMapToCurrentZone() 
		local _, zx1, zy1, zx2, zy2 = GetCurrentMapZone();
		local rx, ry = GetPlayerMapPosition(unit);
		local playerX, playerY = GetPlayerMapPosition("player");
		if (rx == 0 and ry == 0) or (playerX == 0 and playerY == 0) or not ( zx1 and zx2 and zy1 and zy2) then
			return 100000
		end
		local dx,dy = math.abs(playerX - rx) * (zx1 - zx2), math.abs(playerY - ry) * (zy1 - zy2)
		return math.sqrt(dx*dx + dy*dy)
	end
	return 999
end

WhatsNext:AddConditionalStatement("Player Need Buff From Player",{
	category = "Buff",
	test = function(checkTable) 
		for i=1,40 do
			local name, _, _, count, _, _, expirationTime, unit = UnitBuff(tostring(checkTable.unit1),i) 
			if checkTable.buffName == name and unit and UnitIsUnit(unit,tostring(checkTable.unit2)) then
				return math.max(count,1) < tonumber(checkTable.count or 1) or expirationTime - tonumber(checkTable.time) < GetTime()
			end			
		end
		return true
	end,
	text = function(checkTable) 
		return tostring(checkTable.unit1) .. " does not have " .. tostring(checkTable.count or 1) .. " stack(s) of " .. tostring(checkTable.buffName) .. " from " .. tostring(checkTable.unit2) .. " or they will drop off within " .. tostring(checkTable.time) .. " seconds." 
	end,
	arguments = {
		unit1 = {type = "dropdown", default = "target", possibleValues = WhatsNext.valueLists.unitAny},
		unit2 = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		buffName = {type = "text", default = ""},
		time = {type = "integer", default = 3},
		count = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Player Need Buff",{
	category = "Buff",
	test = function(checkTable) 
		for i=1,40 do
			local name, _, _, count, _, _, expirationTime = UnitBuff(tostring(checkTable.unit),i) 
			if checkTable.buffName == name then
				return math.max(count,1) < tonumber(checkTable.count or 1) or expirationTime - tonumber(checkTable.time) < GetTime()
			end			
		end
		return true
	end,
	text = function(checkTable) 
		return tostring(checkTable.unit) .. " does not have " .. tostring(checkTable.count or 1) .. " stack(s) of " .. tostring(checkTable.buffName) .. " or they will drop off within " .. tostring(checkTable.time) .. " seconds." 
	end,
	arguments = {
		unit = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		buffName = {type = "text", default = ""},
		time = {type = "integer", default = 3},
		count = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Player Buffed",{
	category = "Buff",
	test = function(checkTable) 
		local name, _, _, count, _, _, _, unit = UnitBuff(tostring(checkTable.unit), checkTable.buffName) 
		return name and math.max(count,1) >=  tonumber(checkTable.count or 1) 
	end,
	text = function(checkTable) 
		return tostring(checkTable.unit) .. " has " .. tostring(checkTable.count or 1) .. " stack(s) of the " .. tostring(checkTable.buffName) .. " buff."
	end,
	arguments = {
		unit = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		buffName = {type = "spell", default = ""},
		count = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Player Buffed By Player",{
	category = "Buff",
	test = function(checkTable) 
		local name, _, _, count, _, _, _, unit = UnitBuff(tostring(checkTable.unit1), checkTable.buffName) 
		return name and unit and UnitIsUnit(unit,tostring(checkTable.unit2)) and math.max(count,1) >=  tonumber(checkTable.count or 1) 
	end,
	text = function(checkTable) 
		return tostring(checkTable.unit1) .. " has " .. tostring(checkTable.count or 1) .. " stack(s) of the " .. tostring(checkTable.buffName) .. " buff from " .. tostring(checkTable.unit2) .. "."
	end,
	arguments = {
		unit1 = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		unit2 = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		buffName = {type = "text", default = ""},
		count = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Target Has Debuff",{
	category = "Debuff",
	test = function(checkTable)
		local name, _, _, count, _, _, _  = UnitDebuff(tostring(checkTable.unit), checkTable.debuffName)
		return UnitName(tostring(checkTable.unit)) and name and math.max(count,1) >= tonumber(checkTable.count or 1)
	end,
	text = function(checkTable)
		return tostring(checkTable.unit) .. " has " .. tostring(checkTable.count  or 1) .. " stack(s) of the " .. tostring(checkTable.debuffName) .. " debuff."
	end,
	arguments = {
		unit = {type = "dropdown", default = "target", possibleValues = WhatsNext.valueLists.unitAny},
		debuffName = {type = "text", default = ""},
		count = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Target Need Debuff",{
	category = "Debuff",
	test = function(checkTable) 
		local name, _, _, count, _, _, expirationTime  = UnitDebuff(tostring(checkTable.unit), checkTable.debuffName)
		return UnitName(tostring(checkTable.unit)) and (not name or (math.max(count,1) < tonumber(checkTable.count or 1)) or expirationTime - tonumber(checkTable.time or EARLY_CAST_EXPIRE_MARGIN) < GetTime())
	end,
	text = function(checkTable) 
		return tostring(checkTable.unit) .. " does not have " .. tostring(checkTable.count or 1) .. " stack(s) of " .. tostring(checkTable.debuffName) .. " or it will drop off within " .. tostring(checkTable.time or EARLY_CAST_EXPIRE_MARGIN) .. " seconds." 
	end,
	arguments = {
		unit = {type = "dropdown", default = "target", possibleValues = WhatsNext.valueLists.unitAny},
		debuffName = {type = "text", default = ""},
		time = {type = "integer", default = 3},
		count = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Target Has Debuff From Player",{
	category = "Debuff",
	test = function(checkTable)
		for i=1,40 do
			local name, _, _, count, _, _, _, unit  = UnitDebuff(tostring(checkTable.unit1), i)
			if checkTable.debuffName == name and unit and UnitIsUnit(unit,tostring(checkTable.unit2)) then
				return math.max(count,1) >= tonumber(checkTable.count or 1)
			end			
		end
	end,
	text = function(checkTable)
		return tostring(checkTable.unit1) .. " has " .. tostring(checkTable.count  or 1) .. " stack(s) of the " .. tostring(checkTable.debuffName) .. " debuff from " .. tostring(checkTable.unit2) .. "."
	end,
	arguments = {
		unit1 = {type = "dropdown", default = "target", possibleValues = WhatsNext.valueLists.unitAny},
		unit2 = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		debuffName = {type = "text", default = ""},
		count = {type = "integer", default = 1}
	}
})


WhatsNext:AddConditionalStatement("Target Need Debuff From Player",{
	category = "Debuff",
	test = function(checkTable) 
		for i=1,40 do
			local name, _, _, count, _, _, expirationTime, unit  = UnitDebuff(tostring(checkTable.unit1), i)
			if name and checkTable.debuffName == name and unit and UnitIsUnit(unit,tostring(checkTable.unit2)) then
				return math.max(count,1) < tonumber(checkTable.count or 1) or expirationTime - tonumber(checkTable.time) < GetTime()
			end			
		end
		return true
	end,
	text = function(checkTable) 
		return tostring(checkTable.unit1) .. " does not have " .. tostring(checkTable.count or 1) .. " stack(s) of " .. tostring(checkTable.debuffName) .. " from " .. tostring(checkTable.unit2) .. " or they will drop off within " .. tostring(checkTable.time) .. " seconds." 
	end,
	arguments = {
		unit1 = {type = "dropdown", default = "target", possibleValues = WhatsNext.valueLists.unitAny},
		unit2 = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		debuffName = {type = "text", default = ""},
		time = {type = "integer", default = 3},
		count = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Raid Buffed",{
	category = "Buff",
	test = function(checkTable) 
		if not UnitBuff("player", checkTable.buffName) then
			return false
		end
		for i = 1,40 do
			local raidUnit = "raid"..i
			if UnitExists(raidUnit) and GetRangeToRaidMember(i) <= tonumber(checkTable.yards) and not UnitBuff(raidUnit, checkTable.buffName) then
				return false
			end				
		end
		return true
	end,
	text = function(checkTable) 
		return "all raid members in " .. tostring(checkTable.yards) .. " yards have the " .. tostring(checkTable.buffName) .. " buff."
	end,
	arguments = {
		buffName = {type = "text", default = ""},
		yards = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Raid Buffed By Player",{
	category = "Buff",
	test = function(checkTable)
		local name, _, _, _, _, _, _, unit = UnitBuff("player", checkTable.buffName) 
		if not name or not unit or not UnitIsUnit(unit,tostring(checkTable.unit)) then
			return false
		end	
		for i = 1,40 do
			local raidUnit = "raid"..i
			if UnitExists(raidUnit) then
				local name, _, _, _, _, _, _, unit = UnitBuff(raidUnit, checkTable.buffName) 
				if GetRangeToRaidMember(raidUnit) <= tonumber(checkTable.yards) and (not name or not unit or not UnitIsUnit(unit,tostring(checkTable.unit))) then
					return false
				end				
			end
		end
		return true
	end,
	text = function(checkTable) 
		return "all raid members in " .. tostring(checkTable.yards) .. " yards have the " .. tostring(checkTable.buffName) .. " buff from " .. tostring(checkTable.unit) .. "."
	end,
	arguments = {
		unit = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		buffName = {type = "text", default = ""},
		yards = {type = "integer", default = 1}
	}
})








WhatsNext:AddConditionalStatement("Raid Debuffed",{
	category = "Debuff",
	test = function(checkTable) 
		if not UnitDebuff("player", checkTable.debuffName) then
			return false
		end
		for i = 1,40 do
			local raidUnit = "raid"..i
			if UnitExists(raidUnit) and GetRangeToRaidMember(i) <= tonumber(checkTable.yards) and not UnitDebuff(raidUnit, checkTable.debuffName) then
				return false
			end				
		end
		return true
	end,
	text = function(checkTable) 
		return "all raid members in " .. tostring(checkTable.yards) .. " yards have the " .. tostring(checkTable.debuffName) .. " debuff."
	end,
	arguments = {
		debuffName = {type = "text", default = ""},
		yards = {type = "integer", default = 1}
	}
})

WhatsNext:AddConditionalStatement("Raid Debuffed By Player",{
	category = "Debuff",
	test = function(checkTable)
		local name, _, _, _, _, _, _, unit = UnitDebuff("player", checkTable.debuffName) 
		if not name or not unit or not UnitIsUnit(unit,tostring(checkTable.unit)) then
			return false
		end	
		for i = 1,40 do
			local raidUnit = "raid"..i
			if UnitExists(raidUnit) then
				local name, _, _, _, _, _, _, unit = UnitDebuff(raidUnit, checkTable.debuffName) 
				if GetRangeToRaidMember(raidUnit) <= tonumber(checkTable.yards) and (not name or not unit or not UnitIsUnit(unit,tostring(checkTable.unit))) then
					return false
				end				
			end
		end
		return true
	end,
	text = function(checkTable) 
		return "all raid members in " .. tostring(checkTable.yards) .. " yards have the " .. tostring(checkTable.debuffName) .. " debuff from " .. tostring(checkTable.unit) .. "."
	end,
	arguments = {
		unit = {type = "dropdown", default = "player", possibleValues = WhatsNext.valueLists.unitAny},
		debuffName = {type = "text", default = ""},
		yards = {type = "integer", default = 1}
	}
})