1local pairs = pairs;
2local setmetatable = setmetatable;
3local st = require "util.stanza";
4local util = module:require "muc/util";
5
6local function get_filtered_presence(stanza)
7	return util.filter_muc_x(st.clone(stanza));
8end
9
10local occupant_mt = {};
11occupant_mt.__index = occupant_mt;
12
13local function new_occupant(bare_real_jid, nick)
14	return setmetatable({
15		bare_jid = bare_real_jid;
16		nick = nick; -- in-room jid
17		sessions = {}; -- hash from real_jid to presence stanzas. stanzas should not be modified
18		role = nil;
19		jid = nil; -- Primary session
20	}, occupant_mt);
21end
22
23-- Deep copy an occupant
24local function copy_occupant(occupant)
25	local sessions = {};
26	for full_jid, presence_stanza in pairs(occupant.sessions) do
27		-- Don't keep unavailable presences, as they'll accumulate; unless they're the primary session
28		if presence_stanza.attr.type ~= "unavailable" or full_jid == occupant.jid then
29			sessions[full_jid] = presence_stanza;
30		end
31	end
32	return setmetatable({
33		bare_jid = occupant.bare_jid;
34		nick = occupant.nick;
35		sessions = sessions;
36		role = occupant.role;
37		jid = occupant.jid;
38	}, occupant_mt);
39end
40
41-- finds another session to be the primary (there might not be one)
42function occupant_mt:choose_new_primary()
43	for jid, pr in self:each_session() do
44		if pr.attr.type == nil then
45			return jid;
46		end
47	end
48	return nil;
49end
50
51function occupant_mt:set_session(real_jid, presence_stanza, replace_primary)
52	local pr = get_filtered_presence(presence_stanza);
53	pr.attr.from = self.nick;
54	pr.attr.to = real_jid;
55
56	self.sessions[real_jid] = pr;
57	if replace_primary then
58		self.jid = real_jid;
59	elseif self.jid == nil or (pr.attr.type == "unavailable" and self.jid == real_jid) then
60		-- Only leave an unavailable presence as primary when there are no other options
61		self.jid = self:choose_new_primary() or real_jid;
62	end
63end
64
65function occupant_mt:remove_session(real_jid)
66	-- Delete original session
67	self.sessions[real_jid] = nil;
68	if self.jid == real_jid then
69		self.jid = self:choose_new_primary();
70	end
71end
72
73function occupant_mt:each_session()
74	return pairs(self.sessions)
75end
76
77function occupant_mt:get_presence(real_jid)
78	return self.sessions[real_jid or self.jid]
79end
80
81return {
82	new = new_occupant;
83	copy = copy_occupant;
84	mt = occupant_mt;
85}
86