

--GHI = LibStub("AceAddon-3.0"):new("GHI","AceComm-3.0", "AceSerializer-3.0",...);
GHI = LibStub("AceComm-3.0");
local serial = LibStub("AceSerializer-3.0");

function GHI:SendMessage(channel, player, ...)
--print("hit")
--if not(UnitIsPlayer(player)) then return;end
if GMChatFrame_IsGM then return end;
	GHI:SendCommMessage("GHI", serial:Serialize({...}), channel, player);
end

function GHI:SendPrioritizedMessage(prio, channel, player, ...)
--if not(UnitIsPlayer(player)) then return;end
if GMChatFrame_IsGM then return end;
	GHI:SendCommMessage("GHI", serial:Serialize({...}), channel, player, prio);
end

function GHI_CommunicationHookings(self)
	
	--self:RegisterEvent("CHAT_MSG_ADDON");
	
	GHI:RegisterComm("GHI", function(...) GHI:RecieveRawMessage(...) end)
	
	-- SendCommMessage
	
	--[[
	GHI.Orig_SendCommMessage = GHI.SendCommMessage;
	GHI.SendCommMessage = function(self,channel, player, ...)
	GHI.SendCommMessage = function(self,channel, player, ...)
		GHI.Orig_SendCommMessage(self,"GHI",serial:Serialize({...}),channel,player);
	end 
	GHI.SendPrioritizedCommMessage = function(self,prio,channel, player, ...)
		GHI.Orig_SendCommMessage(self,"GHI",serial:Serialize({...}),channel,player,prio);
	end -- ]]
	
	orig_MainMenuBarPerformanceBarFrame_OnEnter = MainMenuBarPerformanceBarFrame_OnEnter;
	MainMenuBarPerformanceBarFrame_OnEnter = GHI_MainMenuBarPerformanceBarFrame_OnEnter;
	
	--GHI_DoScript("GHI_OrigSendAddonMessage = SendAddonMessage; SendAddonMessage = GHI_SendAddonMessage;",10);
	-- the hook should be initialized after the ace comm hook
	GHI_OrigSendAddonMessage = SendAddonMessage; SendAddonMessage = GHI_SendAddonMessage;
end



if GHI then
	GHI.ownName = UnitName("player");
end 

function GHI:ReceiveMessageFromChannel(prefix, sender, distribution, dummy, recieverName, oldRecieve, ...)  -- 
	--[[
	local reciever = "dummy"
	if type(meta) == "string" then
		GHI_Message("FROM CHANNEL. "..prefix.." : ".. sender.." : "..distribution.." : "..recieverName.." :  ".. meta.." : "..type(arg1).." : "..type(arg2))
	else
		GHI_Message("FROM CHANNEL. "..prefix.." : ".. sender.." : "..distribution.." : "..recieverName.." :  ".. type(meta).." : "..type(arg1).." : "..type(arg2))
	end   --]]
	--local meta, arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12 = unpack({...});
	--GHE:Msg("FROM CHANNEL. prefix: %s, sender: %s, distribution: %s, dummy: %s, oldRecieve: %s, recieverName: %s, meta: %s, arg1: %s,arg2: %s, arg3: %s, arg4: %s",prefix, sender, distribution,dummy, oldRecieve, recieverName, ...)
	--GHE:Msg("i f %s == %s th en",recieverName,GHI.ownName);
	if recieverName == nil then
		GHI_Message((sender or "Unknown").."'s client is sending data without any target.");
	end
	
	assert(not(recieverName==nil),"A client is sending data without any target.");
	local t = {...};
	t=GHI.UnpackLen13(t);

	if recieverName == GHI.ownName then
		GHI:ReceiveMessage(prefix, sender, distribution,oldRecieve, unpack(t))
	end
end

--  End of epilogue edits

--	====================================  Ace
function GHI:RecieveRawMessage(prefix,text,distribution,sender)
	local sucess, t = serial:Deserialize(text);
	if type(t) == "table" then
		GHI:ReceiveMessage(prefix, sender, distribution, unpack(t));
	end
end

local recieveFunctions = {};
function GHI:RegisterRecieve(tag,func)
	assert(type(tag) == "string" and type(func) == "function","RegisterRecieve usage: tag (string), func (function)");
	assert(not(type(recieveFunctions[tag])=="function"),"Tag "..tag.." already registered.");
	recieveFunctions[tag] = func;
end



GHI_ShowComm = false;
function GHI:ReceiveMessage(prefix, sender, distribution, oldRecieve, meta, arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
	
	-- filter unknown away
	if distribution == "UNKNOWN" then return end
	
	--[
	if GHI_ShowComm == true then
		if type(meta) == "string" then
			GHI_Message(prefix.." : ".. sender.." : ".. distribution.." :  ".. meta.." : "..type(arg1).." : "..type(arg2))
		else
			GHI_Message(prefix.." : ".. sender.." : ".. distribution.." :  ".. type(meta).." : "..type(arg1).." : "..type(arg2))
		end 
	end
	
	if oldRecieve == true then
		GHI_RecieveData(meta,arg1,sender)
	elseif oldRecieve == false then
		if meta == "BuffInfo" then -- old buff system
			GHI_RecieveBuff(sender,arg1);
		elseif meta == "DebuffInfo" then -- old buff system
			GHI_RecieveDebuff(sender,arg1);
		elseif meta == "ItemVersion" then
			GHI_RecieveItemVersion(arg1,arg2,sender);
		elseif meta == "ItemDataRequest" then
			GHI_RecieveItemDataRequest(arg1,sender);
		elseif meta == "ItemData" then
			GHI_RecieveItemData(arg1,arg2,sender);
		elseif meta == "SuspectedLinkName" then
			GHI_SendLink(arg1,sender);
		elseif meta == "ItemDataVersions" then
			GHI_ItemDataVersions(arg1,arg2,arg3,sender) 
		elseif meta == "ItemRCData" then
			GHI_RecieveItemRCData(arg1,arg2);
		elseif meta == "ExpectRCData" then
			GHI_RecieveExpectRCData(arg1,nil);
		elseif meta == "ExpectRCDataTime" then
			GHI_RecieveExpectRCData(arg1,arg2);
		elseif meta == "EndRCData" then
			GHI_RecieveEndRCData(arg1);
		elseif meta == "TradeDuration" then
			GHI_RecieveTradeDuration(arg1,arg2,arg3,arg4);
		elseif meta == "ApplyBuff" then		
			ApplyGHIBuff(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)
		elseif meta == "TradeBagInfo" then	
			GHI_RecieveTradeBagDetails(arg1,arg2);
		end
	
	end
	
	if string.len(meta or "") > 0 and type(recieveFunctions[meta]) == "function" then
		recieveFunctions[meta](sender,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
	end
end


--	==================================== Communication	====================================

GHI_In = 0;
GHI_Out = 0;
GHI_InThisSec = 0;
GHI_OutThisSec = 0;
GHI_OutThisSec = 0;

GHI_COMMUNICATION_LIMIT = 20;

GHI_OutBuffer = {};
GHI_OutPointer = 0;

function GHI_SendDataToBuffer(metaData,data,reciever)
	--- should no longer be used
	
	
	--GHR_Message("GHI. In: "..GHI_In.." Out: "..GHI_Out);
	--GHI_Message("=== Sending Data to "..reciever.." ===");
	if reciever == "" or reciever == nil then return end;
	
	local a = strsub(reciever,0,1);
	local b = strsub(reciever,2);
	local new = "";
	
	if a then
		local va = tonumber(strbyte(a));
		if (va >= 65 and va <= 90) or (va >= 97 and va <= 122) then
			new = strupper(a)..strlower(b);
		else 
			new = reciever;
		end
	end
	
	if new == nil or new == "" or new == " " then return end;
	
	
	
	--GHR_Message("Sending to "..new);
	--GHI_Message(metaData);
	--SWM_Message(data);

	
	
	GHI_OutThisSec = GHI_OutThisSec + 1;
	
	if GHI_OutThisSec > GHI_COMMUNICATION_LIMIT or GHI_OutPointer > 0 then    --- 	or  buffer size > 0
		local list = {};
		list.metaData = metaData;
		list.data = data;
		list.reciever = new;
		
		GHI_OutPointer = GHI_OutPointer + 1;
		GHI_OutBuffer[GHI_OutPointer] = list;
	else
		GHI_Out = GHI_Out + 1;
		SendAddonMessage("GHI_"..metaData,data,"WHISPER",new);
	end
end

function GHI_SendBufferData()
	if GHI_OutPointer == 0 then return end
	
	-- 	Move data in buffer
	local firstNil = 0;
	if GHI_OutPointer > 500 then
		for i = 1,GHI_OutPointer do
			if GHI_OutBuffer[i] == nil then
				firstNil = i;
				break;
			end
		end
	end
	if not(firstNil == 0) then
		local addr = 0;
		for i = firstNil,GHI_OutPointer do
			addr = addr + 1;
			GHI_OutBuffer[addr] = GHI_OutBuffer[i];
		end
		GHI_OutPointer = addr;
	end
	
	
	local c1 = 0;
	local c2 = 0;
	local c3 = GHI_OutPointer;
	local send = GHI_OutThisSec;
	if GHD_OutThisSec == nil then
		GHD_OutThisSec = 0;
	end
	for i = 1,GHI_OutPointer do
		if send + GHD_OutThisSec > GHI_COMMUNICATION_LIMIT then
			break;
		end
		
		if type(GHI_OutBuffer[i]) == "table" then
			local metaData = GHI_OutBuffer[i].metaData;
			local data = GHI_OutBuffer[i].data;
			local reciever = GHI_OutBuffer[i].reciever;
			if not(metaData == nil) and not(reciever == nil) then
				GHI_Out = GHI_Out + 1;
				SendAddonMessage("GHI_"..metaData,data,"WHISPER",reciever);
				send = send + 1;

				
				GHI_OutBuffer[i] = nil;
				
				if c1 == 0 then
					c1 = i;
				end
			end
		end
		if i == GHI_OutPointer then
			GHI_OutPointer = 0;
			break;
		end
		c2 = i;
	end
	
	--GHI_Message("Sending GHI buffer. Address: "..c1.." - "..c2.." Total: "..c2 - c1.." Max: "..c3);
	
end







function GHI_SendData(dataType,data,reciever)

	if reciever == "" or reciever == nil then return end;
	
	local a = strsub(reciever,0,1);
	local b = strsub(reciever,2);
	local new = "";
	
	if a then
		local va = tonumber(strbyte(a));
		if (va >= 65 and va <= 90) or (va >= 97 and va <= 122) then
			new = strupper(a)..strlower(b);
		--elseif (dataType == "AreaSound" or "AreaBuff") then
		--new = reciever;
		--GHI:SendPrioritizedMessage("BULK", "WHISPER", new,true,dataType,data)
		--return
		else
		new = reciever;
		end
	end
	
	if new == nil or new == "" or new == " " then return end;

	GHI:SendMessage("WHISPER",new, true, dataType, data)
	--SendAddonMessage("GHI_"..dataType,data,"WHISPER",new);
end

function GHI_RecieveData(b,data,sender)
	
	data = GHI_ConvertToNum(data);
	
	--GHI_Message("Recieved "..b);
	--print(data)
	if b == "ReqLink" then
		GHI_SendLink(data,sender)
	elseif string.sub(b,0,10) == "ItemReply<" then
		GHI_RecieveLink(string.sub(b,10),data,sender);
	elseif string.sub(b,0,12) == "ItemReplyEnd" then
		GHI_RecieveLinkEnd(data,sender);
	elseif string.sub(b,0,6) == "Trade<" then	
		GHI_RecieveTradeItem(string.sub(b,7),data,sender);
	elseif b == "TradeAccepted" then
		if sender == GHI_TradePlayer then
			GHI_AcceptTrade();
		end
	elseif b == "RequestBuffs" then	-- request from old buff system
		if not(GHI_SubscribedPlayers[sender]) then
			GHI_OldBuffPlayers[sender] = data or 1;
			if GHI_OldBuffPlayers["own time"] and GHI_OldBuffPlayers["own time"] >= (data or 1) then -- only send it if it have not already been send.
				GHI_SendBuffInfo(sender)
			end
		end
		--GHI_SendDebuffInfo(sender)
	elseif string.sub(b,0,5) == "Buff_" then	
		--GHI_RecieveBuff(string.sub(b,6),data,sender);
	elseif b == "RequestDebuffs" then	-- request from old buff system (not used)
		GHI_SendDebuffInfo(sender)
	elseif string.sub(b,0,7) == "Debuff_" then	
		GHI_RecieveDebuff(string.sub(b,8),data,sender);
	elseif string.sub(b,0,15) == "ItemDataVersion" then
		GHI_RecieveItemDataVersion(data,sender);
	elseif b == "AddonVersionReq" then
		local ver = GetAddOnMetadata("GHI", "Version");
		GHI_SendData("AddonVersionAnswer",ver,sender);
		--GHI_SendData("AddonBetaAnswer",GHI_BetaKey,sender);
	elseif b == "AddonVersionAnswer" then
	    --print("hit")
		if sender == GHI_TradePlayer then
			GHI_RecipientHasGHI = true;
			GHI_RecipientGHIVersion = data;
		end
		if sender == GHI_PingedPlayer then
			GHI_RecievePing(sender,data);
		end
		--GHI_Message(sender.." got version "..data);
	elseif b == "AddonBetaAnswer" then
		if sender == GHI_PingedPlayer then
			GHI_Message(data);
			GHI_PingedPlayer = nil;
		end
	elseif b == "AreaSound" then
	 GHI_GetAreaEffectSound(sender,data)
	  ---i am gonna split the sound and debuff into thier own functions.
	  --print("area sound");
	elseif b == "AreaBuff" then
	GHI_GetAreaEffectBuff(sender,data)
	elseif b == "DisableGHI" then
		GHI_MiscData["disabled"] = true;
	elseif b == "EnableGHI" then
		GHI_MiscData["disabled"] = false;
	end
end



--	vvvvvvvvv	Item data transfer

function GHI_SendLink(name,player) 
	--	Should be run backwards?
	local found = false;
	if not(type(GHI_ItemData) == "table") then return; end
	
	--GHI_Message("Request: "..name.." to "..player);
	
	for index1,value1 in pairs(GHI_SendItemsID) do 
		if GHI_IsOfficialItem(value1) then
			value1 = tonumber(value1);
			if type(GHI_OfficialItemData[value1]) == "table" then 
				if GHI_OfficialItemData[value1].name == name then
					local version = GHI_GetVersions(value1);
					GHI:SendPrioritizedMessage("ALERT","WHISPER",player,false,"ItemVersion",value1,0)
					found = true;
					break;
				end
			end
		else
			if type(GHI_ItemData[value1]) == "table" then
				if GHI_ItemData[value1].name == name then
					local version = GHI_GetVersions(value1);
					GHI:SendPrioritizedMessage("ALERT","WHISPER",player,false,"ItemVersion",value1,version)
					found = true;
					break;
				end
			end
		end
	end
	
	if found == false then
		for i = 1,#(GHI_SendNotItems) do
			if GHI_SendNotItems[i] == name then
				GHI:SendPrioritizedMessage("ALERT","WHISPER",player,false,"ItemVersion","0_"..name,0)
				found = true;
				--GHI_Message("Send none link");
				break;
			end
		end
	end
	
end

function GHI_RecieveItemVersion(ID,version,sender)
	if ID and string.sub(ID,0,2) == "0_" then
		--GHI_Message("Recieve none link");
		GHI_RecieveLinkEnd(ID,sender);
	end
	if GHI_IsOfficialItem(ID) then
		GHI_RecieveLinkEnd(ID,sender)
	end
	local ownVersion = GHI_GetVersions(ID);
	--GHI_Message("sender-> "..version.." > "..ownVersion.." <- own")
	if version > ownVersion then --print("send req");
		GHI:SendMessage("WHISPER",sender,false,"ItemDataRequest",ID)
		GHI_RecieveExpectLink(sender);
	else
		GHI_RecieveLinkEnd(ID,sender)
	end

end

function GHI_RecieveItemDataRequest(ID,sender) -- print("recieve req");
	if not(type(GHI_ItemData) == "table") or not(type(GHI_ItemData[ID])=="table") then return end
	
	local data = {};
	for index1,value1 in pairs(GHI_ItemData[ID]) do
		if not(index1 == "rightClick") then
			data[index1] = value1;
		
		end	
	end
	
	
	GHI:SendMessage("WHISPER",sender,false,"ItemData",ID,data)
end

function GHI_RecieveItemData(ID,data,sender) -- print("recieve data");
	local origRC = GHI_GetRightClickInfo(ID);
	
	GHI_ItemData[ID] = data;
	GHI_SetRightClickInfo(ID,origRC);
	GHI_RecieveLinkEnd(ID,sender)
	--GHI_Message("GHI_RecieveItemData version: "..(GHI_ItemData[ID].version or "nil"));
end


function GHI_RecieveLink(prefix,data,sender)  -- no longer in use
	--GHI_Message(prefix.." : "..data);
	
	local arrayName = "GHI_ItemData";
	local array;
	array = _G[arrayName];
	if not(type(array) == "table") then  return end;
	
	
	addrPart = prefix;
	
	
	if data == tostring(tonumber(data)) then data = tonumber(data); end
	
	c = string.find(addrPart,"<");
	d = string.find(addrPart,">");
	
	if c and d then
		addr1 = string.sub(addrPart,c+1,d-1);
		
		if addr1 then 
			if addr1 == tostring(tonumber(addr1)) then addr1 = tonumber(addr1); end
			c = string.find(addrPart,"<",d);
			d = string.find(addrPart,">",d+1);
			if c and d then
				addr2 = string.sub(addrPart,c+1,d-1);
				
				if addr2 then 
					if addr2 == tostring(tonumber(addr2)) then addr2 = tonumber(addr2); end
					c = string.find(addrPart,"<",d);
					d = string.find(addrPart,">",d+1);
					if c and d then
						addr3 = string.sub(addrPart,c+1,d-1);
						if addr3 then 
							if addr3 == tostring(tonumber(addr3)) then addr3 = tonumber(addr3); end
							c = string.find(addrPart,"<",d);
							d = string.find(addrPart,">",d+1);
							if c and d then
								addr4 = string.sub(addrPart,c+1,d-1);
								if addr4 then
									if addr4 == tostring(tonumber(addr4)) then addr4 = tonumber(addr4); end
									if not(type(array[addr1]) == "table") then
										array[addr1] = {}
									end
									if not(type(array[addr1][addr2]) == "table") then
										array[addr1][addr2] = {}
									end
									if not(type(array[addr1][addr2][addr3]) == "table") then
										array[addr1][addr2][addr3] = {}
									end
									array[addr1][addr2][addr3][addr4] = data;
									_G[arrayName]=array;
								end
							else
								if not(type(array[addr1]) == "table") then
									array[addr1] = {}
								end
								if not(type(array[addr1][addr2]) == "table") then
									array[addr1][addr2] = {}
								end
								array[addr1][addr2][addr3] = data;
								_G[arrayName]=array;
							end
						end
					else
						if not(type(array[addr1]) == "table") then
							array[addr1] = {}
						end
						array[addr1][addr2] = data;
						_G[arrayName]=array;
						
					end
				end
			else
				array[addr1] = data;
				_G[arrayName]=array;
			end		
		end
	end	
	
end


GHI_ExpectLink = {};

function GHI_RecieveExpectLink(sender)
	if sender then
		GHI_ExpectLink[sender]=time();
		--GHR_Message("Expect link from "..sender);
	end
end

function GHI_RecieveLinkEnd(data,sender)
	--GHR_Message("Recieve link en d "..data.." from "..sender);
	local info;
	if data and string.sub(data,0,2) == "0_" then
		info = {};
		info.notLink = true;
		info.name = string.sub(data,3);
	elseif GHI_IsOfficialItem(data) then
		data = tonumber(data);
		info = GHI_OfficialItemData[data];
		
	else
		info = GHI_ItemData[data];
	end
	if not( type(info) == "table") then 
		return 
	end;
	
	
	
	for index1,value1 in pairs(GHI_IncMsgWaiting) do 
		if type(value1) == "table" then
			
			if value1.sender == sender  then
				local text = value1.text;
				a = 0;
				done = true;
				for i=1,5 do
					--GHI_Message("link "..i.." string is now '"..text.."' Size: "..strlen(text));
					a = GHI_SearchStringForChar(text,91,a+1);
					b = strfind(text,"]",a);
					if a and b then
						
						local linkText,link;
						linkText = strsub(text,a+1,b-1);
						
						--GHI_Message(linkText.." == "..info.name..". a found as: "..a);
						if info.notLink == true and info.name == linkText then
							--GHI_Message("Found as "..a..": "..info.name);
							text = strsub(text,0,a-1).."|nolink["..linkText.."]"..strsub(text,b+1);
							a = a + 16;
						elseif linkText == info.name then
							link = GHI_GenerateLink(data);
							local cc = strlen(text);
							text = strsub(text,0,a-1)..link..strsub(text,b+1);
							--GHR_Message("Expanded with "..strlen(text)-cc);
							--GHR_Message("Insert "..link);
							a = a + 60;
						else
							-- is it an already inserted link?
							
							c = string.sub(text,a-7,a-1);
							
							--GHI_Message("'"..c.."' lenght: "..strlen(c).."   link text: "..linkText);
							if not(c == "0:0:0|h" or c == "|nolink") then   -- not already inserted
								---GHR_Message("not already inserted");
								done = false;
							end
							a = a + 2;
						end
						
						--c,d = strfind(text,linkText);
						
						--GHI_SendDataToBuffer("ReqLink",strsub(text,a+1,b-1),arg2);
						
						--
						
					else 	
						break;
					end
				end
				
				a = 0;
				for i = 1,5 do 
					a = GHI_SearchStringForChar(text,91,a+1);
					b = strfind(text,"]",a);
					if a and b then
						c = string.sub(text,a-7,a-1);
						--GHI_Message(c.." == 0:0:0|h");
						if not(c == "0:0:0|h" or c == "|nolink") then
							done = false;
							--GHI_Message("not done: "..text);
						end
						
					else
						break;
					end
				end
				
				
			
				if done == true then
					--GHI_Message("text: "..text);
					text = gsub(text,"|nolink","");
					local old_arg1 = mesg;  --
					local event = value1.event;
				
					_G["mesg"]= text;  --GHI_Message("arg1: "..(text or "nil"));
					_G["sender"]= value1.sender; --GHI_Message("arg2: "..(value1.sender or "nil"));
					_G["lang"]= value1.lang; --GHI_Message("arg3: "..(value1.arg3 or "nil"));
					_G["chanString"]= value1.chanString; --GHI_Message("arg4: "..(value1.arg4 or "nil"));
					_G["target"]= value1.target; --GHI_Message("arg5: "..(value1.arg5 or "nil"));
					_G["flags"]= value1.flags; --GHI_Message("arg6: "..(value1.arg6 or "nil"));
					_G["ukwn1"]= value1.ukwn1; --GHI_Message("arg7: "..(value1.arg7 or "nil"));
					_G["chanNum"]= value1.chanNum; --GHI_Message("arg8: "..(value1.arg8 or "nil"));
					_G["chanName"]= value1.chanName; --GHI_Message("arg9: "..(value1.arg9 or "nil"));
					_G["ukwn2"]= value1.ukwn2; --GHI_Message("arg10: "..(value1.arg10 or "nil"));
					_G["counte"]= value1.counte; 
					_G["guid"]= value1.guid; 
					_G["arg13"]= value1.arg13; 
					_G["arg14"]= value1.arg14; 
					_G["arg15"]= value1.arg15; 
					_G["arg16"]= value1.arg16; 
					_G["arg17"]= value1.arg17; 
					_G["arg18"]= value1.arg18; 
					_G["arg19"]= value1.arg19; 
					--_G["this"]= value1.this); --GHI_Message("this: "..(value1.this:GetName() or "nil"));
					_G["event"]= value1.event; --GHI_Message("event: "..(value1.event or "nil"));
					GHI_TestTrigger = true;
					----------------  start test
					--[[
					GHI_Message("Recieved link end. Variable list: ");
					for i=1,11 do
						local V = _G["arg"..i];
						if type(V) == "string" or type(V) == "number" then
							GHI_Message("arg"..i..": "..type(V).." = "..V);
						else
							GHI_Message("arg"..i..": "..type(V));
						end
					end
					local V = _G["self"];
					if type(V) == "string" or type(V) == "number" then
						GHI_Message("self: "..type(V).." = "..V);
					else
						GHI_Message("self: "..type(V));
					end
					local V = _G["event"];
					if type(V) == "string" or type(V) == "number" then
						GHI_Message("event: "..type(V).." = "..V);
					else
						GHI_Message("event: "..type(V));
					end]]
					--------------   en d test
					if event=="CHAT_MSG_SYSTEM" then
					local player = gsub(string.match(mesg,"'.*'") or "","'","");
					if player and format(ERR_CHAT_PLAYER_NOT_FOUND_S,player) == mesg and ((GHI_MessageErrorsExpected_A[player] or GHI_MessageErrorsExpected_B[player])) then
							--print("filtering ",player)
							return;
						end
					end
					--[[
					if GHI_CompAddons["Prat"] == true and not(value1.FCCC == true) then 
						if event == "CHAT_MSG_CHANNEL" then
							for i = 1,7 do
								_G["self"]=_G["ChatFrame"..i];
								--Prat:ChatFrame_MessageEventHandler(event)
								if i == 1 then
									Prat:ChatFrame_MessageEventHandler(event);
								else
								  local name, fontSize, r, g, b, a, shown, locked, docked, uninteractable = GetChatWindowInfo(i);
								  if name ~= "Combat Log" then
									GHI_origChatFrame_MessageEventHandler(_G["ChatFrame"..i],event,mesg,sender,lang,chanString,target,flags,ukwn1,chanNum,chanName,ukwn2,counte,guid, arg13, arg14, arg15,arg16,arg17,arg18,arg19);
								  end
								end
							end	
						else
							-- todo: run for other chat windows
							Prat:ChatFrame_MessageEventHandler(event)
						end
						
					elseif GHI_CompAddons["ForgottenChatCC"] == true and value1.FCCC == true then
						if value1.self == true then
							GHI_OrigFCCC_OutgoingMessage(value1.to, text, value1.lan)
						else
							GHI_OrigFCCC_IncomingMessage(value1.sender, text, value1.afk)
						end
					else --]]
						if event == "CHAT_MSG_CHANNEL" then
							for i = 1,7 do
								_G["self"]=_G["ChatFrame"..i];
								 local name, fontSize, r, g, b, a, shown, locked, docked, uninteractable = GetChatWindowInfo(i);
								  if name ~= "Combat Log" or i ~= 2 then
									GHI_origChatFrame_MessageEventHandler(_G["ChatFrame"..i],event,mesg,sender,lang,chanString,target,flags,ukwn1,chanNum,chanName,ukwn2,counte,guid, arg13, arg14, arg15,arg16,arg17,arg18,arg19);
								  end

							end		
						else
							-- todo: run for other chat windows
								for i = 1,7 do
								_G["self"]=_G["ChatFrame"..i];
								  local name, fontSize, r, g, b, a, shown, locked, docked, uninteractable = GetChatWindowInfo(i);
								  if name ~= "Combat Log" or i ~= 2 then
									GHI_origChatFrame_MessageEventHandler(_G["ChatFrame"..i],event,mesg,sender,lang,chanString,target,flags,ukwn1,chanNum,chanName,ukwn2,counte,guid, arg13, arg14, arg15,arg16,arg17,arg18,arg19);
								  end
						  end
						end
					--e nd
					
					GHI_IncMsgWaiting[index1] = nil;
					_G["mesg"]= old_arg1;
					GHI_IsForcingEvent = false;
				else
					GHI_IncMsgWaiting[index1].text = text; --GHI_Message("Msg still stored: "..text);
				end			
			end
		end
	end
	
	--	Check i f the item is i n the trade window
	for i = 1,6 do
		if type(GHI_TradeItemsRecipient[i]) == "table" then
			if GHI_TradeItemsRecipient[i].ID == data then
				GHI_SetRecipientButton(i,GHI_TradeItemsRecipient[i].ID,GHI_TradeItemsRecipient[i].amount)
			end
		end
	end
end


function GHI_ItemDataVersions(ID,v1,v2,sender) --- after trade
	local own_v1,own_v2 = GHI_GetVersions(ID);
	if own_v1 > v1 then
		GHI_RecieveItemDataRequest(ID,sender)
	end
	if own_v2 > v2 then
		if not(type(GHI_ItemData) == "table") or not(type(GHI_ItemData[ID])=="table") then return end
	
		local data = {};
		for index1,value1 in pairs(GHI_ItemData[ID]) do
			if (index1 == "rightClick") then
				data = value1;
			
			end	
		end
		
		-- todo:  Send an alert with expectation of the information
		GHI:SendPrioritizedMessage("ALERT","WHISPER",sender,false,"ExpectRCData",ID)
		
		local size_b = 0;
		for prioname, Prio in pairs(ChatThrottleLib.Prio) do
			if type(Prio.Ring)=="table" and type(Prio.Ring.pos)=="table" then
				for prioname, data in pairs(Prio.Ring.pos) do
					size_b = size_b + (data.nSize or 0);
				end
			end
		end
		
		GHI:SendMessage("WHISPER",sender,false,"ItemRCData",ID,data)
		
		
		local size_a = 0;
		for prioname, Prio in pairs(ChatThrottleLib.Prio) do
			if type(Prio.Ring)=="table" and type(Prio.Ring.pos)=="table" then
				for prioname, data in pairs(Prio.Ring.pos) do
					size_a = size_a + (data.nSize or 0);
				end
			end
		end
		
		
		
		--GHI_Message("before: "..size_b.." after: "..size_a);
		--local a = ChatThrottleLib:UpdateAvail(); 
		-- TODO. calculate queue time with corect bandwith. Calculate sending time.
		local secs = (size_a)/250; -- assumed average
		--GHI_Message("done in "..secs.." secs");
		GHI:SendPrioritizedMessage("ALERT","WHISPER",sender,false,"ExpectRCDataTime",ID,secs)
		
		
		GHI:SendMessage("WHISPER",sender,false,"EndRCData",ID)
	end
	
	
end

GHI_AwaitingRCData = {};
GHI_AwaitingRCDataTime ={};

function GHI_RecieveExpectRCData(ID,Time)
	GHI_AwaitingRCData[ID] = true;
	if Time then
		GHI_AwaitingRCDataTime[ID] = Time+time();
	else
		GHI_AwaitingRCDataTime[ID] = Time;
	end
end

function GHI_RecieveItemRCData(ID,data)
	if not(type(GHI_ItemData) == "table") or not(type(GHI_ItemData[ID])=="table") then return end
	GHI_ItemData[ID].rightClick = data;
	--GHI_Message("GHI_RecieveItemRCData version: "..(GHI_ItemData[ID].version or "nil"));
end

function GHI_RecieveEndRCData(ID)
	GHI_AwaitingRCData[ID] = nil;
	GHI_AwaitingRCDataTime[ID] = nil;
end


--	^^^^^^^^^^^^
---AREA SOUND/BUFFS
local function round(number, decimals)
    return (("%%.%df"):format(decimals)):format(number)
end

local function XYUpdate()


	local x, y =GetPlayerMapPosition("player");
	local xa = math.modf(x*1000)/10;
	local ya = math.modf(y*1000)/10;
	x = round(x*1002,2);
	y = round(y*668,2);
	--print(x)
	--print(y)
	--WorldMapFrame:Hide();
	
	return x,y;
end

local SOUND_PLAYED = false;

function GHI_SendAreaEffect(typed,...)
	
	local x,y = XYUpdate();
	--print(typed)
	if typed == "sound" then

		local soundPath,range,delay = ...;
		local comzone = GetZoneText()
		
		---print(comezone)
		local players = GHI_AddOns:GetAllPlayers()

		for k,player in pairs(players) do 
			--print(player);
			--SendAddon message to member name with the soundpath,zone and the xy coords.
			local data = comzone..":"..x..":"..y..":"..soundPath..":"..range..":"..(delay or 0);
			
			if not(soundPath == "dummy") then -- filter the dummy call away. Dummy call is used to request the chat cache to be updated.
				GHI_SendData("AreaSound",data,player)
			end

		end

	elseif typed == "buff" then
		-- Do as above but for buff/debuffs.
		local click = ...;
		local comzone = GetZoneText()

		local otherPlayers = GHI_AddOns:GetAllPlayers()
			
		click.zone = comzone;
		click.x = x;
		click.y = y;
		click.range = range;
			
		for k,v in pairs(otherPlayers) do
			GHI_SendData("AreaBuff",click,v)
		end
  end
  
end

function GHI_SendAreaBuff(buffName,buffDetails,buffIcon,untillCanceled,filter,buffType,buffDuration,cancelable,stackable,count,delay,range)
	local zone = GetZoneText()
	local x,y = XYUpdate();
	
	local data = {
		zone=zone,
		x=x,
		y=y,
		range=range or 60,
		
		buffName=buffName,
		buffDetails=buffDetails,
		buffIcon=buffIcon,
		untillCanceled=untillCanceled,
		filter=filter,
		buffType=buffType,
		buffDuration=buffDuration,
		cancelable=cancelable,
		stackable=stackable,
		count=count or 1,
		delay=delay or 0,
	};				
		
	local players = GHI_AddOns:GetAllPlayers()
	for _,player in pairs(players) do
		GHI_SendData("AreaBuff",data,player)
	end
end


function GHI_GetAreaEffectSound(sender,data)--... is other data.
	if GHI_MiscData["block_area_sound"] then return end
	local comzone = GetZoneText();
	local X,Y = XYUpdate();
	

	local zonesender,sx,sy,soundPath,range,delay = strsplit(":",data);
	
	if range~="Zone" then
		--print(comzone,zonesender);
		if comzone == zonesender then
			--print("hit")
			if ( math.abs(math.sqrt((sx-X)*(sx-X) + (sy-Y)*(sy-Y))) <= tonumber(range) and tonumber(range) <= 70) then
				soundPath = gsub(soundPath,"\\\\","/");
				soundPath = gsub(soundPath,"\\","/");
				
				-- validate sound path
				-- allows spaces \ _ numbers letters and .
				soundPath = (string.match(soundPath,"[a-zA-z0-9\\/_.%s]*"));
				
				local suffix = "";
				if GHI_MiscData["show_area_sound_sender"] then
					suffix = " GHI_Message(\"Area sound by "..(sender or nil).."\");"
				end
				
				
			    local a = "PlaySoundFile(\""..soundPath.."\");"..suffix;
                   --print(a)
				GHI_DoScript(a,tonumber(delay));  --PlaySoundFile
				
				
				
			end
		end
	  
	end

end

function GHI_GetAreaEffectBuff(sender,data)
	
	if GHI_MiscData["block_area_buff"] then return end
--

	local zonesender,sx,sy,range = data.zone,data.x,data.y,data.range;
	local X,Y = XYUpdate();
	local range = range or 60;
	local cast;
	
	local comzone = GetZoneText()
	if comzone == "City of Ironforge" then comzone = "Ironforge"; end
	
	if range~= "Zone" then

	
		if comzone == zonesender then
			
			if (math.abs(math.sqrt((sx-X)*(sx-X) + (sy-Y)*(sy-Y)))<= tonumber(range) and tonumber(range) <= 70) then
				
				ApplyGHIBuff(data.buffName,data.buffDetails,data.buffIcon,data.untillCanceled,data.filter,data.buffType,data.buffDuration,data.cancelable,data.stackable,data.count or 1,data.delay or 0)
			end
		end
	end
end

--[[

if (math.abs(math.sqrt((sx-X)*(sx-X) + (sy-Y)*(sy-Y)))<= tonumber(range)) and SOUND_PLAYED == false then
UpdateLastPlayed()--just gonna do this for buff delay too
--local b = GHU_New("buff") -- It should be called with GHI_ApplyBuff
--b:CastBuff(filter,refID,guid,name,description,icon,totalDuration,endTime,count,debuffType)
   end
   end
 else
 --zone broadcast
  UpdateLastPlayed()
local b = GHU_New("buff")
--b:CastBuff(filter,refID,guid,name,description,icon,totalDuration,endTime,count,debuffType)
 end
end   --]]


function GHI_SendAddonMessage(prefix, text, Type, target)
	--print("send to ",target or "nil")
	if target then 
		GHI_MessageErrorsExpected_A[target] = 1;
	end
	GHI_OrigSendAddonMessage(prefix, text, Type, target)
end



GHI_TimeOutLimit = 10;
function GHI_CheckTimeoutedMsg()
		
	
	for index1,value1 in pairs(GHI_IncMsgWaiting) do 
		if type(value1) == "table" then
			local sender = value1.sender;
			local delay = 0;
			if type(GHI_ExpectLink[sender]) == "number" then
				
				delay = GHI_TimeOutLimit*4
				
			end
		
			if value1.time < time() - (GHI_TimeOutLimit + delay) then
				
				
				--GHR_Message(value1.text.." from "..value1.sender.." timed out after ".. (GHI_TimeOutLimit + delay).." secs");
				local text = gsub(value1.text,"|nolink","");
				
				local event = value1.event;
				-- this should be done dynamically when making GHU_Links
			_G["mesg"]= text;  --GHI_Message("arg1: "..(text or "nil"));
					_G["sender"]= value1.sender; --GHI_Message("arg2: "..(value1.sender or "nil"));
					_G["lang"]= value1.lang; --GHI_Message("arg3: "..(value1.arg3 or "nil"));
					_G["chanString"]= value1.chanString; --GHI_Message("arg4: "..(value1.arg4 or "nil"));
					_G["target"]= value1.target; --GHI_Message("arg5: "..(value1.arg5 or "nil"));
					_G["flags"]= value1.flags; --GHI_Message("arg6: "..(value1.arg6 or "nil"));
					_G["ukwn1"]= value1.ukwn1; --GHI_Message("arg7: "..(value1.arg7 or "nil"));
					_G["chanNum"]= value1.chanNum; --GHI_Message("arg8: "..(value1.arg8 or "nil"));
					_G["chanName"]= value1.chanName; --GHI_Message("arg9: "..(value1.arg9 or "nil"));
					_G["ukwn2"]= value1.ukwn2; --GHI_Message("arg10: "..(value1.arg10 or "nil"));
					_G["counte"]= value1.counte; 
					_G["guid"]= value1.guid; 
					_G["arg13"]= value1.arg13; 
					_G["arg14"]= value1.arg14; 
					_G["arg15"]= value1.arg15; 
					_G["arg16"]= value1.arg16; 
					_G["arg17"]= value1.arg17; 
					_G["arg18"]= value1.arg18; 
					_G["arg19"]= value1.arg19; 
	
				_G["self"]= value1.self;
				
				
				if GHI_CompAddons["Prat"] == true and value1.FCCC == false then 
					
					if event == "CHAT_MSG_CHANNEL" then
						for i = 1,7 do
							_G["self"]=_G["ChatFrame"..i];
							Prat:ChatFrame_MessageEventHandler(event)
						end		
					else
						-- todo: run for other chat windows
						Prat:ChatFrame_MessageEventHandler(event)
					end
				elseif GHI_CompAddons["ForgottenChatCC"] == true and value1.FCCC == true then
					if value1.self == true then
						GHI_OrigFCCC_OutgoingMessage(value1.to, value1.text, value1.lang)
					else
						GHI_OrigFCCC_IncomingMessage(value1.sender, value1.text, value1.afk)
					end
				else
					if event == "CHAT_MSG_CHANNEL" then
						for i = 1,7 do
							_G["self"]=_G["ChatFrame"..i];
													  local name, fontSize, r, g, b, a, shown, locked, docked, uninteractable = GetChatWindowInfo(i);
								  if name ~= "Combat Log" then
									GHI_origChatFrame_MessageEventHandler(_G["ChatFrame"..i],event,mesg,sender,lang,chanString,target,flags,ukwn1,chanNum,chanName,ukwn2,counte,guid, arg13, arg14, arg15,arg16,arg17,arg18,arg19);
								  end

						end		
					else
						-- todo: run for other chat windows
						for i = 1,7 do
							_G["self"]=_G["ChatFrame"..i];
								  local name, fontSize, r, g, b, a, shown, locked, docked, uninteractable = GetChatWindowInfo(i);
								  if name ~= "Combat Log" then
									GHI_origChatFrame_MessageEventHandler(_G["ChatFrame"..i],event,mesg,sender,lang,chanString,target,flags,ukwn1,chanNum,chanName,ukwn2,counte,guid, arg13, arg14, arg15,arg16,arg17,arg18,arg19);
								  end
						end
					end
				end
				GHI_IncMsgWaiting[index1] = nil;
						
			end
		end
	end
	
	
	
end

--	======================== Sending item data
--	sending link = no right click info
--	Sending item data = inc right click info

function GHI_SendItemData(ID,player)
	if not(type(GHI_ItemData) == "table") then return; end
	
	--GHI_Message("Sending all data for "..ID.." to "..player);
	
	
	if type(GHI_ItemData[ID]) == "table" then
		
	local index1 = ID;
	
		for index2,value2 in pairs(GHI_ItemData[ID]) do 
			if type(value2) == "table" then
				for index3,value3 in pairs(value2) do 
					if type(value3) == "table" then
						for index4,value4 in pairs(value3) do 
							if type(value4) == "table" then
								-- More than 4 arrays
							else
								GHI_SendDataToBuffer("ItemReply<"..index1.."><"..index2.."><"..index3.."><"..index4..">",value4,player);
							end
						end
					else
						GHI_SendDataToBuffer("ItemReply<"..index1.."><"..index2.."><"..index3..">",value3,player);
					end
				end
			else 
				GHI_SendDataToBuffer("ItemReply<"..index1.."><"..index2..">",value2,player);
			end
		end
		
		GHI_SendDataToBuffer("ItemReplyEnd",index1,player);				
		
		
	else
		
	end
	
end

function GHI_RecieveItemDataVersion(data,sender)  -- GHR_Message("As: Recieved data version");
	local ID,version = strsplit(":",data);
	if not(ID) or not(version) then return end
	if not(type(GHI_ItemData[ID]) == "table") then return end
	
	local ownVersion = GHI_ItemData[ID].version;
	if not(ownVersion) then
		ownVersion = 0;
	end
	version = tonumber(version);
	ownVersion = tonumber(ownVersion);
	if not(version) or not(ownVersion) then
		return;
	end
	
	if ownVersion > version then
		GHI_SendItemData(ID,sender)  --GHR_Message("A1: Sending data.");
	end
	--GHI_Message(ownVersion.." == "..version);
	--GHR_Message("Ae: End recieved data version");
end


function GHI_SendPing(player)
	GHI_SendData("AddonVersionReq",nil,player);
	GHI_PingedPlayer = player;
end

function GHI_RecievePing(player,data)
	
	GHI_Message("Ping reply from "..player);
	GHI_Message("Version "..data);
	GHI_PingedPlayer = nil;
end



--	======================== Bandwith analyzing ========================
function GHI_MainMenuBarPerformanceBarFrame_OnEnter(f)
	orig_MainMenuBarPerformanceBarFrame_OnEnter(f);
	
	local Max = ChatThrottleLib.BURST
	local avail = ChatThrottleLib:UpdateAvail();
	if ChatThrottleLib.bChoking == true then
		Max = ChatThrottleLib.MAX_CPS;
	end
	
	local qSize = 0;
	for _,Prio in pairs(ChatThrottleLib.Prio) do
		for _,pipe in pairs(Prio.ByName) do
			qSize = qSize + #pipe;
		end
	end
	
	GameTooltip:AddLine("\nBandwidth Used");
	GameTooltip:AddLine(format("%.0f / %.0f b/sec (%.0f%%).",
		Max-avail,
		Max,
		((Max-avail)/Max)*100
	), 1.0, 1.0, 1.0);
	GameTooltip:AddLine(format("%.0f messages in queue.",
		qSize
	), 1.0, 1.0, 1.0);
	if ChatThrottleLib.bChoking then
		GameTooltip:AddLine("Bandwidth lowered due to zoning or low framerate.");
	end
	GameTooltip:Show();
end

PERFORMANCEBAR_UPDATE_INTERVAL = 1;


