Quantcast
-- to move here: Share stuff, Exchange stuff
local	KarmaObj = KarmaAvEnK;
local	KCfg = KarmaObj.Cfg;
local	KOH = KarmaObj.Helpers;
local	KSlash = KarmaObj.Slash;

local	KARMA_DB_L4_RRFF =
	{
			-- used subset
			MEMBERBUCKETS = "MEMBERBUCKETS",
	};

local	KARMA_DB_L5_RRFFM =
	{
			LEVEL = "LEVEL",
			CLASS_ID = "CLSID",
			CLASS = "CLASS",
			RACE = "RACE",
	};

local	KARMA_DB_L5_RRFFM_KARMA_TRUST = "K_TRUST";
local	KARMA_DB_L5_RRFFM_KARMA_IMPORTED = "K_IMP";

local	KARMA_EXCHANGE = {
			ENABLED_WITH = nil,

			START_WITH = nil,
			START_FRAG = nil,
			START_AT = nil,

			REQ_IS = nil,
			REQ_AT = nil,

			ACK_IS = nil,
			ACK_AT = nil,

			FIRST = nil,
			COUNT = nil,
			DONE = nil
		};

local	function	Karma_ExchangeAllow(args)
	if (args[2] == nil) or (args[2] == "") then
		if (KARMA_EXCHANGE.ENABLED_WITH ~= nil) then
			KarmaChatDefault("Player >" .. KARMA_EXCHANGE.ENABLED_WITH .. "< is now not anymore allowed to pull Karma values...");
		end
		KARMA_EXCHANGE.ENABLED_WITH = nil;
	else
		KARMA_EXCHANGE.ENABLED_WITH = args[2];
		KarmaChatDefault("Player >" .. args[2] .. "< is at the moment allowed to pull Karma values...");
	end
end

local	function	Karma_ExchangeRequest(args)
	if (KARMATRANS_AVAILABLE ~= 1) or (type(KarmaForeign) ~= "table") then
		-- TODO: xlate
		KarmaChatDefault("KarmaTrans must be enabled for a large exchange...");
		return;
	end

	if (args[2] == nil) or (args[2] == "") then
		KarmaChatDefault("Missing arguments: <player> [<alphabetic character to begin with>]");
		return;
	end

	local	sRequest = "?x1:";
	if (args[3] ~= nil) then
		if (strlen(args[3]) ~= 1) or (strfind(KARMA_ALPHACHARS, args[3]) == nil) then
			KarmaChatDefault("Additional argument invalid: [<alphabetic character to begin with>] (must be in range of A to Z)");
			return;
		else
			sRequest = sRequest .. args[3] .. "*";
		end
	else
		if (KarmaTrans_ForeignKarmaContinueWithGet ~= nil) then
			local	sServer, sFaction, sName;
			sServer = GetCVar("realmName");
			sFaction = UnitFactionGroup("player");
			local	sName = KarmaTrans_ForeignKarmaContinueWithGet(sServer, sFaction, args[2]);
			if (sName) then
				sRequest = sRequest .. sName;
			end
		end
	end

	KARMA_EXCHANGE.START_WITH = args[2];
	KARMA_EXCHANGE.START_FRAG = strsub(sRequest, 5);
	KARMA_EXCHANGE.START_AT = GetTime();

	KARMA_EXCHANGE.REQ_IS = KARMA_EXCHANGE.START_FRAG;
	KARMA_EXCHANGE.REQ_AT = GetTime();

	KARMA_EXCHANGE.ACK_IS = nil;
	KARMA_EXCHANGE.ACK_AT = nil;

	KARMA_EXCHANGE.FIRST = nil;
	KARMA_EXCHANGE.COUNT = 0;
	KARMA_EXCHANGE.DONE = nil;

	KarmaChatDefault("Asking >" .. args[2] .. "< for a partial copy of their Karma data: Names, total times joined and assigned Karma values...");
	SendAddonMessage("KARMA", sRequest, "WHISPER", args[2]);
end

local	function	Karma_ExchangeStatus()
	if (KARMATRANS_AVAILABLE ~= 1) or (type(KarmaForeign) ~= "table") then
		-- TODO: xlate
		KarmaChatDefault("KarmaTrans must be enabled for a large exchange...");
		return;
	end

	local	key, value, text;
	text = "Karma_ExchangeStatus() -> ";
	for key, value in pairs(KARMA_EXCHANGE) do
		text = text .. key .. ": " .. value .. "; ";
	end
	KarmaChatDefault(text);
end

local	function	Karma_ExchangeTrust(args)
	if	(args[2] == nil) or (args[2] == "") or
		(args[3] == nil) or (args[3] == "") then
		-- TODO: xlate
		KarmaChatDefault("Params: <player> <trust value (0.01 .. 1.0)>");
		return;
	end

	local	oMember = Karma_MemberList_GetObject(args[2]);
	local	trust = tonumber(args[3]);
	if (trust ~= nil) and (trust >= 0.01) and (trust <= 1.0) then
		oMember[KARMA_DB_L5_RRFFM_KARMA_TRUST] = trust;

		-- TODO: xlate
		KarmaChatDefault("Trust for >" .. args[2] .. "< is now " .. trust);
	end
end

local	function	Karma_ExchangeUpdate()
	if (KARMATRANS_AVAILABLE ~= 1) or (type(KarmaForeign) ~= "table") then
		-- TODO: xlate
		KarmaChatDefault("KarmaTrans must be enabled for a large exchange...");
		return;
	end

	local	sServer = GetCVar("realmName"); -- GetRealmName(): not sure about localization
	local	sFaction = UnitFactionGroup("player");
	local	sServFact = sServer .. "#" .. sFaction;

	if (type(KarmaForeign[sServFact]) ~= "table") then
		-- TODO: xlate
		KarmaChatDefault("No data from other players. Nothing to do.");
		return;
	end

	-- set all KARMA_DB_L5_RRFFM_KARMA_IMPORTED to 0
	do
		local	oFaction = KarmaObj.DB.FactionCacheGet();
		local	bucket, memberlist, membername, memberdata;
		for bucket, memberlist in pairs(oFaction[KARMA_DB_L4_RRFF.MEMBERBUCKETS]) do
KarmaChatDebug("reset bucket " .. bucket .. "...");
			for membername, memberdata in pairs(memberlist) do
				memberdata[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] = 0;
			end
		end
	end

	local	bAddAllowed = 0;
	if (KCfg.Get("DEBUG_ENABLED") == 1) then
		bAddAllowed = 1;
	end

	local	oForeign = KarmaForeign[sServFact];
	local	supplier, buckets;
	for supplier, buckets in pairs(oForeign) do
		if (type(buckets) == "table") then
			-- TODO: we want to factor in how much we trust the supplier...
			-- in test phase hardcoded to factor 0.2
			local	suppliertrust = 0.2;
			do
				local	oSupplier = Karma_MemberList_GetObject(supplier);
				if (oSupplier[KARMA_DB_L5_RRFFM_KARMA_TRUST] ~= nil) then
					suppliertrust = oSupplier[KARMA_DB_L5_RRFFM_KARMA_TRUST];
				end
			end

			local	bucket, playerlist;
			for bucket, playerlist in pairs(buckets) do
				local	player, data;
KarmaChatDebug("sup " .. supplier .. ", bucket " .. bucket .. "...");
				if (type(playerlist) == "table") then
					for player, data in pairs(playerlist) do
						local	oMember = Karma_MemberList_GetObject(player);
						if (oMember == nil) and (data.Karma ~= 50) and (bAddAllowed == 1) then
							-- add if enough (interesting) real info is available
							if (data.Level) and (data.Class) and (data.Race) then
								Karma_MemberList_Add(player);
								oMember = Karma_MemberList_GetObject(player);
								if (oMember) then
									oMember[KARMA_DB_L5_RRFFM.LEVEL] = data.Level;
									oMember[KARMA_DB_L5_RRFFM.CLASS_ID] = data.Class;
									oMember[KARMA_DB_L5_RRFFM.CLASS] = KOH.IDToClass(data.Class);
									oMember[KARMA_DB_L5_RRFFM.RACE] = data.Race;
								end
								Karma_MemberList_Update(player);
							end
						end

						if (oMember ~= nil) then
							local	delta = data.Karma - 50;
							if (data.Played < 180) and (math.abs(delta) > 5) then
								-- if just short groupage, no factor, assuming real stupidity
								-- (like e.g. someone ninja'ing adamantite while you clear)
								oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] = delta;
							else
								-- otherwise, factor to offset that humans are... human
								-- max. delta is 40, assuming loss of max. 5 per hour
								local	maxloss = math.floor(5 * data.Played / 3600 + 0.5);
								maxloss = math.min(maxloss, 40);
								if (math.abs(delta) > maxloss) then
									if (delta < 0) then
										delta = - maxloss
									else
										delta = maxloss;
									end
								end

								if (delta < 0) then
									delta = math.ceil(delta * suppliertrust);
								else
									delta = math.floor(delta * suppliertrust);
								end

								if (oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] == nil) then
									oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] = 0;
								end

								oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] = oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] + delta;
							end
						end
					end
				end
			end
		end
	end
end

function	KarmaObj.Share.UpdateEventCheck()
	return (KARMA_EXCHANGE.ACK_AT ~= nil) and (KARMA_EXCHANGE.DONE == nil) and (KARMA_EXCHANGE.START_WITH ~= nil);
end

function	KarmaObj.Share.UpdateEventDo()
	-- KARMA_EXCHANGE: only if nothing else is going on
	if ((KarmaObj.Slash.CommandQLen() == 0) and (#Karma_MessageQueue == 0) and
		(KARMA_TalentInspect.RequiredCount == 0))  then
		if	(TimeNow - KARMA_EXCHANGE.ACK_AT >= 0.5) and
			(TimeNow - KARMA_EXCHANGE.REQ_AT >= 1.0) then

			local	sRequest = "?x1:" .. KARMA_EXCHANGE.ACK_IS;

			KARMA_EXCHANGE.REQ_IS = KARMA_EXCHANGE.ACK_IS;
			KARMA_EXCHANGE.REQ_AT = GetTime();

			KARMA_EXCHANGE.ACK_IS = nil;
			KARMA_EXCHANGE.ACK_AT = nil;

			SendAddonMessage("KARMA", sRequest, "WHISPER", KARMA_EXCHANGE.START_WITH);
		end
	end
end

function	KarmaObj.Share.AddOnMessageXRequest(arg2, arg3, arg4)
	-- only in whisper and must be explicitly allowed
	if (arg3 == "WHISPER") and (KARMA_EXCHANGE.ENABLED_WITH == arg4) then
		local	sBucket, sBorder, sFlags;
		local	iVersion = tonumber(strsub(arg2, 3, 3));

		if (iVersion == 1) then
			sBorder = strsub(arg2, 5);
		elseif (iVersion == 2) then
			local	sDetails = strsub(arg2, 5);
			local	iPos = strfind(sDetails, ":");
			if (iPos) then
				sBorder = strsub(sDetails, 1, iPos - 1);
				sDetails = strsub(sDetails, iPos + 1);
				local	iPos = strfind(sDetails, ":");
				if (iPos) then
					sFlags = strsub(sDetails, 1, iPos - 1);
				else
					sFlags = sDetails;
				end
			else
				sBorder = sDetails;
			end
			if (sFlags == nil) then
				sFlags = "";
			end
		end

		if (sBorder and (sBorder ~= "")) then
			sBucket = KarmaObj.NameToBucket(sBorder);
		else
			sBucket = "A";
			sBorder = "";
		end

		local	sReply = "!x" .. strsub(arg2, 3, 3) .. "+";

		local	lMembers = KarmaObj.DB.SF.MemberListGet(oFaction);
		if (lMembers) then
			local	MAXCOUNT = 5;
			local	oBucket = lMembers[sBucket];
			if (oBucket) then
				local	bSkipEmpty = false;
				local	bSkipUnchanged = false;
				local	bSkipUnjoined = false;
				if (iVersion >= 2) then
					-- Skip empty entries
					bSkipEmpty = (strfind(sFlags, "See ") ~= nil);
					-- Skip unchanged entries since
					iSkipUnchanged = string.match(sFlags, "Sues:(%d+) ");
					if (iSkipUnchanged) then
						iSkipUnchanged = tonumber(iSkipUnchanged);
					end
					bSkipUnchanged = (iSkipUnchanged ~= nil);
					-- Skip never joined entries
					bSkipUnjoined = (strfind(sFlags, "Snje ") ~= nil);
				end
				local	Found = (sBorder == "") or (strsub(sBorder, 2, 2) == "*");
				local	Count = 0;
				local	sName, oMember, bSkip;
				for sName, oMember in pairs(oBucket) do
					if (not Found) then
						Found = sName == sBorder;
					end
					if (Found) then
						if (Count < MAXCOUNT) then
							local	iKarma = KarmaObj.DB.M.KarmaGet(oMember);
							local	sClass = Karma_MemberObject_GetClass(oMember);
							local	iClass = KOH.ClassToID(sClass);
							local	sNote  = Karma_MemberObject_GetPublicNotes(oMember);
							if (sNote and (sNote ~= "")) then
								if ((strsub(sNote, 1, 1) == "#") or strfind(sNote, ":")) then
									sNote = string.gsub(sNote, "#", "##");
									sNote = string.gsub(sNote, "!", "#!");
									sNote = string.gsub(sNote, ":", "#!#!");
									sNote = "#" .. sNote;
								end
								sNote = ":np" .. sNote;
							else
								sNote = "";
							end
							local	sGUID = Karma_MemberObject_GetGUID(oMember);
							if (sGUID and (sGUID ~= "")) then
								sGUID = ":id" .. strsub(sGUID, -4);
							else
								sGUID = "";
							end
							local	iTotalTime = Karma_MemberObject_GetTotalTimePlayedSummedUp(oMember);

							bSkip = false;
							if (bSkipEmpty) then
								bSkip = bSkip or ((iKarma == 50) and (iTotalTime == 0) and (sNote == ""));
							end

							if (not bSkip) then
								local	sAdd =     ":p" .. sName
										.. sGUID
										.. ":l" .. Karma_MemberObject_GetLevel(oMember)
										.. ":k" .. iKarma
										.. sNote
										.. ":ci" .. iClass
										.. ":rs" .. Karma_MemberObject_GetRace(oMember)
										.. ":tt" .. math.floor(iTotalTime);
								-- looong public note?
								if (strlen(sAdd) >= 200) then
									sAdd =     ":p" .. sName
										.. sGUID
										.. ":l" .. Karma_MemberObject_GetLevel(oMember)
										.. ":k" .. iKarma
										.. ":ci" .. iClass
										.. ":rs" .. Karma_MemberObject_GetRace(oMember)
										.. ":tt" .. math.floor(iTotalTime);
								end
								-- already close to limit?
								if (strlen(sReply) + strlen(sAdd) < 200) then
									sReply = sReply .. sAdd;
									Count = Count + 1;
								else
									sReply = sReply .. ":p" .. sName .. "*";
									Count = MAXCOUNT + 1;
									break;
								end
							end
						elseif (Count == MAXCOUNT) then
							sReply = sReply .. ":p" .. sName .. "*";
							Count = Count + 1;
							break;
						end
					end
				end

				if (Count ~= MAXCOUNT + 1) then
					local	iPos = strfind(KARMA_ALPHACHARS, sBucket);
					if (iPos == nil) or ((iPos + 1) > strlen(KARMA_ALPHACHARS)) then
						iPos = 1;
					else
						iPos = iPos + 1;
					end
					sReply = sReply .. ":p" .. strsub(KARMA_ALPHACHARS, iPos, iPos) .. "**";
				end

				SendAddonMessage("KARMA", sReply, arg3, arg4);
			end
		end
	else
		if (KARMA_EXCHANGE.ENABLED_WITH ~= arg4) then
			KarmaChatSecondary("Data exchange request by >" .. KOH.Name2Clickable(arg4) .. "< refused. Use '" .. KARMA_CMDSELF .. " exchangeallow " .. arg4 .. "' to allow them.");
		end

		SendAddonMessage("KARMA", "!x1-", arg3, arg4);
	end
end

function	KarmaObj.Share.AddOnMessageXReply(arg2, arg3, arg4)
	if (arg4 == nil) or (KARMA_EXCHANGE.START_WITH ~= arg4) then
		KarmaChatSecondary("Unsolicited data exchange reply by " .. arg4 .. " - ignored.");
	elseif (strsub(arg2, 3, 3) == "1") then
		if (strsub(arg2, 4, 4) == "-") then
			KarmaChatSecondary("Data exchange request was refused by " .. arg4 .. ". :(");
		elseif (strsub(arg2, 4, 5) == "+:") then
			KarmaChatDebug("Data exchange request was processed by " .. arg4 .. ".");

			if (KarmaTrans_ForeignKarmaEntry == nil) then
				KarmaChatDebug("No use: KarmaTrans is not active. Stopping.");
			end

			local	sServer = GetCVar("realmName"); -- GetRealmName(): not sure about localization
			local	sFaction = UnitFactionGroup("player");
			local	sData = strsub(arg2, 6);
			if (strsub(sData, -1, -1) ~= ":") then
				sData = sData .. ":";
			end
			local	iPos, sFragment;
			local	sPlayer, iKarma, iLevel, iClass, sRace, iPlayed, sNote, sGUID;
			while (sData ~= "") do
				local	iPos = strfind(sData, ":");
				if (iPos == nil) then
					sFragment = sData;
				else
					sFragment = strsub(sData, 1, iPos - 1);
					sData = strsub(sData, iPos + 1);
				end

				if (strsub(sFragment, 1, 1) == "p") then
					-- store data
					if	(sPlayer ~= nil) and (iKarma ~= nil) and (iPlayed ~= nil) then
						local	sBucket = KarmaObj.NameToBucket(sPlayer);
						KarmaTrans_ForeignKarmaEntry(sServer, sFaction, arg4, sBucket, sPlayer, iKarma, iPlayed, iLevel, iClass, sRace, sGUID, sNote);
KarmaChatDebug("Storing: " .. arg4 .. " -> " .. sPlayer .. ": " .. iKarma .. " / " .. iPlayed);
						if (KARMA_EXCHANGE.DONE ~= nil) then
							KARMA_EXCHANGE.COUNT = KARMA_EXCHANGE.COUNT + 1;
						end
					elseif (sPlayer ~= nil) then
KarmaChatDebug("Hmmmmmm: " .. arg4 .. " -> " .. Karma_NilToString(sPlayer) .. ": " .. Karma_NilToString(iKarma) .. " / " .. Karma_NilToString(iPlayed));
					end

					-- next player
					sPlayer = strsub(sFragment, 2);

					-- seen everything once?
					if	(sPlayer == KARMA_EXCHANGE.FIRST) then
						KARMA_EXCHANGE.START_WITH = nil;
						KARMA_EXCHANGE.FIRST = nil;
						KARMA_EXCHANGE.DONE = GetTime();
						KarmaChatDefault("Data exchange with >" .. arg4 .. "< completed. Entry count: " .. KARMA_EXCHANGE.COUNT .. " Duration of exchange: " .. KOH.Duration2String(KARMA_EXCHANGE.DONE - KARMA_EXCHANGE.START_AT));
					end

					-- didn't start with anything: set to first encountered entry
					if (KARMA_EXCHANGE.FIRST == nil) then
						KARMA_EXCHANGE.FIRST = sPlayer;
					end

					-- end of sequence marker?
					if (strsub(sPlayer, -1, -1) == "*") then
						sPlayer = nil;
						KARMA_EXCHANGE.ACK_IS = strsub(sFragment, 2, -2);
KarmaChatDebug("End of group reached, will continue with >" .. KARMA_EXCHANGE.ACK_IS .. "<");
						if (KarmaTrans_ForeignKarmaContinueWithSet ~= nil) then
							KarmaTrans_ForeignKarmaContinueWithSet(sServer, sFaction, arg4, KARMA_EXCHANGE.ACK_IS);
						end
					end

					iKarma = nil;
					iLevel = nil;
					iClass = nil;
					sRace = nil;
					iPlayed = nil;
					sNote = nil;
					sGUID = nil;
				elseif (strsub(sFragment, 1, 1) == "k") then
					iKarma = tonumber(strsub(sFragment, 2));
				elseif (strsub(sFragment, 1, 1) == "l") then
					iLevel = tonumber(strsub(sFragment, 2));
				elseif (strsub(sFragment, 1, 2) == "ci") then
					iClass = tonumber(strsub(sFragment, 3));
				elseif (strsub(sFragment, 1, 2) == "rs") then
					sRace = strsub(sFragment, 3);
				elseif (strsub(sFragment, 1, 2) == "tt") then
					iPlayed = tonumber(strsub(sFragment, 3));
				elseif (strsub(sFragment, 1, 2) == "id") then
					sGUID = strsub(sFragment, 3);
				elseif (strsub(sFragment, 1, 2) == "np") then
					sNote = strsub(sFragment, 3);
					if (strsub(sNote, 1, 1) == "#") then
						sNote = strsub(sNote, 2);
						sNote = string.gsub(sNote, "#!#!", ":");
						sNote = string.gsub(sNote, "#!", "!");
						sNote = string.gsub(sNote, "##", "#");
					end
				end
			end

			KARMA_EXCHANGE.ACK_AT = GetTime() + strlen(arg2) / 100;
		end
	end
end

function	KarmaObj.Share.CommandsInsert()
	KarmaObj.Slash.CommandAdd("exchangeallow", Karma_ExchangeAllow);
	KarmaObj.Slash.CommandAdd("exchangerequest", Karma_ExchangeRequest);
	KarmaObj.Slash.CommandAdd("exchangestatus", Karma_ExchangeStatus);
	KarmaObj.Slash.CommandAdd("exchangeupdate", Karma_ExchangeUpdate);
	KarmaObj.Slash.CommandAdd("exchangetrust", Karma_ExchangeTrust);
end