
KLHTM_MessageLog = 
{
	["NonKLHTM"] = 
	{
		["NumMessages"] = 0,
		["TotalBytes"] = 0,
	},
	["Invalid"] = 
	{
		["NumMessages"] = 0,
		["TotalBytes"] = 0,
	},
	["Good"] = 
	{
		["NumMessages"] = 0,
		["TotalBytes"] = 0,
	},
	["Total"] = 
	{
		["NumMessages"] = 0,
		["TotalBytes"] = 0,
	},
}

function KLHTM_LogMessage(Message, Category)
	
	KLHTM_MessageLog[Category].NumMessages = KLHTM_MessageLog[Category].NumMessages + 1
	KLHTM_MessageLog[Category].TotalBytes = KLHTM_MessageLog[Category].TotalBytes + string.len(Message)
	
	KLHTM_MessageLog.Total.NumMessages = KLHTM_MessageLog.Total.NumMessages + 1
	KLHTM_MessageLog.Total.TotalBytes = KLHTM_MessageLog.Total.TotalBytes + string.len(Message)

end

function KLHTM_NetOnEvent()
	
	if event == "CHAT_MSG_CHANNEL" then
		
		if arg9 ~= CT_RA_Channel then
			return -- not our channel
		end
		
		if string.sub(arg1, 1, 6) ~= "KLHTM " then
			KLHTM_LogMessage(arg1, "NonKLHTM")
			return -- not a KLHTM message
		end
		
		if KLHTM_IsPlayerInGroup(arg2) == nil then
			KLHTM_LogMessage(arg1, "NonKLHTM")
			return -- message not from a member of our group
		end
		
		-- to get here, it's fine
		KLHTM_MessageIn(arg2, string.sub(arg1, 7))
	
	elseif event == "CHAT_MSG_SYSTEM" then
					
		if string.find(arg1, string.format(MARKED_AFK_MESSAGE, "")) then
			KLHTM_SetState("afk", true)
				
		elseif string.find(arg1, CLEARED_AFK) then
			KLHTM_SetState("afk", false)
		end
		
	else
		
		return
	end
	
end

function KLHTM_IsPlayerInGroup(PlayerName)

	if GetNumRaidMembers() > 0 then
		for x = 1, 40 do
			if UnitName("raid" .. x) == PlayerName then
				return true
			end
		end
	
	elseif GetNumPartyMembers() > 0 then
		for x = 1, 4 do
			if UnitName("party" .. x) == PlayerName then
				return true
			end
		end
		
		if PlayerName == UnitName("player") then
			return true
		end
	end
	
	if PlayerName == UnitName("player") then
		return true
	end

end

-- returns true if Name = party leader or raid leader or raid assistant
function KLHTM_IsPlayerOfficer(Name)

	local name
	local rank

	if GetNumRaidMembers() > 0 then
		for i = 1, 40 do
			
			name, rank = GetRaidRosterInfo(i)
			if name == Name then
				if rank > 0 then
					return true
				else
					return false
				end
			end
		end
		
	elseif GetNumPartyMembers() > 0 then
		if UnitIsPartyLeader("player") == 1 and Name == UnitName("player") then
			return true
		else
			for i = 1, 4 do
				if UnitName("party" .. i) == Name then
					if UnitIsPartyLeader("party" .. i) == 1 then
						return true
					else
						return false
					end
				end
			end
		end
		
	else
		return true -- single player = officer
		
	end
	
end


function KLHTM_MessageIn(Author, Message)
	
	KLHTM_PrintTrace("ChannelMessages", string.format("|cff33ff33[%s]: |cff6666ff%s.|r", Author, Message))
	
	if Message == "clear" then
		-- check out the Author's credentials
		if KLHTM_IsPlayerOfficer(Author) == true then
			-- ok, clear
			KLHTM_Print(string.format(KLHTM_String("print", "network", "threatreset"), Author))
			
			-- reset our raid data
			KLHTM_ResetRaidThreat()
			
			-- now reset the window
			KLHTM_ResetMyData("Raid")
			
			-- Log
			KLHTM_LogMessage("KLHTM: " .. Message, "Good")
		else
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", Author .. " tried to clear the raid threat, but he isn't an officer.")
		end
		
	elseif string.sub(Message, 1, 7) == "threat " then
		
		-- threat updates here. just a number
		local value = tonumber(string.sub(Message, 8))
		
		if value == nil then 
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
			return -- some deformed message
		end
		
		KLHTM_PrintTrace("ThreatUpdates", string.format("%s updates his threat to %d.", Author, value))
		KLHTM_RaidData[Author] = value
		KLHTM_RedrawTable(KLHTM_RaidWindow)
		
		-- Log
		KLHTM_LogMessage("KLHTM: " .. Message, "Good")
		
	elseif string.sub(Message, 1, 7) == "target " then
		local newmt = string.sub(Message, 8)
		
		if newmt ~= nil and string.len(newmt) > 0 then
			-- valid message so far
			
			if KLHTM_IsPlayerOfficer(Author) == true then
				
				KLHTM_SetNewMasterTarget(newmt, Author)
								
				-- Log
				KLHTM_LogMessage("KLHTM: " .. Message, "Good")
				
			else
				KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
				KLHTM_PrintTrace("BadMessage", Author .. " tried to set a master target, but he is not an officer.")
			end
		
		else
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
		end
	
	elseif Message == "cleartarget" then
		
		if KLHTM_IsPlayerOfficer(Author) == true then
			-- OK
			KLHTM_MasterTarget = nil
			KLHTM_Print(string.format(KLHTM_String("print", "network", "mtclear"), Author))
			KLHTM_RaidWindow.Label = KLHTM_String("gui", "raidlabel")
			
			if KLHTM_RaidWindow.IsMinimised == false then
				KLHTM_RaidFrameTextMain:SetText(KLHTM_RaidWindow.Label)
			end
				
			KLHTM_UpdateFrameBounds(KLHTM_RaidWindow)
			
			-- Log
			KLHTM_LogMessage("KLHTM: " .. Message, "Good")
		else
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", Author .. " tried to clear the master target, but he is not an officer.")
		end
		
	elseif Message == "knockbackstart" then
		if KLHTM_IsPlayerOfficer(Author) == true then
			
			KLHTM_KnockbackDiscoveryIsActive = true
			KLHTM_MasterTargetTarget = nil
			
			if Author == UnitName("player") then
				KLHTM_IsKnockbackInvestigator = true
			end
			
			KLHTM_Print(string.format(KLHTM_String("print", "network", "knockbackstart"), Author))
			
			-- Log
			KLHTM_LogMessage("KLHTM: " .. Message, "Good")

		else
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", Author .. " tried to start knockback discovery, but he is not an officer.")
		end
	
	elseif Message == "knockbackstop" then
		if KLHTM_IsPlayerOfficer(Author) == true then
			
			KLHTM_KnockbackDiscoveryIsActive = false
			
			if Author == UnitName("player") then
				KLHTM_IsKnockbackInvestigator = false
			end
			
			KLHTM_Print(string.format(KLHTM_String("print", "network", "knockbackstop"), Author))
			
			-- Log
			KLHTM_LogMessage("KLHTM: " .. Message, "Good")

		else
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", Author .. " tried to stop knockback discovery, but he is not an officer.")
		end
	
	elseif string.sub(Message, 1, 10) == "aggrogain " then
		
		-- threat updates here. just a number
		local value = tonumber(string.sub(Message, 11))
		
		if value == nil then 
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
			return -- some deformed message
		end
		
		-- only say something if we are monitoring knockbacks
		if KLHTM_IsKnockbackInvestigator == true then
			KLHTM_Print(string.format(KLHTM_String("print", "network", "aggrogain"), Author, value))
		end
	
		-- Log
		KLHTM_LogMessage("KLHTM: " .. Message, "Good")
	
	elseif string.sub(Message, 1, 10) == "aggroloss " then
		
		-- threat updates here. just a number
		local value = tonumber(string.sub(Message, 11))
		
		if value == nil then 
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
			return -- some deformed message
		end
		
		-- only say something if we are monitoring knockbacks
		if KLHTM_IsKnockbackInvestigator == true then
			KLHTM_Print(string.format(KLHTM_String("print", "network", "aggroloss"), Author, value))
		end
	
		-- Log
		KLHTM_LogMessage("KLHTM: " .. Message, "Good")
		
	elseif string.sub(Message, 1, 10) == "knockaway " then
		
		-- threat updates here. just a number
		local value = tonumber(string.sub(Message, 11))
		
		if value == nil then 
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
			return -- some deformed message
		end
		
		-- only say something if we are monitoring knockbacks
		if KLHTM_IsKnockbackInvestigator == true then
			KLHTM_Print(string.format(KLHTM_String("print", "network", "knockback"), Author, value))
		end
	
		-- Log
		KLHTM_LogMessage("KLHTM: " .. Message, "Good")
	
	elseif string.sub(Message, 1, 14) == "knockawaytext " then
		
		-- threat updates here. just a number
		local text = string.sub(Message, 15)
		
		if text == nil then 
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
			return -- some deformed message
		end
		
		-- only say something if we are monitoring knockbacks
		if KLHTM_IsKnockbackInvestigator == true then
			KLHTM_Print(string.format(KLHTM_String("print", "network", "knockbackstring"), Author, text))
		end

		-- Log
		KLHTM_LogMessage("KLHTM: " .. Message, "Good")

	elseif string.sub(Message, 1, 8) == "version " then
		
		local value = tonumber(string.sub(Message, 9))
		
		if value == nil then	
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
			return -- some deformed message
		end
		
		if KLHTM_Release < value then
			KLHTM_Print(string.format(KLHTM_String("print", "network", "upgraderequest"), Author, value, KLHTM_Release))
		
		elseif KLHTM_Release > value then
			KLHTM_Print(string.format(KLHTM_String("print", "network", "remoteoldversion"), Author, value, KLHTM_Release))
		
		else
			-- using the same version as us. Do nothing.
		end

		-- Log
		KLHTM_LogMessage("KLHTM: " .. Message, "Good")

	elseif Message == "versionquery" then
		if KLHTM_IsPlayerOfficer(Author) == true then
			
			-- respond with our version
			KLHTM_SendMessage("versionresponse " .. KLHTM_Release)
			
			-- Log
			KLHTM_LogMessage("KLHTM: " .. Message, "Good")
			
		else
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", Author .. " sent a version request, but he is not an officer.")
		end
	
	elseif string.sub(Message, 1, 16) == "versionresponse " then
		
		-- get the version number
		local value = tonumber(string.sub(Message, 17))
		
		if value == nil then 
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
			return -- some deformed message
		end
		
		-- ignore unless we are checking versions
		if KLHTM_VersionQueryTimeout > 0 then
			if KLHTM_RaidVersions["" .. value] == nil then
				KLHTM_RaidVersions["" .. value] = { }
			end
			
			KLHTM_RaidVersions["" .. value][Author] = true
		end
		
		-- Log
		KLHTM_LogMessage("KLHTM: " .. Message, "Good")
	
	elseif string.sub(Message, 1, 15) == "knockbackvalue " then
		
		-- 1) tokenise
		local tokenlist = { }
		local token
	
		for token in string.gfind(string.sub(Message, 16), "[^ ]+") do
			table.insert(tokenlist, token)
		end
	
		-- 2) get value
		local value = tonumber(tokenlist[1])
		if value == nil or value < -1 or value > 0 then
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Value was invalid in the message: " .. Message)
			return -- some deformed message
		end
		
		-- 3) get attack
		table.remove(tokenlist, 1)
		local attack = ""
		local x
		
		for x = 1, table.getn(tokenlist) do
			if x > 1 then
				attack = attack .. " "
			end
			
			attack = attack .. tokenlist[x]
		end
		
		-- 4) check attack is valid, and mastertarget exists
		if (KLHTM_Knockbacks[attack] == nil) or (KLHTM_MasterTarget == nil) then
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", "Attack = '" .. attack .. "' or MasterTarget is nil in the message: " .. Message)
			return -- some deformed message
		end
		
		-- 5) check for author officer
		if KLHTM_IsPlayerOfficer(Author) ~= true then
			KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
			KLHTM_PrintTrace("BadMessage", Author .. " was not an officer: " .. Message)
			return -- some deformed message
		end
		
		-- 6) do it!
		KLHTM_Knockbacks[attack][KLHTM_MasterTarget] = value
		KLHTM_Print(string.format(KLHTM_String("print", "network", "knockbackvaluechange"), Author, KLHTM_MasterTarget, attack, value * 100))
		
	else
		KLHTM_PrintTrace("BadMessage", "Received this invalid message: " .. Message)
		KLHTM_LogMessage("KLHTM: " .. Message, "Invalid")
	end

end

-- Target: name of the mob who is the new master target
-- Officer: name of the player who changed the master target
function KLHTM_SetNewMasterTarget(Target, Officer)
	
	-- 1) Check whether Target matches Officer's Target
	local officerunit = KLHTM_FindUnitIdFromName(Officer)
	local officertarget = UnitName(officerunit .. "target")
	
	if officertarget == nil then
		KLHTM_Print(string.format(KLHTM_String("print", "network", "newmttargetnil"), Target, Officer))
	
	elseif officertarget ~= Target then
		KLHTM_Print(string.format(KLHTM_String("print", "network", "newmttargetmismatch"), Officer, Target, officertarget))
		Target = officertarget
	end
	
	-- OK
	KLHTM_MasterTarget = Target
							
	KLHTM_Print(string.format(KLHTM_String("print", "network", "newmt"), Target, Officer))
				
	-- this will put an ellipsis at the end of the master target name in the raid window label, if it's too long.
	KLHTM_RaidWindow.Label = KLHTM_MasterTarget	
	if string.len(KLHTM_MasterTarget) > 15 then
		KLHTM_RaidWindow.Label = string.sub(KLHTM_MasterTarget, 1, 12) .. "..."
	end
				
	if KLHTM_RaidWindow.IsMinimised == false then
		KLHTM_RaidFrameTextMain:SetText(KLHTM_RaidWindow.Label)
	end
				
	KLHTM_UpdateFrameBounds(KLHTM_RaidWindow)
	
end

function KLHTM_SendMessage(Message)
	
	if CT_RA_Channel then
		
		local channelnumber = GetChannelName(CT_RA_Channel)
		
		if channelnumber > 0 then
			SendChatMessage("KLHTM " .. Message, "CHANNEL", nil, channelnumber)
			
			KLHTM_PrintTrace("MessageSent", "Sent this message: KLHTM " .. Message)

			return true
		end
	end
	
	-- (return nil)
	
end

function KLHTM_ClearMasterTarget()
	
	if KLHTM_IsPlayerOfficer(UnitName("player")) == true then
		KLHTM_SendMessage("cleartarget")
		
	else
		KLHTM_Print(KLHTM_String("print", "network", "raidpermission"))
	end
end

function KLHTM_SendMasterTarget(TargetName)

	if KLHTM_IsPlayerOfficer(UnitName("player")) == true then
		KLHTM_SendMessage("target " .. TargetName)
		
	else
		KLHTM_Print(KLHTM_String("print", "network", "raidpermission"))
	end
	
end

function KLHTM_StartKnockbackDiscovery()
	
	if KLHTM_IsPlayerOfficer(UnitName("player")) == true then
		
		if KLHTM_MasterTarget ~= nil then
			KLHTM_SendMessage("knockbackstart")
		
		else
			KLHTM_Print(KLHTM_String("print", "network", "needmastertarget"))
		end
		
	else
		KLHTM_Print(KLHTM_String("print", "network", "raidpermission"))
	end
end

function KLHTM_StopKnockbackDiscovery()
	
	if KLHTM_IsPlayerOfficer(UnitName("player")) == true then
		
		if KLHTM_KnockbackDiscoveryIsActive == false then
			KLHTM_Print(KLHTM_String("print", "network", "knockbackinactive"))
		else
			KLHTM_SendMessage("knockbackstop")
		end
		
	else
		KLHTM_Print(KLHTM_String("print", "network", "raidpermission"))
	end
	
end

function KLHTM_VersionQuery()
	
	if KLHTM_IsPlayerOfficer(UnitName("player")) == true then
		
		-- clear the version table
		local key
		
		for key, _ in KLHTM_RaidVersions do
			table.remove(KLHTM_RaidVersions, key)
		end
		
		-- set the timeout for responses
		KLHTM_VersionQueryTimeout = GetTime() + 3
		
		-- Notify the user
		KLHTM_Print(KLHTM_String("print", "network", "versionrequest"))
		
		-- send the message
		KLHTM_SendMessage("versionquery")
		
	else
		KLHTM_Print(KLHTM_String("print", "network", "raidpermission"))
	end
end

function KLHTM_SetRaidKnockbackValue(value, attack)
	
	if KLHTM_IsPlayerOfficer(UnitName("player")) == true then
		
		-- Check master target exists
		if KLHTM_MasterTarget == nil then
			KLHTM_Print(KLHTM_String("print", "network", "needmastertarget"))
		
		else
			KLHTM_SendMessage("knockbackvalue " .. value .. " " .. attack)
		end
		
	else
		KLHTM_Print(KLHTM_String("print", "network", "raidpermission"))
	end
end
	
KLHTM_LastThreatUpdate = 0 -- value of GetTime()
KLHTM_MinimumUpdateInterval = 0.5
KLHTM_IdleUpdateInterval = 5.0
KLHTM_LastThreatValueSent = -1

function KLHTM_NetOnUpdate()

	KLHTM_UpdateThreatToRaid()
	KLHTM_CheckVersionQuery()

end

-- When we do "/ktm version query", the rest of the raid has 3 seconds to respond.
function KLHTM_CheckVersionQuery()
	
	if KLHTM_VersionQueryTimeout == 0 then
		return
	end
	
	if GetTime() > KLHTM_VersionQueryTimeout then
		-- print it out and stuff
		KLHTM_VersionQueryTimeout = 0
		
		local message
		local key
		local value
		local key2
		local namesfound = { }
		
		for key, value in KLHTM_RaidVersions do
			message = string.format(KLHTM_String("print", "network", "versionrecent"), key)
			
			for key2, _ in value do
				message = message .. key2 .. ", "
				namesfound[key2] = true
			end
			
			message = message .. " }."
			KLHTM_Print(message)
			
			table.remove(KLHTM_RaidVersions, key)
		end
		
		-- Now print the people who have out of date versions
		message = KLHTM_String("print", "network", "versionold")
		for key, _ in KLHTM_RaidData do
			if namesfound[key] == nil and KLHTM_IsPlayerInGroup(key) == true then
				namesfound[key] = true
				message = message .. key .. ", "
			end
		end
		
		message = message .. " }."
		KLHTM_Print(message)
		
		-- Now print out people who are not talking to us
		message = KLHTM_String("print", "network", "versionnone")
		
		for value = 1, 40 do
			key = GetRaidRosterInfo(value)
			if (key ~= nil) and (namesfound[key] == nil) then
				namesfound[key] = true
				message = message .. key .. ", "
			end
		end
		
		message = message .. " }."
		KLHTM_Print(message)
		
	end
end

function KLHTM_UpdateThreatToRaid()
	
	-- check not afk
	if KLHTM_States.afk.value == true then
		return
	end
	
	local interval
	local myraidthreat
	
	if KLHTM_States.incombat.value == true then
		myraidthreat = math.ceil(KLHTM_MyRaidThreat())
	else
		myraidthreat = 0
	end
	
	if myraidthreat == KLHTM_LastThreatValueSent then
		interval = KLHTM_IdleUpdateInterval
	
	else
		interval = KLHTM_MinimumUpdateInterval
	end
	
	-- check update frequency
	if GetTime() < KLHTM_LastThreatUpdate + interval then
		return -- only just sent an update. Wait a bit to send the next one.
	end
	
	-- OK. Send.

	if KLHTM_SendMessage("threat " .. myraidthreat) == nil then
		KLHTM_PrintTrace("ChannelFail", "Threat was not updated because the CTRA Channel is not set up properly.")
		
	else
		KLHTM_LastThreatUpdate = GetTime()
		KLHTM_LastThreatValueSent = myraidthreat
	end

end

-- Version Querying Stuff. Key = release number, value = array of names
KLHTM_RaidVersions = { }
KLHTM_VersionQueryTimeout = 0 -- 0 = inactive, > 0 = active

