local GetDefaultLanguage = GetDefaultLanguage
local DisplayChannelOwner = DisplayChannelOwner
local SendAddonMessage = SendAddonMessage
local SendChatMessage = SendChatMessage
local KEYWROD = "MessageShare"
MessageShare = LibStub("AceAddon-3.0"):NewAddon(KEYWROD, "AceTimer-3.0", "AceEvent-3.0","AceSerializer-3.0");
local MS = MessageShare
local ChanngeName = "MoguChannel"
local PassWord = "MessageSharePassWord"
local Language = GetDefaultLanguage()
local PlayerName = UnitName("Player")
local realmKey = GetRealmName()
local MessageTable = {}
local MessageTypes = {}
local InviteKeyWord = {"+","组","組","invite"}
local db
--MS.kick = {}
local ChannelOwner
function MS:Module(name, ...)
	local module = self:GetModule(name, true)
	if not module then
		module = self:NewModule(name, ...)
		module.func = {}
		module.db = module.default or {}
		setmetatable(module.func, {__index = function(t,k,v) return MS[k] end})
	end
	return module
end
function MS:SendAddonMessage(...)
	if not self.messages then
		self.messages = {}
		self.frame = CreateFrame'Frame'
		local delay = 0
		self.frame:SetScript("OnUpdate",function(_,elapsed)
			delay = delay + elapsed
			if delay>.08 then
				delay = 0
				if #self.messages>0 then
					--SendAddonMessage(unpack(tremove(self.messages,1)))
					ChatThrottleLib:SendAddonMessage("NORMAL",unpack(tremove(self.messages,1)))
				end
			end
		end)
	end
	table.insert(self.messages,{...})
end
function MS:DelMessage(sender)
	local found
	if self.messages then
		for i=#self.messages,1,-1 do
			if select(4,self.messages[i])==sender then
				tremove(self.messages,i)
				found = true
			end
		end
	end
	return found
end
local function HideChannelDisplay()
	oGetChannelName = oGetChannelName or GetChannelName
	function GetChannelName(id)
		local index,name,arg3 = oGetChannelName(id)
		if name ==ChanngeName then
			return 0,nil,0
		else
			return index,name,arg3
		end
	end
	oGetChannelList = oGetChannelList or GetChannelList
	function GetChannelList()
		local t = {oGetChannelList()}
		for i,j in pairs(t) do
			if j==ChanngeName then
				table.remove(t,i-1)
				table.remove(t,i-1)
				break
			end
		end
		return unpack(t)
	end
end
local function GetChannelId()
	return oGetChannelName(ChanngeName)
end
local function JoinChannel()
	if GetChannelList() then
		JoinTemporaryChannel(ChanngeName,PassWord)
		DisplayChannelOwner(ChanngeName)
		ChatFrame_RemoveChannel(FCF_GetCurrentChatFrame(), ChanngeName)
		MS:ScheduleTimer(function() 
			for i,j in pairs(MS.modules) do
				if j.OnModuleReady then
					j:OnModuleReady()
				end
			end
		end,
		2)
	else
		MS:ScheduleTimer(function()
			JoinChannel()
		end,
		1)	
	end
end
function MS:PLAYER_ENTERING_WORLD()
	MS:ScheduleTimer(function() --不加延时,重载后会丢失频道
		JoinChannel()
	end,
	.5)
end
function MS:PLAYER_LOGIN()
	MessageShareDB = MessageShareDB or {}
	MessageShareDB[realmKey] = MessageShareDB[realmKey] or {}
	db = MessageShareDB[realmKey]
	for i,j in pairs(MS.modules) do
		db[i] = db[i] or j.db
		j.db = db[i]
	end
	MS:Options()
end
function MS:GetModuleUser()--试玩账号不能获取
--print(next(self.UserList))
	return next(self.UserList) or ChannelOwner
end
function MS:GetChannelMemberNum()
	local id = GetChannelId()
	if not id then return end
	local name, header, collapsed, channelNumber, count, active, category, voiceEnabled, voiceActive = GetChannelDisplayInfo(id);
	return count
end
function MS:GetChannelMaster()
	return ChannelOwner
end
function MS:SendWisper(key,msg,target)
--print("SendWisper",msg,target)
--SendChatMessage("123","WHISPER",Language,target)
	if not (msg and target) then return end
	msg = MS:Serialize(msg)
	local time = time()
	self:SendAddonMessage(ChanngeName,key.."&&START"..time,"WHISPER",target)
	local lenkey = string.len(key)
	local len,str = 250-lenkey-2
	while msg~="" do
		str = msg:sub(1,len)
		self:SendAddonMessage(ChanngeName,key.."&&"..str,"WHISPER",target)
		msg = msg:sub(len+1)
	end
	self:SendAddonMessage(ChanngeName,key.."&&END"..time,"WHISPER",target)
end
local function addUserList(mod,name)
	mod.func.UserList[name] = true
	--print("addUserList",name)
end
local function delUserList(mod,name)
	if mod.func.UserList and mod.func.UserList[name] then
		mod.func.UserList[name] = nil
	end
end
local function OnReceiveWhisper(key,sender)
	local t = MessageTable[key][sender][#(MessageTable[key][sender])]
	local msg = t.msg
	local time = t.time
	--msg:gsub(key.."&&","")
	local success,msg = MS:Deserialize(msg)
	if success then
		for i,j in pairs(MS.modules) do
			if j.func.MessageTypes and j.func.MessageTypes[key] then
				j:OnReceiveWhisper(key,sender,msg)
				if msg=="isUser" then
				--print("OnReceiveWhisper","isUser",sender)
					addUserList(j,sender)
				end
			end
		end
	end
end
function MS:CHAT_MSG_ADDON(event,prefix, msg, channel, sender)
	if prefix == ChanngeName and sender~=PlayerName then
--print(event,prefix, msg, channel, sender)
		local key = msg:match("(.+)&&")
		if MessageTypes[key] and MessageTypes[key]>0 then
			--[[ if msg:find("&&isUser")  then
			print("CHAT_MSG_ADDON","isUser")
				local mod = self:GetModule(key, true)
				if mod and mod.func.UserList then
					table.insert(mod.func.UserList,sender)
				end
			elseif msg:find("&&GetUserList") then
			print("CHAT_MSG_ADDON","GetUserList")
				SendAddonMessage(ChanngeName,key.."&&isUser","WHISPER",sender)
			else ]]if msg:find("&&START")  then
				local time = msg:match("%d+")
				MessageTable[key] = MessageTable[key] or {}
				MessageTable[key][sender] = MessageTable[key][sender] or {}
				tinsert(MessageTable[key][sender],{time = time,msg = "",})
			elseif msg:find("&&END") and MessageTable[key] and MessageTable[key][sender] then
				local t = MessageTable[key][sender][#(MessageTable[key][sender])]
				if not t or t.ended then return end
				t.ended = true
				if t.time == msg:match("%d+") then
					OnReceiveWhisper(key,sender)
				end
			elseif MessageTable[key] and MessageTable[key][sender] then
				--debug(MessageTable,key,sender,#(MessageTable[key][sender]))
				local t = MessageTable[key][sender][#(MessageTable[key][sender])]
				if not t or t.ended then return end
				t.msg = t.msg..msg:gsub(key.."&&","")
			--else
				--print("2CHAT_MSG_ADDON",key,msg,sender)
			end
		end
	end
end
function MS:SendMessage(key,msg)
--print("SendMessage",msg)
	if not msg then return end
	msg = MS:Serialize(msg)
	msg = msg:gsub("\124","\124\124")
	local id = GetChannelId()
	local time = time()
	SendChatMessage(key.."&&START"..time,"CHANNEL",Language,id)
	local lenkey = string.len(key)
	local len,str,step
	while msg~="" do--尽量每句发的长点.并且要避免把UTF8字符及"\124\124"截断
		len = 80
		str = msg:utf8sub(1,len)
		while (string.len(str) < (250- string.len(key) -2))  or (str:sub(-1)=="\124" and str:sub(-2)~="\124\124") do
			step = floor(((250- lenkey -2) - string.len(str))/3)
			len = len + max(1,step)
			str = msg:utf8sub(1,len)
			if str==msg then
				break
			end
		end
		SendChatMessage(key.."&&"..str,"CHANNEL",Language,id)
		msg = msg:utf8sub(len+1)
	end
	SendChatMessage(key.."&&END"..time,"CHANNEL",Language,id)
end
function MS:RegisterChatType(key)
	self.UserList = {}
	self.MessageTypes = self.MessageTypes or {}
	self.MessageTypes[key] = true
	MessageTypes[key] = MessageTypes[key] and (MessageTypes[key] + 1) or 1
	MS:SendMessage(key,"GetUserList")
end

function MS:UnregisterChatType(key)
	if self.MessageTypes and self.MessageTypes[key] then
		self.MessageTypes[key] = nil
		MessageTypes[key] = MessageTypes[key] and (MessageTypes[key] - 1) or 0
	end
end
local function OnReceiveMessage(key,sender)
	local t = MessageTable[key][sender][#(MessageTable[key][sender])]
	local msg = t.msg
	local time = t.time
	for i,j in pairs(MS.modules) do
		if j.func.MessageTypes and j.func.MessageTypes[key] then
			msg = msg:gsub("\124\124","\124")
			local success,msg = MS:Deserialize(msg)
			if success then
				j:OnReceiveMessage(key,sender,msg)
				if msg=="GetUserList" then
				--print("SendWisper","isUser",sender)
					MS:SendWisper(i,"isUser",sender)
					addUserList(j,sender)
				end
			end
		end
	end
end
function MS:CHAT_MSG_BN_WHISPER(event,msg,sender,...)
	if CanGroupInvite() then
		for _,key in pairs(InviteKeyWord)do
			if msg and msg:find(key) then
				local index = 1
				local flag,presenceID, presenceName, battleTag, isBattleTagPresence, toonName = pcall(BNGetFriendInfo,index)
				while flag and presenceName do
					if presenceName==sender then
						InviteToGroup(toonName)
						local text = string.format(MESSAGESHARE_INVITEWHISPER,PlayerName,GetNumGroupMembers())
						SendChatMessage(text,"WHISPER",Language,toonName)
						return
					else
						index = index + 1
						flag,presenceID, presenceName, battleTag, isBattleTagPresence, toonName = pcall(BNGetFriendInfo,index)
					end
				end
			end
		end
	end
end
function MS:CHAT_MSG_WHISPER(event,msg,sender)
	if CanGroupInvite() then
		for _,key in pairs(InviteKeyWord)do
			if msg and msg:find(key) then
				InviteToGroup(sender)
				local text = string.format(MESSAGESHARE_INVITEWHISPER,PlayerName,GetNumGroupMembers())
				SendChatMessage(text,"WHISPER",Language,sender)
				return
			end
		end
	end
end
function MS:CHAT_MSG_CHANNEL(event,msg,sender,language,channle)
	--if InCombatLockdown() then return end
	if channle:find(ChanngeName) and sender~=PlayerName then
	--print(event,msg,sender)
		local key = msg:match("(.+)&&")
		if MessageTypes[key] and MessageTypes[key]>0 then
			--[[ if msg:find("&&GetUserList")  then
			print("CHAT_MSG_CHANNEL","GetUserList")
				--SendAddonMessage(ChanngeName,key.."&&isUser","WHISPER",sender)
			else ]]if msg:find("&&START")  then
				local time = msg:match("%d+")
				MessageTable[key] = MessageTable[key] or {}
				MessageTable[key][sender] = MessageTable[key][sender] or {}
				tinsert(MessageTable[key][sender],{time = time,msg = "",})
			elseif msg:find("&&END") and MessageTable[key] and MessageTable[key][sender] then
				local t = MessageTable[key][sender][#(MessageTable[key][sender])]
				if not t or t.ended then return end
				t.ended = true
				if t.time == msg:match("%d+") then
					OnReceiveMessage(key,sender)
				end
			elseif MessageTable[key] and MessageTable[key][sender] then
				local t = MessageTable[key][sender][#(MessageTable[key][sender])]
				if not t or t.ended then return end
				t.msg = t.msg..msg:gsub(key.."&&","")
			--else print("CHAT_MSG_CHANNEL",key,msg,sender)
			end
		end
	end
end
function MS:CHAT_MSG_CHANNEL_NOTICE_USER(...)
	local _,message,owner,_,_,_,_,_,_,channelName = ...
	if (message =="CHANNEL_OWNER" or message=="OWNER_CHANGED") and channelName==ChanngeName then
		ChannelOwner = owner
	end
end
function MS:CHAT_MSG_CHANNEL_JOIN(event,...)
	local _, sender, _, channelString, _, _, _, channelNumber, channelName=...
	if channelName == ChanngeName then
		if PlayerName==MS:GetChannelMaster() then-- 第一次收到的 Whisper可能丟失,因此加入頻道後先收到一條無用消息
			MS:SendWisper("","",sender)
		end
	end
end
function MS:CHAT_MSG_CHANNEL_LEAVE(event,...)
	local _, sender, _, channelString, _, _, _, channelNumber, channelName=...
	if channelName == ChanngeName then
		for i,j in pairs(MS.modules) do
			delUserList(j,sender)
		end
		self:DelMessage(sender)
	end
end
ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", function(_,_,msg)
	local name = msg and msg:match(ERR_CHAT_PLAYER_NOT_FOUND_S:gsub("%%s","(.+)"))
	if name then
		MS:DelMessage(name)
		 return true--MS:DelMessage(name)
	end
end)
function MS:OnLeaveGame()
	LeaveChannelByName(ChanngeName)
end
--print("OnInitialize")
function MS:OnInitialize()
	HideChannelDisplay()
	if (RegisterAddonMessagePrefix) then
		RegisterAddonMessagePrefix (ChanngeName)
	end
	self:RegisterEvent("CHAT_MSG_WHISPER")
	self:RegisterEvent("CHAT_MSG_BN_WHISPER")
	self:RegisterEvent("CHAT_MSG_CHANNEL")
	self:RegisterEvent("PLAYER_LOGIN")
	self:RegisterEvent("CHAT_MSG_ADDON")
	self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE_USER")
	self:RegisterEvent("CHAT_MSG_CHANNEL_JOIN")
	self:RegisterEvent("CHAT_MSG_CHANNEL_LEAVE")
	self:RegisterEvent("PLAYER_QUITING","OnLeaveGame")
	self:RegisterEvent("PLAYER_LEAVING_WORLD","OnLeaveGame")
	self:RegisterEvent("PLAYER_ENTERING_WORLD")
end
function ToggleAutoInvite(flag)
	if flag then
		MS:RegisterEvent("CHAT_MSG_WHISPER")
		MS:RegisterEvent("CHAT_MSG_BN_WHISPER")
	else
		MS:UnregisterEvent("CHAT_MSG_WHISPER")
		MS:UnregisterEvent("CHAT_MSG_BN_WHISPER")
	end
end
function MS:CopyTable(result,value)
	if type(value) =="table" then
		wipe(result)
		for i,j in pairs(value) do
			result[i] = j
		end
	end
end
function MS:Options()
	if IsAddOnLoaded("!!!Mush") then
		return
	end
	if db.autoinvite==nil then db.autoinvite = true end
	ToggleAutoInvite(db.autoinvite)
	print(MESSAGESHARE_OPTIONS_MS)
	local function SlashCmd(msg)
		msg = string.lower(msg)
		if msg=="bank" then
			ShowOffLineBank()
		elseif msg=="boss" then
			WildBossShowLog()
		elseif msg=="group" then
			db.autoinvite = not db.autoinvite
			ToggleAutoInvite(db.autoinvite)
			print(MESSAGESHARE_OPTIONS_INVITE..(db.autoinvite and "|cff00ff00"..ENABLE or "|cffff0000"..DISABLE))
		elseif msg=="list" then
			ShowPlayerList()
		else
			print(MESSAGESHARE_OPTIONS_BANK)	
			print(MESSAGESHARE_OPTIONS_BOSS)	
			print(MESSAGESHARE_OPTIONS_LIST)	
			print(MESSAGESHARE_OPTIONS_INVITE..(db.autoinvite and "|cff00ff00"..ENABLE or "|cffff0000"..DISABLE))	
		end
	end
	SLASH_MS1 = "/MessageShare";
	SLASH_MS2 = "/ms";
	SlashCmdList["MS"] = SlashCmd;
end
