--[[
	The SW Sync Channel
	
]]--

SW_SyncPassiveMode = false;

SW_SyncMsgs = {};

SW_S_DetailsSynced = {};
SW_S_HealedSynced = {};

--1.5 added deathcounter to sync
SW_DCSynced = {};

--1.5.1 added decurse count syncing
SW_DecurseCSynced = {};

-- holds "lost" mana info
SW_ManaAfterDrop = {0,0,0};

SW_SyncSessionID = 1;

SW_SyncChanID = 0;
-- var that hold info if we are leaving the SyncChannel
SW_SyncLeavingChannel = false;

-- used to see if the person is still there
SW_LITimerDead = 300;

-- 1.42 added timeframe in which to accept session id updates without a RE
-- (joining a running channel)
SW_SessIDTimerThresh = 210 ; -- in this imeframe we will have at least an LI once
SW_SessIDTimer = time();

-- 1.5.3 increased val buffer from 3% to 10%
SW_ValBuffer = 10 -- % this is used to check if somebody else needs to post info even though this was a self info (user dropped)
SW_DecurseBuffer = 3; --same as above but not as % 

-- time in seconds to assume the person in the channel has "up to date" info 
-- eg he drops and reconnects checked in SW_SyncSend
SW_SyncKeepTime = 300;

SW_S_LastManaSent = {0,0,0};

-- 1.5 added, used to stop sending unneeded messages on relogging
SW_StartupTime = time();
SW_SyncIgnoreNil = 120;

SW_Sync_MsgTrack = {};

--[[ The sync Queue
	So we dont have to think about timing record length etc
	only thing to consider is that one single message may not be larger then 255 chars
	but we use short strings here anyways
]]--


SW_SyncQueue =
{
	first = 1,
	last =	0,
	maxBlockLen = 255, 
	sep = '"',
	sepLen = 1,
	queue = {},
	clearing = false,
	itemSep = '~',
	
	PushSWInfo = function (self, infType, vals)
		if self.clearing then return false; end
		if SW_Settings["SYNCLastChan"] == nil then return; end
		if SW_SyncChanID == 0 then return; end
		
		local tmpVal;
		local outStr = infType.." ";
		local valLen =0;
		local ident = SW_SyncPepper[infType];
		local sCount=0;
		local iCount=0;
		if vals == nil then
			vals = { math.random(100) };
		end
		
		valLen = table.getn(vals);
		for i,v in ipairs(vals) do
			tmpVal = tonumber(v);
			if tmpVal == nil then
				sCount = sCount + 1;
				
			else
				iCount = iCount + 1;
				ident = ident + tmpVal;
				
				
			end
			outStr = outStr..v;
			if i ~= valLen then
				outStr = outStr..self.itemSep
			end
		end
			
		
		tmpVal = math.floor(math.sqrt(ident * string.len(SW_Settings["SYNCLastChan"]))) * 1000;
		ident = math.floor(1000 * math.sqrt(ident * string.len(SW_Settings["SYNCLastChan"])));
		
		self:PushVal(SW_SyncSessionID.." "..(ident-tmpVal).." "..sCount.." "..iCount.." "..outStr);
		--self:PushVal(SW_SyncSessionID.." "..outStr);
	end,
	PushVal = function (self, val)
		if string.len(val) > self.maxBlockLen or self.clearing then return false; end
		local last = self.last + 1;
		self.last = last;
		self.queue[last] = val;
		return true;
	end,
	PopStack = function (self)
		if self.clearing then return nil; end
		
		local last = self.last;
		if self.first > last then return nil; end
		local val = self.queue[last];
		self.queue[last] = nil;
		self.last = last - 1;
		return val;
	end,
	Pop = function (self)
		if self.clearing then return nil; end
		local first = self.first;
		if first > self.last then return nil; end
		local val = self.queue[first];
		self.queue[first] = nil;
		self.first = first + 1;
		return val;
	end,
	HasData = function (self)
		if self.clearing then return false; end
		return not (self.first > self.last);
	end,
	Clear = function (self)
		self.clearing = true;
		for i=self.first, self.last do 
			self.queue[i] = nil;
			self.first = i + 1;
		end
		self.clearing = false;
	end,
	PopBlock = function (self)
		if self.clearing then return nil; end
		local first = self.first;
		if first > self.last then return nil; end
		local sepsLen = self.sepLen;
		local pos = first;
		local len = string.len(self.queue[first]);
		while self.queue[pos + 1] and len + string.len(self.queue[pos + 1]) + sepsLen < self.maxBlockLen do
			pos = pos + 1;
			sepsLen = sepsLen + self.sepLen;
			len = len + string.len(self.queue[pos]);
		end
		local val = table.concat(self.queue, self.sep, first, pos);
		for i=first, pos do 
			self.queue[i] = nil;
			self.first = i + 1;
		end
		return val;
	end,
	-- to lazy wouldn't work if + is a sep in the queue not using %
	-- because this goes through chat and the profanity filter could alter the str and add a %
	EncStr = function (self, str)
		local sOut = string.gsub(str, "([%"..self.sep.."%"..self.itemSep.."%+%|])", 
			function(c)
				return string.format ("+%02X", string.byte(c)) 
			end);
		return sOut;
	end,
	DecStr = function (self, str)
		local sOut = string.gsub (str, "%+(%x%x)", 
			function(h) 
				return string.char(tonumber(h,16)) 
			end);
		return sOut;
	end,
	
};

function SW_SyncSend()
	-- this only happens when logging out and comeing back in or when leaving sync channel
	if SW_SyncChanID ~= 0 and SW_Settings["SYNCLastAction"] ~= nil and time() - SW_Settings["SYNCLastAction"]  > SW_SyncKeepTime then
		-- are we still in this channel?
		id, _ = GetChannelName(SW_Settings["SYNCLastChan"]); 
		if id == 0 then
			SW_SyncChanID = 0;
			SW_Settings["SYNCLastChan"] = nil;
			if SW_S_DetailsSynced[SW_SELF_STRING] ~= nil then
				SW_S_DetailsSynced[SW_SELF_STRING]["LI"] = nil;
			end
			return;
		end
		-- if we get here we are still in the channel and need a reset
		SW_printStr("Reset in SyncSend");
		SW_SessIDTimer = time();
		SW_SyncReset(1);
		return;
	end
	if SW_SyncChanID == 0 and SW_Settings["SYNCLastChan"] ~= nil then
		SW_SyncChanID, _ = GetChannelName(SW_Settings["SYNCLastChan"]);
	end
	
	local toSend = SW_SyncQueue:PopBlock();
	if toSend ~= nil then
		if SW_SyncChanID ~= 0 then
			SendChatMessage(toSend, "CHANNEL", nil, SW_SyncChanID);
		end
	end
	if SW_SyncLeavingChannel then
		SW_SyncLeavingChannel = false;
		SW_SyncChanID = 0;
		LeaveChannelByName(SW_Settings["SYNCLastChan"]);
		SW_Settings["SYNCLastChan"] = nil;
		SW_Settings["SYNARP"] = nil;
		SW_BarFrame1_Title_SyncIcon:Hide();
	end
end
-- used to un/compress ints that are being sent
-- not sure about WOW but looking at utf  im assuming we have only the lower 127 chars available for 1 byte storage
-- minus the lower 32 that are special chars - minus " " (space) - '"' (doublequote) which we want to use
-- DOH and dont use \ .. escape codes 
-- DOH what about pipe??

-- taking it out atm its making more problems than doing good
--[[
SW_SyncInt = {
	digits = {},
	rev = {},
	base = 10;
	Init = function(self, base)
		--[[
		self.base = base;
		self.digits = {};
		self.rev = {};
		for i=0,9 do self.digits[i] = string.char(48+i) end
		for i=10,71 do self.digits[i] = string.char(55+i) end -- dont add 127 (DEL)
		for i=72,84 do self.digits[i] = string.char(119-i) end --go back in the table from before "0" and stop before '"'
		self.digits[85] = "!";
		for i=86,92 do self.digits[i] = string.char(150-i) end
		--]]
		self.base = base;
		self.rev = {};
		self.digits = {"1","2","3","4","5","6","7","8","9",
		  "A","B","C","D","E","F","G","H","I","J",
		  "K","L","M","N","O","P","Q","R","S","T",
		  "U","V","W","X","Y","Z","a","b","c","d",
		  "e","f","g","h","i","j","k","l","m","n",
		  "o","p","q","r","s","t","u","v","w","x",
		  "y","z","!","#","$","%","&","(",")",
		  "*","+","-",".","/",":",";","<","=",">",
		  "?","@","^","_","{","}",
		};
		 --"y","z","!","#","$","%","&","'","(",")",
		--"?","@","[","]","^","_","{","}","~",
		
		self.digits[0] = "0";
		
		for i,v in ipairs(self.digits) do 
			self.rev[v] = i;
		end
		self.rev[ self.digits[0] ] = 0;
	end,
	
	Enc = function(self, number)
		local s = "";
		local remainder = 0;
		repeat
			remainder = math.mod(number,self.base);
			s = self.digits[remainder]..s;
			number = (number-remainder)/self.base;
		until number==0
		return s;	
	end,
	Dec = function(self, number)
		local num = 0;
		local sLen = string.len(number);
		for i=1,sLen do
			num = num + (self.rev[string.sub(number,i,i)]  * self.base ^ (sLen - i));
		end
		return num;	
	end,
};
]]--

-- reset 
-- 1.4.2 changed this it will only reset yourself if your A or L
-- and others will check if the sender is A or L
-- 1.5.beta.1 added a "force self reset" for completion on a reset vote
function SW_SyncReset(newSessID, issuedBy, selfForce)

	if newSessID ~= nil then 
		if issuedBy ~= nil then
			-- 1.5.3 very ralrely some events don't fire
			-- if sombody has an A or is L might not be known so added this
			-- drawback: somebody with A might have started RE, then had A revoked milliseconds after he sent the msg
			-- oh hell can't catch em all
			SW_RebuildFriendList();
		end
		if (issuedBy == nil and (time()-SW_SessIDTimer) < SW_SessIDTimerThresh) 
		or (issuedBy ~= nil and SW_Friends[issuedBy] ~= nil and SW_Friends[issuedBy].Rank > 0) then
			SW_SyncQueue.clearing = true;
			SW_ResetInfo(); 
			SW_S_DetailsSynced = {};
			SW_S_HealedSynced = {};
			SW_DCSynced = {};
			SW_ManaAfterDrop = {0,0,0};
			SW_SyncSessionID = tonumber(newSessID);
			SW_Settings["SYNCLastAction"] = time();
			SW_SyncQueue:Clear();
		end
	
	else
		if SW_Friends[SW_SELF_STRING].Rank > 0 or selfForce then
			SW_SyncQueue.clearing = true;
			SW_ResetInfo(); 
			SW_S_DetailsSynced = {};
			SW_S_HealedSynced = {};	
			SW_DCSynced = {};
			SW_ManaAfterDrop = {0,0,0};
			SW_SyncQueue:Clear();
			SW_SyncSessionID = SW_SyncSessionID + 1;
		end
		if SW_Friends[SW_SELF_STRING].Rank > 0 and (not selfForce) then
			SW_SyncQueue:PushSWInfo("RE");
		end
	end
	
	
end



--[[ 1.5 added this
	The old way wouldnt leave the channel and join a new one in the same funccall
--]]
local SW_PendingJoinInfo = {
	newChan = nil,
	isPassive = nil,
}
--[[ 
	if isPassive == true that person wont send sync msgs
	but can listen
	TODO testing 1.5.3 I noticed some messages do get sent - these are sent through "catch" functions when we 
	send data on a recieved data event, because these are so few not sure if a change is needed
--]]
function SW_SyncJoin(chanName, isPassive)
	if tonumber(chanName) then
		return;
	end
	local retName;
	local id;
	local oldSynarp;
	
	if chanName == nil then return; end
	SW_Timed_Calls:StopJoinChanPending();
	SW_Timed_Calls:StopCheckChan();
	--Stop the pump sending messages
	SW_SyncChanID = 0;
	
	oldSynarp = SW_Settings["SYNARP"];
	SW_Settings["SYNARP"] = nil;
	if SW_Settings["SYNCLastChan"] ~= nil then
		if SW_Settings["SYNCLastChan"] == chanName then
			-- are we still in this channel?
			id, _ = GetChannelName(chanName);
			if id ~= 0 then
				if SW_Settings["SYNCLastAction"] ~= nil and time() - SW_Settings["SYNCLastAction"]  < SW_SyncKeepTime then
					-- if we get here it was just a repost, for new members to join this chan
					SW_SyncChanID = id;
					SW_Settings["SYNARP"] = oldSynarp;
					return
				else 
					SW_printStr("Reset on Join LA:"..SW_Settings["SYNCLastAction"].." NOW:"..time());
				end
			end
		else
			SW_SyncQueue.clearing = true;
			--SW_DumpResultList(GetChannelList());
			LeaveChannelByName(SW_Settings["SYNCLastChan"]);			
		end
	end
	--SW_DumpResultList(GetChannelList());
	-- 1.5 leaving and joining while already in 10 channels where 1 is swtats didnt work.
	SW_PendingJoinInfo.newChan = chanName;
	SW_PendingJoinInfo.isPassive = isPassive;
	SW_Timed_Calls:StartJoinChanPending();
	
end
function SW_SyncJoinPending()
	local chanName = SW_PendingJoinInfo.newChan;
	if chanName == nil then return; end
	
	if SW_PendingJoinInfo.isPassive then
		SW_SyncPassiveMode = isPassive;
	end
	
	SW_SyncQueue.clearing = true;
	_, retName = JoinChannelByName(chanName);
	id, _ = GetChannelName(chanName);
	if id ~= 0 then
		SW_Settings["SYNCLastChan"] = chanName;
		SW_SessIDTimer = time();
		SW_SyncReset(1);
		SW_Settings["SYNCLastAction"] = time();
	else
		-- we werent able to join the chan
		SW_printStr(SW_SYNC_CHAN_FAIL..chanName, 1);
		SW_Settings["SYNCLastChan"] = nil;
	end	
	
	SW_SyncChanID = id;
	SW_PendingJoinInfo.newChan = nil;
	SW_PendingJoinInfo.isPassive = nil;
	SW_Timed_Calls:StartCheckChan();
end
function SW_SyncJoinedCheck()
	local chanName = SW_Settings["SYNCLastChan"];
	if chanName == nil then 
		return; 
	end
	if SW_SyncCheckInChan(chanName) then
		SW_printStr(SW_SYNC_CHAN_JOIN..chanName, 1);
		local sf =getglobal("SW_BarSyncFrame");
		-- refresh sync frame
		if sf:IsVisible() then
			sf:Hide()
			sf:Show()
		end
		-- be sure we arent paused
		SW_ToggleRunning(true);
		-- 1.5.3 show the sync icon
		SW_BarFrame1_Title_SyncIcon:Show();
		
	else
		SW_printStr(SW_SYNC_CHAN_FAIL..chanName, 1);
	end
end
function SW_SyncCheckInChan(chanName)
	local function Check(...)
		local i = 1;
		
		while arg[i] ~= nil do
			if arg[i] == chanName then return true; end
			i = i + 1;
		end
		return false;
	end
	if Check(GetChannelList()) then
		return true;
	else
		SW_SyncChanID = 0;
		SW_Settings["SYNCLastChan"] = nil;
		SW_Settings["SYNARP"] = nil;
		SW_BarFrame1_Title_SyncIcon:Hide();
		if chanName then
			SW_printStr("SW_SyncCheckInChan:False "..chanName);
		else
			SW_printStr("SW_SyncCheckInChan:False Name:NIL");
		end
		--SW_printStr(debugstack());
		return false;
	end 
end
function SW_SyncCheckMsgForChan(msg, who)
	local chan;
	
	_,_,chan = string.find(msg, SW_SYNC_CHAN_REGEX);
	
	if chan ~= nil and who~= nil and chan ~= SW_Settings["SYNCLastChan"] then
		StaticPopupDialogs["SW_JoinCheck"]["SW_toChan"] = chan;
		StaticPopupDialogs["SW_JoinCheck"]["SW_postedBy"] = who;
		StaticPopupDialogs["SW_JoinCheck"]["text"] = string.format(SW_SYNC_JOINCHECK_FROM, chan, who).."\n"..SW_SYNC_JOINCHECK_INFO;
		StaticPopup_Show ("SW_JoinCheck");

	end
end

function SW_SyncSplitMsg(msg)
	
  local t = {};
  local function helper(line) table.insert(t, line); end
  helper((string.gsub(msg, "(.-)%"..SW_SyncQueue.sep, helper)))
  
  return t
end

function SW_SyncCheckAlive()
	local now = time();
	for k,v in pairs(SW_S_DetailsSynced) do
		if v["LI"] ~= nil then
			if now - v["LI"] > SW_LITimerDead then
				v["LI"] = nil;
			end
		end
	end
	
	if SW_SyncPassiveMode then return; end
	if SW_S_DetailsSynced[SW_SELF_STRING] == nil or
		SW_S_DetailsSynced[SW_SELF_STRING]["LI"] == nil or
		time() - SW_S_DetailsSynced[SW_SELF_STRING]["LI"] > (SW_LITimerDead - 200) then
		
		SW_SyncQueue:PushSWInfo("LI");
	end
end
function SW_SyncHandleMsg(msg, from)
	local pre;
	
	--[[ this will inject even more wrong people if sombody is drunk.. (S->Sh) but
		most of the times people use filters, group, evergroup npc etc
		so these drop out anyways in the display
		but a lot of the info is most likely valid
		also this will suppress most unexpected ident msgs if somebody is drunk
	--]]
	if SLURRED_SPEECH ~= nil then
		_,_,pre = string.find(msg, SW_DrunkRegEx)
		if pre ~= nil then
			--SW_printStr(msg.."==>"..pre);
			msg = pre;
		end
	end
	local msgs = SW_SyncSplitMsg(msg);
	SW_Settings["SYNCLastAction"] = time();
	local v1,vx,vs,vi,v2,v3,vals,ident, tmpInt, iCount, sCount;
	--handels a single Sync Msg
	for __,oneLine in ipairs(msgs) do
		_,_,v1,vx,vs,vi,v2,v3 = string.find(oneLine, "^(%d+) (%d+) (%d+) (%d+) (.-) (.+)");
		--_,_,v1,v2,v3 = string.find(oneLine, "^(%d+) (.-) (.+)");
		if v1==nil or vx==nil or vs==nil or vi==nil or v2==nil or v3==nil then -- another wierd one that happens very rarely
			-- hmm this could happen if somebody types normal chat messages into the SyncChannel
			SW_printStr("SW_SyncHandleMsg NIL value FROM: "..from.." in Msg:");
			SW_printStr(oneLine);
			return;
		end
		vx = tonumber(vx);
		vs = tonumber(vs);
		vi = tonumber(vi);
		
		vals = {};
		for info in string.gfind(v3, "[^~]+") do
			table.insert(vals,info); 
		end
		if table.getn(vals) ~= vs+vi then
			SW_printStr("SW_SyncHandleMsg unexpected argument count FROM: "..from.." in Msg:");
			SW_printStr(oneLine);
			return;
		end
		
		ident = SW_SyncPepper[v2];
		if ident == nil then
			SW_printStr("SW_SyncHandleMsg unexpected type FROM: "..from.." in Msg:");
			SW_printStr(oneLine);
			return;
		end
		sCount=0;
		iCount=0;
		for i,v in ipairs(vals) do
			tmpInt = tonumber(v);
			if tmpInt == nil then
				sCount = sCount+1;
			else
				iCount=iCount+1;
				vals[i] = tmpInt;
				ident = ident + tmpInt;
			end
		end
		
		if sCount ~= vs or iCount ~= vi then
			SW_printStr("SW_SyncHandleMsg type missmatch FROM: "..from.." in Msg:");
			SW_printStr(oneLine);
			return;
		end
		-- can happen while leaving channel
		if SW_Settings["SYNCLastChan"] == nil then
			return;
		end
		tmpInt = math.floor(math.sqrt(ident * string.len(SW_Settings["SYNCLastChan"]))) * 1000;
		ident = math.floor(1000 * math.sqrt(ident * string.len(SW_Settings["SYNCLastChan"])));
		if ident-tmpInt ~= vx then
			SW_printStr("SW_SyncHandleMsg unexpected ident FROM: "..from.." in Msg:");
			SW_printStr(oneLine);
			return;
		end
		
		-- ignore "old" messages
		if tonumber(v1) < SW_SyncSessionID then 
			
			return; 
		end 
		-- 1.4.2 chganged reset logic 
		if tonumber(v1) > SW_SyncSessionID then
			if v2 == "RE" then
				SW_SyncReset(v1, from);
			else
				SW_SyncReset(v1);
			end
		else
			if SW_S_DetailsSynced[from] == nil then
				SW_S_DetailsSynced[from] = {};
			end
			SW_S_DetailsSynced[from]["LI"] = time();
			if v2 ~= "RE" then -- if == and RE we issued it and already did reset
				if SW_SyncMsgs[v2] ~= nil then
					SW_SyncMsgs[v2](vals, from);
				end
			end
		end
		
	end
end

function SW_GetValPair(name, subItem, S)
	if S == nil then return nil; end
	if S[name] == nil then --[[SW_printStr("NILCRAP "..name.." "..subItem);--]]  return 0,0; end
	if S[name][subItem] == nil then return 0,0; end
	
	 return S[name][subItem][1],S[name][subItem][2];
end
function SW_SetValPair(name, subItem, S, v1, v2)
	if S == nil then return nil; end
	if S[name] == nil then S[name]={}; end
	if S[name][subItem] == nil then S[name][subItem] = {}; end
	S[name][subItem][1] = v1;
	S[name][subItem][2] = v2;
end
function SW_GetVal(name, subItem, S)
	if S == nil then return nil; end
	if S[name] == nil then return 0; end
	if S[name][subItem] == nil then return 0; end
	
	 return S[name][subItem];
end
function SW_SetVal(name, subItem, S, v)
	if S == nil then return nil; end
	if S[name] == nil then S[name]={}; end
	
	S[name][subItem] = v; 
	
end
function SW_SyncDo()
	if SW_Settings["SYNCLastChan"] == nil and SW_SyncChanID ==0 then
		return; 
	end
	if not SW_SyncCheckInChan(SW_Settings["SYNCLastChan"]) then
		return;
	end
	if SW_SyncPassiveMode then return; end
	
	SW_SyncDoOne(SW_SELF_STRING, true);
	SW_SyncDoHeal(SW_SELF_STRING, true);
	SW_SyncDoMana();
	
	local SW_SyncP = 0;
	
	local rnd;
	local peerCount =0;
	for k,v in pairs(SW_S_DetailsSynced) do
		if SW_S_DetailsSynced[k]["LI"] ~= nil then
			peerCount = peerCount +1;
		end
	end
	--auto% when to sync 
	if peerCount > 5 then
		SW_SyncP = math.ceil( (100 / peerCount) / 2 );
	else 
		-- nonsense to post when alone but i use it for testing
		SW_SyncP = 10;
	end
	
	for k,v in pairs(SW_S_Details) do
		rnd = math.random(100);
		
		if k ~= SW_SELF_STRING and rnd <= SW_SyncP then
			if SW_S_DetailsSynced[k] == nil then
				SW_SyncDoOne(k, false);
			else
				if SW_S_DetailsSynced[k]["LI"] == nil then
					SW_SyncDoOne(k, false);
				end
			end
		end
	end
	for k,v in pairs(SW_S_Healed) do
		rnd = math.random(100);
		if k ~= SW_SELF_STRING and rnd <= SW_SyncP then
			if SW_S_HealedSynced[k] == nil then
				SW_SyncDoHeal(k, false);
			else
				-- only tracking "alive" in SW_S_DetailsSynced
				if SW_S_DetailsSynced[k] == nil or SW_S_DetailsSynced[k]["LI"] == nil then
					SW_SyncDoHeal(k, false);
				end
			end
		end
	end
	for k,v in pairs(SW_PetInfo["PET_OWNER"]) do
		rnd = math.random(100);
		
		if rnd <= SW_SyncP or (v["currentOwners"] and v["currentOwners"][SW_SELF_STRING]) then
			SW_SyncDoOnePet(k);
		end
	end
	for k,v in pairs(SW_PetInfo["OWNER_PET"]) do
		rnd = math.random(100);
		
		if rnd <= SW_SyncP or k == SW_SELF_STRING then
			SW_SyncDoOnePetOwner(k);
		end
	end
	for k,v in pairs(SW_S_SpellInfo) do
		rnd = math.random(100);
		if rnd <= SW_SyncP or k == SW_SELF_STRING then
			SW_SyncDoOneDecurseCount(k);
		end
	end
end

-- only do self
function SW_SyncDoMana()
	if SW_S_ManaUsage ~= nil and SW_S_ManaUsage[SW_SELF_STRING] ~= nil then
		
		local v = SW_S_ManaUsage[SW_SELF_STRING];
		if v[1] > 0 or v[2] > 0 then
		    if SW_S_LastManaSent[1] < v[1] or SW_S_LastManaSent[2] < v[2] or SW_S_LastManaSent[3] < v[3] then 
				SW_S_LastManaSent[1] = v[1];
				SW_S_LastManaSent[2] = v[2];
				SW_S_LastManaSent[3] = v[3];
				SW_SyncQueue:PushSWInfo("MI", {SW_ManaAfterDrop[1] + v[1],SW_ManaAfterDrop[2] + v[2],SW_ManaAfterDrop[3] + v[3]});
			end
		end
	end
end
function SW_SyncDoHeal(name, isSelf)
	local hi = SW_S_Healed[name];
	if hi == nil then return; end
	
	local hiSync = SW_S_HealedSynced[name];
	if hiSync == nil and time() - SW_StartupTime  < SW_SyncIgnoreNil then
		return;
	end
	for k,v in hi do 
		if hiSync == nil or hiSync[k] == nil or v > hiSync[k] then
			if isSelf then
				SW_SyncQueue:PushSWInfo("HIS", {k, v});
			else
				SW_SyncQueue:PushSWInfo("HIO", {name, k, v});
			end	
		end
	end
end

function SW_SyncDoOne(name, isSelf)
	local doneDmg, doneHeal = SW_GetValPair(name, SW_PRINT_ITEM_TOTAL_DONE, SW_S_Details);
	local gotDmg, gotHeal = SW_GetValPair(name, SW_PRINT_ITEM_RECIEVED, SW_S_Details);
	local doneDmgS, doneHealS = SW_GetValPair(name, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced);
	local gotDmgS, gotHealS = SW_GetValPair(name, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced);

	SW_SyncDoOneDeathCount(name);
	
	if doneDmg > doneDmgS or doneHeal > doneHealS or
		gotDmg > gotDmgS or gotHeal > gotHealS then
		if isSelf then
			SW_SyncQueue:PushSWInfo("SI", {doneDmg, doneHeal, gotDmg, gotHeal});
		else
			if time() - SW_StartupTime  < SW_SyncIgnoreNil then
				if doneDmgS == 0 and doneHealS == 0 and gotDmgS == 0 and gotHealS == 0 then
					return;
				end
			end
			SW_SyncQueue:PushSWInfo("OI", {name, doneDmg, doneHeal, gotDmg, gotHeal});
		end
	end
end
function SW_SyncDoOneDeathCount(name)
	local syDeaths = SW_DCSynced[name];
	if syDeaths == nil then
		syDeaths = 0;
	end
	if time() - SW_StartupTime  < SW_SyncIgnoreNil then
		if syDeaths == 0 then
			return;
		end
	end
	local tmpVal = SW_S_Details[name];
	if tmpVal ~= nil and tmpVal[SW_PRINT_ITEM_DEATHS] ~= nil then
		tmpVal = tmpVal[SW_PRINT_ITEM_DEATHS];
		if tmpVal > syDeaths then
			SW_SyncQueue:PushSWInfo("DC", {name, tmpVal, math.random(100)});
		end
	end
end
function SW_SyncDeathCount(data, from)
	local name, newDC, id = unpack(data);
	local syDeaths = SW_DCSynced[name];
	if syDeaths == nil or newDC > syDeaths then
		SW_DCSynced[name] = newDC;	
	end
	syDeaths = SW_DCSynced[name];
	local tmpVal = SW_S_Details[name];
	if tmpVal ~= nil then
		if tmpVal[SW_PRINT_ITEM_DEATHS] == nil or tmpVal[SW_PRINT_ITEM_DEATHS] < syDeaths then
			tmpVal[SW_PRINT_ITEM_DEATHS] = syDeaths;
		end
	end
	
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("Info from "..from.." for DeathCount of "..name..": "..newDC);
	end
end
function SW_SyncDoOneDecurseCount(name)
	local syDecs = SW_DecurseCSynced[name];
	if syDecs == nil then
		syDecs = 0;
	end
	
	if time() - SW_StartupTime  < SW_SyncIgnoreNil then
		if syDecs == 0 then
			return;
		end
	end
	
	local tmpVal = SW_S_SpellInfo[name];
	if tmpVal ~= nil and tmpVal[SW_DECURSEDUMMY] ~= nil and tmpVal[SW_DECURSEDUMMY]["total"] ~= nil then
		tmpVal = tmpVal[SW_DECURSEDUMMY]["total"];
		if tmpVal~=nil and tmpVal > syDecs then
			SW_SyncQueue:PushSWInfo("DCC", {name, tmpVal, math.random(100)});
		end
	end
	
end
function SW_SyncDecurseCount(data, from)
	local name, newDCC, id = unpack(data);
	local syDecs = SW_DecurseCSynced[name];
	if syDecs == nil or newDCC > syDecs then
		SW_DecurseCSynced[name] = newDCC;	
	end
	syDecs = SW_DecurseCSynced[name];
	local tmpVal;
	if SW_S_SpellInfo[name] == nil then
		SW_S_SpellInfo[name] = {};
	end
	if SW_S_SpellInfo[name][SW_DECURSEDUMMY] == nil then
		SW_S_SpellInfo[name][SW_DECURSEDUMMY] = {};
	end
	tmpVal = SW_S_SpellInfo[name][SW_DECURSEDUMMY];
	if tmpVal["total"] == nil then
		tmpVal["total"] = 0;
	end
	
	if tmpVal["total"] < syDecs then
		tmpVal["total"] = syDecs;
	end
	
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("Info from "..from.." for DecurseCount of "..name..": "..newDCC);
	end
end

function SW_SyncDoOnePetOwner(name)
	local doneDmg, doneHeal = SW_GetValPair(name, SW_PRINT_ITEM_TOTAL_DONE, SW_PetInfo["OWNER_PET"]);
	local gotDmg, gotHeal = SW_GetValPair(name, SW_PRINT_ITEM_RECIEVED, SW_PetInfo["OWNER_PET"]);
	local doneDmgS, doneHealS = SW_GetValPair(SW_PETOWNER..name, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced);
	local gotDmgS, gotHealS = SW_GetValPair(SW_PETOWNER..name, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced);

	if doneDmg > doneDmgS or doneHeal > doneHealS or
		gotDmg > gotDmgS or gotHeal > gotHealS then
		if time() - SW_StartupTime  < SW_SyncIgnoreNil then
			if doneDmgS == 0 and doneHealS == 0 and gotDmgS == 0 and gotHealS == 0 then
				return;
			end
		end
		SW_SyncQueue:PushSWInfo("PO", {name, doneDmg, doneHeal, gotDmg, gotHeal});
	end
end

function SW_SyncDoOnePet(name)
	local doneDmg, doneHeal = SW_GetValPair(name, SW_PRINT_ITEM_TOTAL_DONE, SW_PetInfo["PET_OWNER"]);
	local gotDmg, gotHeal = SW_GetValPair(name, SW_PRINT_ITEM_RECIEVED, SW_PetInfo["PET_OWNER"]);
	local doneDmgS, doneHealS = SW_GetValPair(SW_PET..name, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced);
	local gotDmgS, gotHealS = SW_GetValPair(SW_PET..name, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced);

	if doneDmg > doneDmgS or doneHeal > doneHealS or
		gotDmg > gotDmgS or gotHeal > gotHealS then
		if time() - SW_StartupTime  < SW_SyncIgnoreNil then
			if doneDmgS == 0 and doneHealS == 0 and gotDmgS == 0 and gotHealS == 0 then
				return;
			end
		end
		SW_SyncQueue:PushSWInfo("PI", {name, doneDmg, doneHeal, gotDmg, gotHeal});
	end
end
function SW_SyncPetOwner(data, from)
local name, doneDmgS, doneHealS, gotDmgS, gotHealS = unpack(data);
	local syncName = SW_PETOWNER..name;
	
	
	local doneDmg, doneHeal = SW_GetValPair(name, SW_PRINT_ITEM_TOTAL_DONE, SW_PetInfo["OWNER_PET"]);
	local gotDmg, gotHeal = SW_GetValPair(name, SW_PRINT_ITEM_RECIEVED, SW_PetInfo["OWNER_PET"]);
	
	local doneDmgSync, doneHealSync = SW_GetValPair(syncName, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced);
	local gotDmgSync, gotHealSync = SW_GetValPair(syncName, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced);
	
	
	
	if doneDmgS > doneDmgSync or doneHealS > doneHealSync then
		SW_SetValPair(syncName, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced, doneDmgS, doneHealS);
	end
	if gotDmgS > gotDmgSync or gotHealS > gotHealSync then
		SW_SetValPair(syncName, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced, gotDmgS, gotHealS);
	end
	
	local v1, v2;
	if doneDmgS > doneDmg then v1 = doneDmgS; else v1 = doneDmg; end
	if doneHealS > doneHeal then v2 = doneHealS; else v2 = doneHeal; end
	SW_SetValPair(name, SW_PRINT_ITEM_TOTAL_DONE, SW_PetInfo["OWNER_PET"], v1, v2);
	
	if gotDmgS > gotDmg then v1 = gotDmgS; else v1 = gotDmg; end
	if gotHealS > gotHeal then v2 = gotHealS; else v2 = gotHeal; end
	SW_SetValPair(name, SW_PRINT_ITEM_RECIEVED, SW_PetInfo["OWNER_PET"], v1, v2);
	
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("Info from "..from.." for PETOWNER "..name.." "..doneDmgS.." "..doneHealS.." "..gotDmgS.." "..gotHealS);
	end
	
end

function SW_SyncPetInfo(data, from)
	local name, doneDmgS, doneHealS, gotDmgS, gotHealS = unpack(data);
	local syncName = SW_PET..name;
	
	
	local doneDmg, doneHeal = SW_GetValPair(name, SW_PRINT_ITEM_TOTAL_DONE, SW_PetInfo["PET_OWNER"]);
	local gotDmg, gotHeal = SW_GetValPair(name, SW_PRINT_ITEM_RECIEVED, SW_PetInfo["PET_OWNER"]);
	
	local doneDmgSync, doneHealSync = SW_GetValPair(syncName, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced);
	local gotDmgSync, gotHealSync = SW_GetValPair(syncName, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced);
	
	
	
	if doneDmgS > doneDmgSync or doneHealS > doneHealSync then
		SW_SetValPair(syncName, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced, doneDmgS, doneHealS);
	end
	if gotDmgS > gotDmgSync or gotHealS > gotHealSync then
		SW_SetValPair(syncName, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced, gotDmgS, gotHealS);
	end
	
	local v1, v2;
	if doneDmgS > doneDmg then v1 = doneDmgS; else v1 = doneDmg; end
	if doneHealS > doneHeal then v2 = doneHealS; else v2 = doneHeal; end
	SW_SetValPair(name, SW_PRINT_ITEM_TOTAL_DONE, SW_PetInfo["PET_OWNER"], v1, v2);
	
	if gotDmgS > gotDmg then v1 = gotDmgS; else v1 = gotDmg; end
	if gotHealS > gotHeal then v2 = gotHealS; else v2 = gotHeal; end
	SW_SetValPair(name, SW_PRINT_ITEM_RECIEVED, SW_PetInfo["PET_OWNER"], v1, v2);
	
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("Info from "..from.." for PET "..name.." "..doneDmgS.." "..doneHealS.." "..gotDmgS.." "..gotHealS);
	end
	
end

function SW_SyncBasicInfo(data, from, isSelf)
	local doneDmgS, doneHealS, gotDmgS, gotHealS = unpack(data);
	local isSelfStr ="";
	local buffedDmg, buffedHeal;
	
	if from == nil then 
		SW_Event_Channel:AddMessage("From:NIL");
		return;
	end
	if isSelf then
		isSelfStr = " IsSelf ";
	else
		isSelfStr = " IsOther ";
	end
	if doneDmgS == nil then
		SW_Event_Channel:AddMessage("From:"..from..isSelfStr.."doneDmgS == NIL: "..data);
		return;
	elseif doneHealS == nil then
		SW_Event_Channel:AddMessage("From:"..from..isSelfStr.."doneHealS == NIL: "..data);
		return;
	elseif gotDmgS == nil then
		SW_Event_Channel:AddMessage("From:"..from..isSelfStr.."gotDmgS == NIL: "..data);
		return;
	elseif gotHealS == nil then
		SW_Event_Channel:AddMessage("From:"..from..isSelfStr.."gotHealS == NIL: "..data);
		return;
	end
	
	local doneDmg, doneHeal = SW_GetValPair(from, SW_PRINT_ITEM_TOTAL_DONE, SW_S_Details);
	local gotDmg, gotHeal = SW_GetValPair(from, SW_PRINT_ITEM_RECIEVED, SW_S_Details);
	--check here if somebody came back after a "reset" (he was disconnected to long)
	if isSelf and from ~= SW_SELF_STRING and (doneDmgS < doneDmg or doneHealS < doneHeal ) then
		-- this will trigger a message from every player with the addon installed
		-- maybe find a better way (but this doesnt happen on a regular basis)
		-- also the first few "ticks" of selfinfo are lost but ist very little compared to total stats
		-- and maybe somebody else even got those msgs and we ar totally correct
		--RC5 Changed this.. generated a LOT of chat spam only issue an update like this if its heihger then SW_ValBuffer %
		-- could happen because of the chat send delay + chat delay, somebody sent info
		-- that was correct but it arrived 2 seconds later and this would trigger this aswell

		buffedDmg = ((doneDmgS/100) * SW_ValBuffer) + doneDmgS;
		buffedHeal = ((doneHealS/100) * SW_ValBuffer) + doneHealS;
		if buffedDmg < doneDmg or buffedHeal < doneHeal then
			if not SW_SyncPassiveMode then
				--1.5.3 after a reset this would generate unneded msgs
				-- added a delta val buffer depending on the level
				if SW_Friends[from] ~= nil and SW_Friends[from]["L"] ~= nil and SW_Friends[from]["L"] > 0 then
					local minVal = SW_Friends[from]["L"] * 100;
					if ((doneDmgS + minVal) < doneDmg) or ((doneHealS + minVal) < doneHeal) then
						SW_SyncQueue:PushSWInfo("OI", {from, doneDmg, doneHeal, gotDmg, gotHeal});
					end
				else
					-- still have this here for sync to work as expected for people that aren't grouped
					SW_SyncQueue:PushSWInfo("OI", {from, doneDmg, doneHeal, gotDmg, gotHeal});
				end
			end
		end
		return;
	end
	
	local doneDmgSync, doneHealSync = SW_GetValPair(from, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced);
	local gotDmgSync, gotHealSync = SW_GetValPair(from, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced);
	
	local topDelta =0;
	if isSelf and (doneDmgSync > 0) then
		topDelta = doneDmgS - doneDmgSync;
		if SW_Sync_MsgTrack[from]["TOPDELTAD"] < topDelta then
			SW_Sync_MsgTrack[from]["TOPDELTAD"] = topDelta;
		end
	end
	if isSelf and (doneHealSync > 0) then
		topDelta = doneHealS - doneHealSync;
		if SW_Sync_MsgTrack[from]["TOPDELTAH"] < topDelta then
			SW_Sync_MsgTrack[from]["TOPDELTAH"] = topDelta;
		end
	end
	
	--0.98 no need to update lower info in synced
	if doneDmgS > doneDmgSync or doneHealS > doneHealSync then
		SW_SetValPair(from, SW_PRINT_ITEM_TOTAL_DONE, SW_S_DetailsSynced, doneDmgS, doneHealS);
	end
	if gotDmgS > gotDmgSync or gotHealS > gotHealSync then
		SW_SetValPair(from, SW_PRINT_ITEM_RECIEVED, SW_S_DetailsSynced, gotDmgS, gotHealS);
	end
	
	local v1, v2, sIInced=false;
	if doneDmgS > doneDmg then 
		v1 = doneDmgS; 
		if isSelf then
			SW_Sync_MsgTrack[from]["SI_WAS_NEEDED"] = SW_Sync_MsgTrack[from]["SI_WAS_NEEDED"] + 1;
			sIInced=true;
		end
	else 
		v1 = doneDmg; 
	end
	if doneHealS > doneHeal then 
		v2 = doneHealS; 
		if isSelf and (not sIInced) then
			SW_Sync_MsgTrack[from]["SI_WAS_NEEDED"] = SW_Sync_MsgTrack[from]["SI_WAS_NEEDED"] + 1;
			sIInced=true;
		end
	else 
		v2 = doneHeal; 
	end
	
	SW_SetValPair(from, SW_PRINT_ITEM_TOTAL_DONE, SW_S_Details, v1, v2);
	
	if gotDmgS > gotDmg then v1 = gotDmgS; else v1 = gotDmg; end
	if gotHealS > gotHeal then v2 = gotHealS; else v2 = gotHeal; end
	
	-- 1.5.3 raid per second 
	-- an SI with dmg is valid 
	if isSelf and (doneDmgS > doneDmg) then
		SW_RPS:validEvent();
	end
	SW_SetValPair(from, SW_PRINT_ITEM_RECIEVED, SW_S_Details, v1, v2);
	
	if SW_Settings["EI_ShowSync"] ~= nil then
		if isSelf then
			SW_Event_Channel:AddMessage("SelfInfo for "..from.." "..doneDmgS.." "..doneHealS.." "..gotDmgS.." "..gotHealS);
		else
			SW_Event_Channel:AddMessage("Info for "..from.." "..doneDmgS.." "..doneHealS.." "..gotDmgS.." "..gotHealS);
		end
	end
	
end

function SW_checkSIOI()
	local vals = {};
	for k, v in pairs (SW_Sync_MsgTrack) do
		if v["OI_UPDATE_SI"] > 0 then
			table.insert(vals, {k, v["OI_UPDATE_SI"]});
		end
	end
	table.sort(vals, 
			function(a,b)
				return a[2] > b[2];
			end);	
	return vals;
end
function SW_checkSINeeded()
	local vals = {};
	for k, v in pairs (SW_Sync_MsgTrack) do
		if v["SI_WAS_NEEDED"] > 0 then
			table.insert(vals, {k, v["SI_WAS_NEEDED"]});
		end
	end
	table.sort(vals, 
			function(a,b)
				return a[2] > b[2];
			end);	
	return vals;
end
function SW_updateMsgTrack(from, isOI, data)
	if SW_Sync_MsgTrack[from] == nil then
		SW_Sync_MsgTrack[from] = {["OI"] = 0, ["SI"] = 0, ["OI_UPDATE_SI"] = 0, ["SI_WAS_NEEDED"] = 0, ["TOPDELTAD"] = 0, ["TOPDELTAH"] = 0};
	end
	if isOI then
		if SW_S_DetailsSynced[ data[1] ] and SW_S_DetailsSynced[ data[1] ]["LI"] ~= nil then
			SW_Sync_MsgTrack[from]["OI_UPDATE_SI"] = SW_Sync_MsgTrack[from]["OI_UPDATE_SI"] + 1;
		else
			SW_Sync_MsgTrack[from]["OI"] = SW_Sync_MsgTrack[from]["OI"] + 1;
		end
	else
		SW_Sync_MsgTrack[from]["SI"] = SW_Sync_MsgTrack[from]["SI"] + 1;
	end	
end
function SW_SyncSelfInfo(data, from)
	SW_updateMsgTrack(from, false, data);
	SW_SyncBasicInfo(data, from, true);
end
function SW_SyncOtherInfo(data, from)
	--local _,_,nameFrom, restData = string.find(data, "^~(.-)~ (.+)");
	--SW_SyncBasicInfo(restData, nameFrom, false);
	SW_updateMsgTrack(from, true, data);
	
	local name = data[1];
	table.remove(data, 1);
	SW_SyncBasicInfo(data, name, false);
end
function SW_SyncSendARP(allow)
	if UnitInRaid("player") and not (IsRaidLeader() or IsRaidOfficer()) then
		return;
	end
	if allow then
		SW_SyncQueue:PushSWInfo("ARP", {"true", math.random(100)});
	else
		SW_SyncQueue:PushSWInfo("ARP", {"false", math.random(100)});
	end
end
function SW_SyncAllowReport(data, from)
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("Allow Report "..data[1].." from "..from);
	end
	if data[1] == "true" then
		SW_Settings["SYNARP"] = true;
	else
		SW_Settings["SYNARP"] = nil;
	end
end
function SW_SyncManaInfo(data, from)
	if from ~= SW_SELF_STRING then
		if SW_S_ManaUsage[from] ~= nil then
			if data[3] < SW_S_ManaUsage[from][3] then
				--the sender dropped, alt+f4d etc.
				-- this isn't time critical and we don't want a huge spam when somebody comes back
				-- so just make it a 20% chance
				local rnd = math.random(100);
				if rnd < 20 then
					local mu = SW_S_ManaUsage[from];
					SW_SyncQueue:PushSWInfo("MIO", {from, mu[1], mu[2], mu[3]});
				end
			else
				SW_S_ManaUsage[from] = {unpack(data)};
			end
		else
			SW_S_ManaUsage[from] = {unpack(data)};
		end
	end
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("ManaInfo from "..from.." "..data[1].." "..data[2].." "..data[3]);
	end
end

function SW_SyncManaInfoOther(data, from)
	
	--this happens when we posten a self mana info and somebody in the SyncChannel 
	-- had a higher value stored, we dropped or alt+f4'd etc
	if data[1] == SW_SELF_STRING then
		local tp, m1, m2, m3 = unpack(data);
		local m1o, m2o, m3o = unpack(SW_ManaAfterDrop);
		if m3 > m3o then
			SW_ManaAfterDrop = {m1,m2,m3};
		end
	end
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("ManaInfoOther from "..from.." for "..data[1].." "..data[2].." "..data[3].." "..data[4]);
	end
	
end
function SW_SyncAlive(data, from)
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("LI from "..from);
	end
	
	-- nothing really to do here
end

-- 0.98 heal info details (who healed who)
function SW_SyncHealInfo(healer, healTarget, amount, isSelf)
	
	healed = SW_GetVal(healer, healTarget, SW_S_Healed);
	healedSync = SW_GetVal(healer, healTarget, SW_S_HealedSynced);
	
	--the person posting self info dropped
	if isSelf and healer ~= SW_SELF_STRING and amount < healed then
		--SW_SyncQueue:Push(SW_SyncSessionID.." HIO ~"..healer.."~ ~"..healTarget.."~ "..healed);
		if ((amount/100) * SW_ValBuffer) + amount < healed then
			SW_SyncQueue:PushSWInfo("HIO", {healer, healTarget, healed});
		end
		return;
	end
	
	if amount > healedSync then
		SW_SetVal(healer, healTarget, SW_S_HealedSynced, amount);
	end
	if healed < amount then
		SW_SetVal(healer, healTarget, SW_S_Healed, amount);
	end
	if SW_Settings["EI_ShowSync"] ~= nil then
		if isSelf then
			SW_Event_Channel:AddMessage("SelfInfo "..healer.." healed "..healTarget.." "..amount);
		else
			SW_Event_Channel:AddMessage("Info "..healer.." healed "..healTarget.." "..amount);
		end
	end
end
function SW_SyncSendLeave()
	if SW_Settings["SYNCLastChan"] ~= nil then
		SW_SyncQueue:Clear();
		SW_SyncQueue:PushSWInfo("LS");
		SW_SyncLeavingChannel = true;
	end
end
function SW_SyncHealInfoOther(data, from)
	local nameFrom, nameTo, amount = unpack(data);
	
	SW_SyncHealInfo(nameFrom, nameTo, amount, false);
end
function SW_SyncHealInfoSelf(data, from)
	local nameTo, amount = unpack(data);
	SW_SyncHealInfo(from, nameTo, amount, true);
end
function SW_SyncRequestFullSync()
	--SW_SyncQueue:Push(SW_SyncSessionID.." FS "..SW_SyncSessionID);
	SW_SyncQueue:PushSWInfo("FS");
end
--0.98b added full sync 
--1.5 removed the console sommand to acces this
-- it's just nbot needed in the current form
function SW_SyncFullSync(nop, from)
	-- A full sync.. never ever do in fight.....
	if from == SW_SELF_STRING then
		--this works but not sure if i want it
		-- idea is that the requestor sends out all his info
		SW_S_DetailsSynced = {};
		SW_S_HealedSynced = {};
	end
	for k,v in pairs(SW_S_Details) do 
		if k == SW_SELF_STRING then
			SW_SyncDoOne(k, true);
		else
			SW_SyncDoOne(k, false);
		end
	end
	for k,v in pairs(SW_S_Healed) do 
		if k == SW_SELF_STRING then
			SW_SyncDoHeal(k, true);
		else
			SW_SyncDoHeal(k, false);
		end
	end
end
function SW_SyncLeave(data, from)
	if SW_S_DetailsSynced[from] ~= nil then
		SW_S_DetailsSynced[from]["LI"] = nil; 
	end
end

function SW_SyncSendRSU(skillName)
	SW_SyncQueue:PushSWInfo("RSU", {skillName, math.random(100)});
end
function SW_SyncRequestSkillUsage(data, from)
	
	if SW_S_SpellInfo[SW_SELF_STRING] ~= nil and SW_S_SpellInfo[SW_SELF_STRING][ data[1] ] ~= nil then
		SW_SyncQueue:PushSWInfo("SU", {data[1], SW_S_SpellInfo[SW_SELF_STRING][ data[1] ][1], math.random(100)});
	end
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("Request Skill Usage from "..from.." for Skill "..data[1]);
	end
end

function SW_SyncSkillUsage(data, from)
	SW_printStr("["..date("%X").."] "..LIGHTYELLOW_FONT_COLOR_CODE..from..FONT_COLOR_CODE_CLOSE.." "..data[1]..":"..RED_FONT_COLOR_CODE..data[2]..FONT_COLOR_CODE_CLOSE);
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("Skill Usage  "..from.." for Skill "..data[1]..":"..data[2]);
	end
end

-- added 1.4 version check stuff  
function SW_SyncSendRSV()
	SW_SyncQueue:PushSWInfo("RSV", {math.random(100)});
end
function SW_SyncRequestVersionCheck(data, from)

	SW_SyncQueue:PushSWInfo("SV", {SW_VERSION, GetLocale(), math.random(100)});
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("Request Version info from "..from);
	end
end
function SW_SyncVersionCheck(data, from)
	if data[2] ~= nil and tonumber(data[2]) then
		SW_printStr("["..date("%X").."] "..from.." "..RED_FONT_COLOR_CODE..data[1]..FONT_COLOR_CODE_CLOSE);
	else
		SW_printStr("["..date("%X").."] "..from.." "..RED_FONT_COLOR_CODE..data[1]..FONT_COLOR_CODE_CLOSE.." ("..data[2]..")");
	end
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("V  "..from..": "..data[1].." "..data[2]);
	end
end
-- added 1.4 kicking people from the sync chan
-- usefull if somebody left the raid/group and is still playing
function SW_SyncKick(data, from)
	if SW_Settings["EI_ShowSync"] ~= nil then
		SW_Event_Channel:AddMessage("KICK from "..from.." for: "..data[1]);
	end
	SW_printStr("["..date("%X").."] KICK from "..from.." for:"..RED_FONT_COLOR_CODE..data[1]..FONT_COLOR_CODE_CLOSE);
	if data[1] == SW_SELF_STRING then
		SW_SyncSendLeave();
	end
end
function SW_SendSyncKick(who)
	SW_SyncQueue:PushSWInfo("KI", {who, math.random(100)});
end

function SW_SyncGetLIs()
	local out = {};
	local SW_PC = 0;
	
	for k,v in pairs(SW_S_DetailsSynced) do
		if SW_S_DetailsSynced[k]["LI"] ~= nil then
			SW_PC = SW_PC +1;
			out[k] = 1;
		end
	end
	out["SW_PC"] = SW_PC;
	return out;
end

function SW_SyncInit()
	-- use "base 89"
	-- had nil problems usinglower base to see if it fixes that
	-- turned off compression alltogether for now
	--SW_SyncInt:Init(84);
	
	SW_SyncMsgs ={
		["RE"] = SW_SyncReset,
		["OI"] = SW_SyncOtherInfo,
		["SI"] = SW_SyncSelfInfo,
		["LI"] = SW_SyncAlive,
		["HIO"] = SW_SyncHealInfoOther,
		["HIS"] = SW_SyncHealInfoSelf,
		["FS"] = SW_SyncFullSync,
		["LS"] = SW_SyncLeave,
		["MI"] = SW_SyncManaInfo,
		["MIO"] = SW_SyncManaInfoOther,
		["ARP"] = SW_SyncAllowReport,
		["RSU"] = SW_SyncRequestSkillUsage,
		["SU"] = SW_SyncSkillUsage,
		["RSV"] = SW_SyncRequestVersionCheck,
		["SV"] = SW_SyncVersionCheck,
		["KI"] = SW_SyncKick,
		["PI"] = SW_SyncPetInfo,
		["PO"] = SW_SyncPetOwner,
		["DC"] = SW_SyncDeathCount,
		["IV"] = SW_SyncIssuedVote,
		["IVA"] = SW_SyncIssuedVoteAnswer,
		["VA"] = SW_SyncVoteAnswer,
		["DCC"] = SW_SyncDecurseCount,
		
	};
	SW_SyncPepper ={
		["RE"] = 3985,
		["OI"] = 9724,
		["SI"] = 9967,
		["LI"] = 5391,
		["HIO"] = 8549,
		["HIS"] = 3941,
		["FS"] = 7105,
		["LS"] = 6418,
		["MI"] = 8256,
		["MIO"] = 9601,
		["ARP"] = 4215,
		["RSU"] = 1098,
		["SU"] = 7209,
		["RSV"] = 5780,
		["SV"] = 3009,
		["KI"] = 6105,
		["PI"] = 2193,
		["PO"] = 6623,
		["DC"] = 1043,
		["IV"] = 8312,
		["IVA"] = 3104,
		["VA"] = 8858,
		["DCC"] = 5103,
	};
	
end