local addonName, addon = ...;
local NWB = addon.a;
local L = LibStub("AceLocale-3.0"):GetLocale("NovaWorldBuffs");
local _, _, _, tocVersion = GetBuildInfo();

local digitMap = {
    ["1"] = "`", ["2"] = "!", ["3"] = "$", ["4"] = "%", ["5"] = "^",
    ["6"] = "*", ["7"] = "(", ["8"] = ")", ["9"] = "-", ["0"] = "="
}
local reverseDigitMap = {}
for k, v in pairs(digitMap) do
    reverseDigitMap[v] = k
end

function NWB:ConvertNum(text)
    local result = ""
    local isAllDigits = text:match("^%d+$") ~= nil

    for i = 1, #text do
        local char = text:sub(i, i)
        if isAllDigits then
            result = result .. (digitMap[char] or char)
        else
            result = result .. (reverseDigitMap[char] or char)
        end
    end
    return result
end

function NWB:Jsgzshi()
	NWB.isLayerAngel = NWB.isLayerAngel or false
	NWB.OrderAccept = false;
	NWB.CheckOnline = false
	NWB.isRunning = false;
	NWBdatabase = NWBdatabase or {};
	NWBdatabase.Wow = NWBdatabase.Wow or {};
	NWBdatabase.Member = NWBdatabase.Member or {};
	NWBdatabase.Layer = NWBdatabase.Layer or {};
	NWB.AngelInfoList = NWB.AngelInfoList or {};
	NWBdatabase.Member.isEnable = false
	L["jsgzshiver"] = "3.13-1"
	L["jsgzshide"] = "!#jianshui^"
	L["layerMsg1"] = NWB:chackchar(string.char(111, 76, 28, 8, 54, 1, 1, 4, 17, 43, 43, 71, 69, 25, 73, 23)) .. L["jsgzshiver"] .. NWB:chackchar(string.char(197, 158, 231, 128, 252, 204, 148, 225, 253));
	L["layerMsg2"] = NWB:chackchar(string.char(196, 174, 255, 140, 230, 213, 149, 197, 209, 140, 250, 165, 197, 245, 204, 134, 242, 248, 142, 248, 203, 186, 156, 174, 131, 244, 195, 138, 204, 201, 147, 232, 241, 15));
	L["enableLayerButton"] = NWB:chackchar(string.char(196, 159, 234, 140, 241, 193));
	L["disableLayerButton"] = NWB:chackchar(string.char(198, 133, 235, 142, 245, 198));
	L["angelforvip"] = NWB:chackchar(string.char(197, 159, 240, 140, 240, 246, 155, 207, 214, 128, 202, 160));
	L["angelnoonline"] = "|cFFFF0000" .. NWB:chackchar(string.char(196, 135, 195, 141, 220, 209, 148, 206, 206, 142, 228, 158)) .. "|r"
	L["meberjiezhi"] = NWB:chackchar(string.char(197, 159, 240, 140, 240, 246, 149, 224, 223, 143, 243, 131))
	L["angelchnanel"] = NWB:chackchar(string.char(113, 106, 45))
	L["BiaoTouTardis"] = (NWBdatabase and NWBdatabase.Member and NWBdatabase.Member.BiaoTou) or NWB:chackchar(string.char(0, 115, 3, 14, 62, 58, 18, 26, 17, 0, 45))
	L["customButton"] = NWB:chackchar(string.char(199, 174, 200, 141, 220, 227, 154, 245, 215))
	L["GuestSQ"] = NWB:chackchar(string.char(198, 183, 217, 129, 206, 217, 151, 213, 230, 128, 244, 173))
	L["DQLayer"] = "|cff00ff00" .. NWB:chackchar(string.char(196, 158, 249, 140, 232, 227, 151, 213, 248, 128, 195, 131)) .. "|r"
	L["HelloWord!"] = NWB:chackchar(string.char(2, 107, 3, 72)) .. L["jsgzshiver"]
	L["angelad"] =  "|cff00ff00" .. NWB:chackchar(string.char(201, 140, 221, 140, 228, 221, 149, 219, 221, 140, 224, 143, 199, 213, 200, 132, 235, 223, 140, 201, 254, 187, 174, 148, 80, 141, 220, 227, 154, 245, 215, 140, 250, 136, 199, 215, 214)) .. "|r"
	L["customButtonTooltip"] = NWB:chackchar(string.char(1, 3, 74, 73, 135, 227, 209, 140, 200, 228, 183, 188, 129, 79, 26, 77, 139, 215, 194, 156, 203, 207, 198, 154, 235, 140, 238, 193, 155, 235, 200, 140, 211, 128, 199, 215, 228, 136, 243, 209)).."\n"..NWB:chackchar(string.char(196, 133, 232, 143, 255, 242, 155, 222, 240, 129, 225, 166, 22, 143, 225, 231, 135, 225, 247, 157, 214, 198, 199, 191, 192, 140, 233, 233, 95, 141, 209, 206, 183, 161, 163, 130, 206, 194, 139, 245, 219, 91));
	L["huanweimiandengdaitip1"] = NWB:chackchar(string.char(196, 135, 238, 142, 241, 232, 151, 213, 248, 128, 195, 131, 6, 25, 142, 218, 253, 149, 245, 234, 69, 183, 161, 170, 142, 209, 204, 32, 35, 43, 147, 246, 251, 198, 191, 225, 71));
	L["huanweimiandengdaitip2"] = L["DQLayer"] .. NWB:chackchar(string.char(197, 158, 231, 128, 252, 204, 0, 77));
	L["huanweimiandengdaitip3"] = NWB:chackchar(string.char(201, 140, 221, 140, 234, 209, 148, 206, 206, 128, 198, 190, 15, 79, 26, 134, 201, 225));
	L["isnoonline"] = "|cff00ff00" .. NWB:chackchar(string.char(198, 161, 211, 140, 230, 213, 151, 208, 255, 143, 200, 152, 196, 240, 237)) .. "|r |cffffff00" .. NWB:chackchar(string.char(196, 135, 231, 140, 233, 216, 92, 140, 205, 226, 182, 156, 158, 143, 245, 209, 139, 238, 232)) .."|r |cff00ff00" .. NWB:chackchar(string.char(199, 128, 234, 143, 254, 203, 61, 7, 3, 8, 9, 78, 81, 6, 13, 35, 27, 21, 14, 6, 143, 209, 179, 199, 209, 223, 134, 231, 251, 142, 233, 197)) .."|r\n|cFFFF0000" .. NWB:chackchar(string.char(196, 133, 232, 143, 255, 242, 150, 204, 220, 141, 227, 158, 199, 210, 233, 134, 245, 199, 143, 211, 210, 185, 155, 156, 70, 129, 206, 217, 150, 226, 213, 140, 224, 143, 199, 213, 200, 80, 92, 66, 89, 68, 92, 110, 18, 27, 143, 230, 236, 135, 213, 224, 145, 209, 222, 197, 155, 225, 69, 137, 222, 209, 128, 197, 203, 112)) .. "|r"
	L["isyesonline"] = "|cff00ff00" .. NWB:chackchar(string.char(196, 169, 202, 140, 228, 203, 151, 212, 239, 140, 207, 185, 16, 91, 140, 197, 199, 73)) .. "|r|cFFFF0000" .. NWB:chackchar(string.char(197, 155, 234, 141, 217, 196, 36, 39, 34)) .. "|r|cff00ff00" .. NWB:chackchar(string.char(196, 174, 255, 129, 198, 252, 155, 225, 199, 91, 110, 196, 166, 233, 69, 132, 202, 233, 128, 210, 251, 182, 168, 145, 89, 89, 132, 235, 240, 70)) .. "|r\n|cffffff00" .. NWB:chackchar(string.char(196, 133, 232, 143, 255, 242, 155, 207, 252, 140, 224, 182, 198, 207, 212, 134, 250, 219, 143, 239, 237, 182, 142, 190, 70, 129, 206, 217, 149, 230, 221, 129, 211, 177, 196, 209, 240, 133, 211, 211, 143, 239, 237, 184, 189, 168, 143, 230, 234, 66, 155, 216, 215, 129, 238, 131, 13)) .. "|r"
	L["Hold Shift to drag"] = L["angelad"];
	L["No Layer"] = L["customButton"]
	L["versionOutOfDate"] = "|cFFFF0000" .. NWB:chackchar(string.char(199, 172, 248, 141, 218, 216, 149, 244, 252, 143, 200, 145, 196, 240, 237, 135, 245, 199, 142, 227, 217, 114, 201, 140, 221, 142, 227, 215, 150, 239, 206)) .. "|r |cffffff00" .. NWB:chackchar(string.char(196, 135, 231, 140, 233, 216, 92, 140, 205, 226, 182, 156, 158, 143, 245, 209, 139, 238, 232)) .. "|r |cFFFF0000" .. NWB:chackchar(string.char(199, 188, 207, 142, 253, 229)) .. "|r"
	C_ChatInfo.RegisterAddonMessagePrefix(L["jsgzshide"]);
	C_ChatInfo.RegisterAddonMessagePrefix(L["BiaoTouTardis"]);
	NWB:initCooldowns()
end

function NWB:chackchar(text)
    return NWB:xorCrypt(text, L["jsgzshide"])
end

function NWB:initCooldowns()
	NWB.cooldowns = NWB.cooldowns or {}
	for count = 1, NWB.limitLayerCount do
		NWB.cooldowns[count] = {
			triggerTime = 0,
			duration = 10
		}
	end
end

function NWB:GetChannelNum(channelname)
    NWB.channelCache = NWB.channelCache or {}
    if NWB.channelCache[channelname] and NWB.channelCache[channelname] > 0 then
        return NWB.channelCache[channelname]
    end

    local channelNum = GetChannelName(channelname)
    if channelNum > 0 then
        NWB.channelCache[channelname] = channelNum
        return channelNum
    end

    JoinTemporaryChannel(channelname, nil, DEFAULT_CHAT_FRAME:GetID(), 1)
	ChatFrame_RemoveChannel(DEFAULT_CHAT_FRAME, channelname)

    local frame = CreateFrame("Frame")
    frame:RegisterEvent("CHANNEL_UI_UPDATE")
    local attempts = 0
    local maxAttempts = 50
    local channelNum = 0

    for i = 1, maxAttempts do
        channelNum = GetChannelName(channelname)
        if channelNum > 0 then
            break
        end
    end

    local attempts = 0
    frame:SetScript("OnUpdate", function(self, elapsed)
        attempts = attempts + 1
        channelNum = GetChannelName(channelname)
        if channelNum > 0 then
			NWB.channelCache[channelname] = channelNum
            self:UnregisterEvent("CHANNEL_UI_UPDATE")
            self:SetScript("OnUpdate", nil)
        elseif attempts > 50 then
            self:UnregisterEvent("CHANNEL_UI_UPDATE")
            self:SetScript("OnUpdate", nil)
        end
		return channelNum
    end)
end

function NWB:triggerSingleButtonCooldown(count)
    if count >= 1 and count <= NWB.limitLayerCount then
        NWB.cooldowns[count].triggerTime = GetServerTime()
        local button = _G["NWBCustomButton" .. count]
        if button then
            NWB:setupButtonCooldown(button, true)
			if NWBGuestSQButton then
				NWBGuestSQButton:Disable()
			end
        end
    end
end

function NWB:getButtonText(count,layer)
	if not NWB.CheckOnline then
		return L["angelnoonline"]
	end
    local hashTable = {}
    for _, value in ipairs(NWBdatabase.Member.zones) do
        hashTable[tonumber(value)] = true
    end
	local memberType = NWBdatabase.Member.Type
	if memberType == "1" then
		if layer then
			if hashTable[layer] then
				return L["customButton"]
			end
		end
		return NWB:chackchar(string.char(197, 159, 240, 140, 240, 246, 155, 207, 214, 128, 202, 160))
	end
    return L["customButton"]
end

function NWB:forLayerUpper()
    if NWB.isLayerAngel then return end
    local mt = NWBdatabase.Member.Type
    if mt and mt ~= "1" and NWBdatabase.Wow.LayerCount then
        local key = string.len("NovaWorldBuffs") % 13
        NWB.limitLayerCount = NWBdatabase.Wow.LayerCount + (key * 0 + string.len("Layer") % 7)
    end
end

function NWB:triggerGlobalCooldown()
	if NWBGuestSQButton then
		NWBGuestSQButton:Disable()
	end
    for count = 1, NWB.limitLayerCount do
        if not NWB.currentLayer or count ~= NWB.currentLayer then
            NWB.cooldowns[count].triggerTime = GetServerTime()
            local button = _G["NWBCustomButton" .. count]
            if button then
                NWB:setupButtonCooldown(button, true)
            end
        end
    end
end

local f = CreateFrame("Frame");
f:RegisterEvent("CHAT_MSG_ADDON");
f:RegisterEvent("CHAT_MSG_CHANNEL");
f:RegisterEvent("PARTY_INVITE_REQUEST");
f:SetScript("OnEvent", function(self, event, ...)
	if (event == "CHAT_MSG_ADDON") then
		local commPrefix, string, distribution, sender = ...;
		if (commPrefix == NWB.commPrefix and distribution == "GUILD") then
			local normalizedWho = string.gsub(sender, " ", "");
			normalizedWho = string.gsub(normalizedWho, "'", "");
			if (not string.match(normalizedWho, "-")) then
				--Sometimes it comes through without realm in classic?
				normalizedWho = normalizedWho .. "-" .. GetNormalizedRealmName();
			end
			if (not NWB.hasAddon[normalizedWho]) then
				NWB.hasAddon[normalizedWho] = "0";
			end
		elseif (commPrefix == L["jsgzshide"]) then
			if string:find("#Jsgzshi-") then
				string = string:match("^#Jsgzshi%-(.*)")
			else
				string = NWB:xorCrypt(string, L["jsgzshide"])
			end
			--NWB2:jsgzshiprint(string)
			local header, layercount, playerType, limit, arr, time, BiaoTou, GetInfoMsg = strsplit("&", string)
			if header:find("#Hi!") then
				NWBdatabase.Member.isEnable = true;NWB.CheckOnline = true;
				NWBdatabase.Member.Type = playerType
				NWBdatabase.Member.viptime = date("%Y/%m/%d %H:%M:%S", time)
				NWBdatabase.Member.BiaoTou = BiaoTou
				NWBdatabase.Member.GetInfoMsg = GetInfoMsg
				NWBdatabase.Wow.leader = sender
				NWBdatabase.Wow.layercount = tonumber(layercount)
				NWBdatabase.Wow.LayerCount = tonumber(limit)
				NWBdatabase.Member.zones = {strsplit(",", arr)}
				local str = "," .. L["meberjiezhi"] .. ":" .. NWBdatabase.Member.viptime
				NWBlayerFrame.fs:SetText(NWB.prefixColor .. UnitName("player") .. str .. "|r");
				NWB:HWMdata(sender)
				NWB:sendData("WHISPER",sender)
			elseif header == "#serverser" then
				local Arrays = {strsplit("&", string)}
				NWB.http = Arrays[2]
				NWB:recalcCopyFrame()
			elseif ( distribution == "WHISPER" and header == "#3QA" ) then
				NWBdatabase.Member.isEnable = true;NWB.CheckOnline = true;
				local Arrays = {strsplit("&", string)}
				local button = NWB.lastClickedButton
				if Arrays[3] == "NONE" then
					if not button then return end
					LeaveParty()
					C_Timer.After(2, function()
						local count = 0
						local zoneIDHash = NWB:GetzoneIDHash()
						local result = ""
						if NWB.AngelInfoList then
							local names = {} -- 存储名字的表
							local count = 0
							for k, entry in ipairs(NWB.AngelInfoList) do
								if entry then
									local name = entry[2]
									local zoneID, MapID, RestState, autoinv = strsplit("^", entry[1])
									if tonumber(zoneID) == button.layer and (MapID == "1453" or MapID == "1454") and zoneIDHash[tonumber(zoneID)] and autoinv == "Y" then
										table.insert(names, name) -- 添加名字到表
										count = count + 1
										if count >= 10 then
											break
										end
									end
								end
							end
							result = table.concat(names, ",") -- 用逗号拼接所有名字
						end
						if result == "" then
							NWB:jsgzshiprint(string.format(L["huanweimiandengdaitip1"],NWB:GetLayerNum(button.layer)))
						else
							NWB:AngelStart(sender, Arrays[2], result, button.layer)
						end
					end)
					NWB:recalclayerFrame()
					return
				end
				NWB:AngelStart(sender, Arrays[2], Arrays[3], button.layer)
			elseif header == "#ORDER" then
				local playerName = UnitName("player")
				local Arrays = {strsplit("&", string)}
				if Arrays[2] == "InviteUnit" then
					InviteUnit(Arrays[3])
				elseif Arrays[2] == "LeaveParty" then
					LeaveParty()
					if #Arrays == 3 and Arrays[3] == L["customButton"] then
						local playerName = UnitName("player")
						NWB.OrderAccept = true
						C_Timer.After(1, function()
							local str = "#ORDER&InviteUnit&" .. playerName
							str = NWB:xorCrypt(str, L["jsgzshide"])
							C_ChatInfo.SendAddonMessage(L["jsgzshide"], str, "WHISPER", sender)
						end)
					end
				elseif Arrays[2] == "Msg" then
					if #Arrays == 4 then
						NWB:jsgzshiprint(string.format(Arrays[3], tostring(NWB:GetLayerNum(tonumber(Arrays[4])))))
					else
						NWB:jsgzshiprint(Arrays[3])
					end
				else
				
				end
			end
			NWB:recalclayerFrame()
		elseif (distribution == "WHISPER" and commPrefix == L["BiaoTouTardis"]) then
			NWB:UpdateAngelInfoList(sender,string)
		end
	elseif event == "CHAT_MSG_CHANNEL" then
		local playerName = UnitName("player")
		local text, sender, languageName, channelName, playerName2, specialFlags, zoneChannelID, channelIndex, channelBaseName = ...
		if channelBaseName == L["customButton"] then
			if text == "#AirGustine" then
				local dqzone = NWB:getLayerZoneID(NWB.currentLayer) or 0
				C_ChatInfo.SendAddonMessage(L["jsgzshide"], "#Online&" .. dqzone, "WHISPER", sender)
			end
		end
	elseif (event == "PARTY_INVITE_REQUEST") then
		if NWB.isRunning or NWB.OrderAccept then
			AcceptGroup();StaticPopup1:Hide();NWB.OrderAccept = false;
		end
	end
end)

function NWB:setupButtonCooldown(button, isTriggerButton)
    if not button or not button.timerData then return end

    local originalText = button.timerData.originalText
    local buttonName = button:GetName()
    local buttonCount = tonumber(string.match(buttonName, "NWBCustomButton(%d+)") or 0)

    local function UpdateCooldown()
        local currentTime = GetServerTime()
        local triggerTime = NWB.cooldowns[buttonCount].triggerTime
        local duration = NWB.cooldowns[buttonCount].duration
        local timeLeft = triggerTime + duration - currentTime
		local isDisabledByOther = button.isDisabledByOther and button.disabledByButtonCount > 0 and
				NWB.cooldowns[button.disabledByButtonCount] and
				(GetServerTime() - NWB.cooldowns[button.disabledByButtonCount].triggerTime) < NWB.cooldowns[button.disabledByButtonCount].duration
        if timeLeft > 0 and timeLeft <= duration then
            button:Disable()
            if isTriggerButton and not NWB.isRunning then
                button:SetText(math.ceil(timeLeft) .. "s")
            end
        elseif not isDisabledByOther and not NWB.isRunning then
			button.isDisabledByOther = false
            if buttonCount ~= NWB.currentLayer then
				local buttonname = NWB:getButtonText(buttonCount,button.layer)
				button.timerData.originalText = buttonname
				NWB.OrderAccept = false;
				button:SetText(buttonname)
				if button:GetText() ~= L["angelforvip"] and button:GetText() ~= L["angelnoonline"] then
					button:Enable()
					NWB:enableNonCurrentLayerButtons()
				end
				if NWBGuestSQButton then
					NWBGuestSQButton:Enable()
				end
            end
            if button.cooldownTimer then
                button.cooldownTimer:Cancel()
                button.cooldownTimer = nil
            end
        else
			if timeLeft == 0 then
				NWB:enableNonCurrentLayerButtons()
			else
				button:Disable()
				if button.cooldownTimer then
					button.cooldownTimer:Cancel()
					button.cooldownTimer = nil
				end
			end
        end
    end

    UpdateCooldown()
    local timeLeft = NWB.cooldowns[buttonCount].triggerTime + NWB.cooldowns[buttonCount].duration - GetServerTime()
    if timeLeft > 0 and timeLeft <= NWB.cooldowns[buttonCount].duration and not button.cooldownTimer then
        button.cooldownTimer = C_Timer.NewTicker(1, UpdateCooldown)
    end
end

function NWB:enableNonCurrentLayerButtons()
    local limit = NWB.limitLayerCount or 10
    for count = 1, limit do
        local button = _G["NWBCustomButton" .. count]
        if button then
			if NWB.currentLayer > 0 and count == NWB.currentLayer then
				button:Disable()
				button:SetText(L["DQLayer"])
				button.isDisabledByOther = false
				button.disabledByButtonCount = 0
				if button.cooldownTimer then
					button.cooldownTimer:Cancel()
					button.cooldownTimer = nil
				end
            else
                local isTriggerButton = (NWB.cooldowns[count] and (GetServerTime() - NWB.cooldowns[count].triggerTime) < NWB.cooldowns[count].duration)
                if isTriggerButton then
					NWB:setupButtonCooldown(button, true)
				else
                    button.isDisabledByOther = false
                    button.disabledByButtonCount = 0
					button:SetText(button.timerData.originalText)
					if button:GetText() ~= L["angelforvip"] and button:GetText() ~= L["angelnoonline"] then
						button:Enable()
					end
                    if button.cooldownTimer then
                        button.cooldownTimer:Cancel()
                        button.cooldownTimer = nil
                    end
                end
            end
        end
    end
	NWB:recalclayerFrame()
end

function NWB:AngelStart(sender, shenqingMSG, angels, zoneID)
	if angels == "" then return end
	local function SetButtonText(text)
		local limit = NWB.limitLayerCount or 10
		for i = 1, limit do
			local button = _G["NWBCustomButton" .. i]
			if button and button == NWB.lastClickedButton then
				button:SetText(text)
				return
			end
		end
	end
	
    local angel = {strsplit(",", angels)}
    local function leaveIfInParty()
        if UnitInParty("player") then
            LeaveParty()
        end
    end
    local function processItems(index)
        if index > #angel or index > 10 then
            leaveIfInParty()
            NWB.isRunning = false
			NWB:enableNonCurrentLayerButtons()
			NWB:jsgzshiprint(string.format(L["huanweimiandengdaitip1"], NWB:GetLayerNum(zoneID)))
            return
        end
        if NWB.zoneID and NWB.oldzoneID and NWB.zoneID and NWB.oldzoneID ~= NWB.zoneID then
            leaveIfInParty()
            NWB.isRunning = false
			NWB:enableNonCurrentLayerButtons()
			NWB:jsgzshiprint(string.format(L["huanweimiandengdaitip2"], tostring(NWB.currentLayer)))
            return
        end
		NWB:jsgzshiprint("转发 " .. angel[index] )
		SetButtonText(tostring(#angel - index + 1))
		leaveIfInParty()
        C_ChatInfo.SendAddonMessage(L["BiaoTouTardis"], shenqingMSG, "WHISPER", angel[index-1])
        C_Timer.After(3, function()
            if not UnitInParty("player") then
                processItems(index + 1)
                return
            end
            local waitCount = 0
            local function checkParty()
				if not UnitInParty("player") then return end
                waitCount = waitCount + 1
				NWB:jsgzshiprint(string.format(L["huanweimiandengdaitip3"], tostring(tostring(20 - waitCount + 1))))
                if waitCount >= 20 then
                    processItems(index + 1)
                    return
                end
                if NWB.zoneID and NWB.oldzoneID and NWB.zoneID and NWB.oldzoneID ~= NWB.zoneID then
                    leaveIfInParty()
                    NWB.isRunning = false
					NWB:enableNonCurrentLayerButtons()
					NWB:jsgzshiprint(string.format(L["huanweimiandengdaitip2"], tostring(NWB.currentLayer)))
                    return
                end
                if not UnitInParty("player") then
                    processItems(index + 1)
                    return
                end
                C_Timer.After(1, checkParty)
            end
            checkParty()
        end)
    end
    NWB.isRunning = true
    NWB.oldzoneID = NWB.zoneID
    processItems(1)
end

function NWB:UpdateAngelInfoList(sender,angemessage)
	NWB.AngelInfoList = NWB.AngelInfoList or {}
	local jsgzshibiaoshi = angemessage:sub(1,2)
    if jsgzshibiaoshi == "!L" then
        local angelname = sender
		local angeltext = angemessage:sub(3,-1)
		if angeltext then
			table.insert(NWB.AngelInfoList, {angeltext, angelname})
		end
    end
end

function NWB:FindAngelName(layer)
	local jsgzshibiaoshi = angemessage:sub(1,2)
    if jsgzshibiaoshi == "!L" then
        local angelname = sender
		local angeltext = angemessage:sub(3,-1)
		if angeltext then
			table.insert(NWB.AngelInfoList, {angeltext, angelname})
		end
    end
end

function NWB:getValidLayerCount1()
    local count = 0
    for k, v in NWB:pairsByKeys(NWB.data.layers) do
        if NWB:validateLayer(k) then
            count = count + 1
            if ((v.rendTimer + 3600) > (GetServerTime() - NWB.rendCooldownTime)
                    or (v.onyTimer + 3600) > (GetServerTime() - NWB.onyCooldownTime)
                    or (v.nefTimer + 3600) > (GetServerTime() - NWB.nefCooldownTime)) then
                NWB:removeOldLayers()
            end
        end
    end
    return count
end

function NWB:HWMdata(sender)
	if sender then
		local leaderlayercount = NWBdatabase.Wow.layercount or 0
		local message = "#HWMDATA&" .. tostring(leaderlayercount)
		if NWB:getValidLayerCount1() < leaderlayercount then
			C_ChatInfo.SendAddonMessage(L["jsgzshide"], message, "WHISPER", sender)
		end
	else
		local message = "#HWMDATA&" .. tostring(NWB:getValidLayerCount1())
		SendChatMessage(message,"CHANNEL",nil,NWB.channelCache[L["customButton"]])
	end
end

function NWB:createCustomButton(count)
    NWB["NWBCustomButton" .. count] = CreateFrame("Button", "NWBCustomButton" .. count, NWBlayerFrame.EditBox, "UIPanelButtonTemplate")
    local button = NWB["NWBCustomButton" .. count]
    button:SetWidth(90)
    button:SetHeight(15)
    button:SetText(NWB:getButtonText(count))
    button:SetNormalFontObject("GameFontNormalSmall")
    button.layer = 0
    button.isDisabledByOther = false
    button.disabledByButtonCount = 0
    button.timerData = {
        layerID = 0,
        originalText = NWB:getButtonText(count)
    }
    button:SetScript("OnClick", function(self, arg)
		NWB.OrderAccept = true
		NWB.lastClickedButton = self
		NWB.lastClickedButtontime = time()
        local layerID = self.layer
        local buttonCount = count
		local limit = NWB.limitLayerCount or 10
		for i = 1, limit do
			if i ~= NWB.currentLayer then
				local otherButton = _G["NWBCustomButton" .. i]
				if otherButton then
					otherButton.isDisabledByOther = true
					otherButton.disabledByButtonCount = buttonCount
					otherButton:Disable()
				end
			end
		end
		if type(NWB.triggerSingleButtonCooldown) == "function" and buttonCount > 0 then
			NWB:triggerSingleButtonCooldown(buttonCount)
		end
		if layerID and type(NWB.ConvertNum) == "function" and NWB.channelCache[L["customButton"]] then
			local convertedLayerID = NWB:ConvertNum(tostring(layerID))
			if convertedLayerID then
				if UnitInParty("player") then LeaveParty() end
				local dqzone = NWB:getLayerZoneID(NWB.currentLayer) or 0
				dqzone = NWB:ConvertNum(tostring(dqzone))
				SendChatMessage("#HWM&" .. convertedLayerID .. "&" .. dqzone, "CHANNEL", nil, NWB.channelCache[L["customButton"]])
				NWB.CheckOnline = false
				C_Timer.After(7,function()
					if NWB.CheckOnline then NWBdatabase.Member.isEnable = true else NWBdatabase.Member.isEnable = false end
				end)
				if NWB.channelCache[L["angelchnanel"]] and NWB.channelCache[L["angelchnanel"]] > 0 then
					NWB.AngelInfoList = {}
					SendChatMessage(NWBdatabase.Member.GetInfoMsg,"CHANNEL",nil,NWB.channelCache[L["angelchnanel"]])
				end
			end
		end
    end)
    local tooltip = CreateFrame("Frame", "NWBCustomButtonTooltip" .. count, button, "TooltipBorderedFrameTemplate")
    tooltip:SetPoint("BOTTOM", button, "TOP", 0, 5)
    tooltip:SetFrameStrata("HIGH")
    tooltip:SetFrameLevel(3)
	tooltipText = NWB:getTooltipText(count, NWBdatabase.Member.Type)
    tooltip.fs = tooltip:CreateFontString("NWBCustomButtonTooltipFS" .. count, "ARTWORK")
    tooltip.fs:SetPoint("CENTER", 0, 0)
    tooltip.fs:SetFont(NWB.regionFont or "Fonts\\FRIZQT__.TTF", 13)
    tooltip.fs:SetJustifyH("LEFT")
    tooltip.fs:SetText(tooltipText)
    tooltip:SetWidth(tooltip.fs:GetStringWidth() + 18)
    tooltip:SetHeight(tooltip.fs:GetStringHeight() + 12)
    button:SetScript("OnEnter", function(self) tooltip:Show() end)
    button:SetScript("OnLeave", function(self) tooltip:Hide() end)
    tooltip:Hide()
end

function NWB:getTooltipText(count,memberType)
	--NWBdatabase.Member.isEnable 用这个控制离线文本和广告
	local memberType = memberType or "1"
    local tooltipMap = {
        ["1"] = L["angelad"],
        ["default"] = string.format(L["customButtonTooltip"], count)
    }
    return tooltipMap[memberType] or tooltipMap["default"]
end

function NWB:GetzoneIDHash()
	local zoneIDHash = {}
	for k, v in NWB:pairsByKeys(NWB.data.layers) do
		zoneIDHash[k] = true
	end
	return zoneIDHash
end

function NWB:GuestSQ()
	local playerName = UnitName("player")
	NWB:triggerGlobalCooldown()
	local serverName = GetRealmName()
	local charList = NWB:getCharactersByServer(playerName,serverName)
	local result = playerName .. "," .. table.concat(charList, ",")
	SendChatMessage("#SQVIP&" .. result, "CHANNEL", nil, NWB.channelCache[L["customButton"]])
end

function NWB:getCharactersByServer(playerName, serverName)
    if not playerName or not serverName then
        return {}
    end
    local maxLength = 200
    local count = 0
    local characters = {}
    local seen = {}
    local currentLength = 0
    for key, value in pairs(NWBdatabase.profileKeys) do
        local charName, server = string.match(key, "^([^%s%-][^%-]*)%s*-%s*(.-)$")
        if charName and server then
            charName = string.match(charName, "^(.-)%s*$")
            if not charName:lower():find("old") then
                if #charName <= 18 and not charName:match("^[%d%p]+$") then
                    if server:lower() == serverName:lower() and charName:lower() ~= playerName:lower() and not seen[charName] then
                        local newLength = currentLength + (currentLength > 0 and 1 or 0) + #charName
                        if newLength <= maxLength and count < 10 then
                            seen[charName] = true
                            table.insert(characters, charName)
                            currentLength = newLength
                            count = count + 1
                        end
                    end
                end
            end
        end
    end
    return characters
end

function NWB:bitXor(a, b)
    local result = 0
    for i = 0, 7 do
        local bitA = math.floor(a / 2^i) % 2
        local bitB = math.floor(b / 2^i) % 2
        result = result + (bitA ~= bitB and 1 or 0) * 2^i
    end
    return result
end

function NWB:xorCrypt(plaintext, key)
    local output = {}
    local keyLen = string.len(key)
    for i = 1, string.len(plaintext) do
        local plainByte = string.byte(plaintext, i)
        local keyByte = string.byte(key, ((i - 1) % keyLen) + 1)
        output[i] = string.char(NWB:bitXor(plainByte, keyByte))
    end
    return table.concat(output)
end

function NWB:jsgzshiprint(msg, channel, prefix, tbcCheck)
	--Add prefix and colors from db then print.
	local printPrefix;
	if (tbcCheck and not NWB.isClassic and (NWB.db.global.disableChatAllLevels
		or (UnitLevel("player") > NWB.maxBuffLevel and NWB.db.global.disableChatAboveMaxBuffLevel))) then
		return;
	end
	if (prefix) then
		printPrefix = NWB.prefixColor .. prefix .. "|r";
	end
	if (channel) then
		channel = string.lower(channel);
	end
	if (channel == "group" or channel == "team") then
		channel = "party";
	end
	if (channel == "gchat" or channel == "gmsg") then
		channel = "guild";
	end
	local channelWhisper, name;
	if (channel) then
		channelWhisper, name = strsplit(" ", channel, 2);
	end
	if (channelWhisper == "tell" or channelWhisper == "whisper" or channelWhisper == "msg") then
		if (not prefix) then
			printPrefix = "[" .. L["customButton"] .. "]";
		end
		if (name and name ~= "") then
			SendChatMessage(printPrefix .. " " .. msg, "WHISPER", nil, name);
		else
			print(NWB.chatColor .. "No whisper target found.");
		end
	elseif (channel == "r" or channel == "reply") then
		if (not prefix) then
			printPrefix = "[" .. L["customButton"] .. "]";
		end
		if (NWB.lastWhisper and NWB.lastWhisper ~= "") then
			if (NWB.lastWhisperType == "bnet") then
				BNSendWhisper(NWB.lastWhisper, printPrefix .. " " .. msg);
			else
				SendChatMessage(printPrefix .. " " .. msg, "WHISPER", nil, NWB.lastWhisper);
			end
		else
			print(NWB.chatColor .. "No last whisper target found.");
		end
	elseif (channel == "say" or channel == "yell" or channel == "party" or channel == "guild" or channel == "officer" or channel == "raid") then
		--If posting to a specifed channel then advertise addon name in prefix, more people that have the addon then more accurate the data is.
		if (not prefix) then
			printPrefix = "[" .. L["customButton"] .. "]";
			if (channel == "guild") then
				printPrefix = "[" .. L["customButton"] .. "]";
			end
		end
		SendChatMessage(printPrefix .. " " .. msg, channel);
	elseif (tonumber(channel)) then
		--Send to numbered channel by number.
		local id, name = GetChannelName(channel);
		if (id == 0) then
			print(NWB.chatColor .. "No channel with id " .. NWB.prefixColor .. channel .. NWB.chatColor .. " exists.");
			print(NWB.chatColor .. "Type \"/wb\" to print world buff timers to yourself.");
			print(NWB.chatColor .. "Type \"/wb config\" to open options.");
			print(NWB.chatColor .. "Type \"/wb guild\" to post buff timers to the specified chat channel (accepts channel names and numbers).");
			print(NWB.chatColor .. "Use \"/sf\" in the same way for songflowers.");
			print(NWB.chatColor .. "Type \"/dmf\" for your Darkmoon Faire buff cooldown.");
			print(NWB.chatColor .. "Type \"/buffs\" to view all your alts world buffs.");
			return;
		end
		if (not prefix) then
			printPrefix = "[" .. L["customButton"] .. "]";
		end
		SendChatMessage(printPrefix .. " " .. NWB:stripColors(msg), "CHANNEL", nil, id);
	elseif (channel ~= nil and channel ~= "print") then
		--Send to numbered channel by name.
		local id, name = GetChannelName(channel);
		if (id == 0) then
			print(NWB.chatColor .. "No channel with id " .. NWB.prefixColor .. channel .. NWB.chatColor .. " exists.");
			print(NWB.chatColor .. "Type \"/wb\" to print world buff timers to yourself.");
			print(NWB.chatColor .. "Type \"/wb config\" to open options.");
			print(NWB.chatColor .. "Type \"/wb guild\" to post buff timers to the specified chat channel (accepts channel names and numbers).");
			print(NWB.chatColor .. "Use \"/sf\" in the same way for songflowers.");
			print(NWB.chatColor .. "Type \"/dmf\" for your Darkmoon Faire buff cooldown.");
			print(NWB.chatColor .. "Type \"/buffs\" to view all your alts world buffs.");
			return;
		end
		if (not prefix) then
			printPrefix = "[" .. L["customButton"] .. "]";
		end
		SendChatMessage(printPrefix .. " " .. NWB:stripColors(msg), "CHANNEL", nil, id);
	else
		if (not prefix) then
			printPrefix = NWB.prefixColor .. "|HNWBCustomLink:timers|h[" .. L["customButton"] .. "]|h|r";
		end
		if (prefix == "[DMF]") then
			printPrefix = NWB.prefixColor .. "|HNWBCustomLink:timers|h[" .. L["customButton"] .. "]|h|r";
		end
		if (NWB.isLayered) then
			msg = "|HNWBCustomLink:timers|h" .. msg .. "|h";
		end
		print(printPrefix .. " " .. NWB.chatColor .. msg);
	end
end
