1 module dscord.types.guild;
2 
3 import std.stdio,
4        std.algorithm,
5        std.array,
6        std.conv;
7 
8 import dscord.client,
9        dscord.types.all;
10 
11 alias GuildMap = ModelMap!(Snowflake, Guild);
12 alias RoleMap = ModelMap!(Snowflake, Role);
13 alias GuildMemberMap = ModelMap!(Snowflake, GuildMember);
14 alias EmojiMap = ModelMap!(Snowflake, Emoji);
15 
16 bool memberHasRoleWithin(RoleMap map, GuildMember mem) {
17   foreach (ref role; map.values) {
18     if (mem.hasRole(role)) return true;
19   }
20   return false;
21 }
22 
23 class Role : IModel {
24   mixin Model;
25 
26   Snowflake   id;
27   Guild       guild;
28   Permission  permissions;
29 
30   string  name;
31   uint    color;
32   bool    hoist;
33   short   position;
34   bool    managed;
35   bool    mentionable;
36 
37   this(Client client, ref JSON obj) {
38     super(client, obj);
39   }
40 
41   this(Guild guild, ref JSON obj) {
42     this.guild = guild;
43     super(guild.client, obj);
44   }
45 
46   override void load(ref JSON obj) {
47     obj.keySwitch!(
48       "id", "name", "hoist", "position", "permissions",
49       "managed", "mentionable", "color"
50     )(
51       { this.id = readSnowflake(obj); },
52       { this.name = obj.read!string; },
53       { this.hoist = obj.read!bool; },
54       { this.position = obj.read!short; },
55       { this.permissions = Permission(obj.read!uint); },
56       { this.managed = obj.read!bool; },
57       { this.mentionable = obj.read!bool; },
58       { this.color = obj.read!uint; },
59     );
60   }
61 
62   Snowflake getID() {
63     return this.id;
64   }
65 }
66 
67 class Emoji : IModel {
68   mixin Model;
69 
70   Snowflake  id;
71   Guild      guild;
72   string     name;
73   bool       requireColons;
74   bool       managed;
75 
76   Snowflake[]  roles;
77 
78   this(Client client, ref JSON obj) {
79     super(client, obj);
80   }
81 
82   this(Guild guild, ref JSON obj) {
83     this.guild = guild;
84     super(guild.client, obj);
85   }
86 
87   override void load(ref JSON obj) {
88     obj.keySwitch!(
89       "id", "name", "require_colons", "managed", "roles"
90     )(
91       { this.id = readSnowflake(obj); },
92       { this.name = obj.read!string; },
93       { this.requireColons = obj.read!bool; },
94       { this.managed = obj.read!bool; },
95       { this.roles = obj.read!(string[]).map!((c) => c.to!Snowflake).array; },
96     );
97   }
98 
99   bool matches(string usage) {
100     if (this.name == ":" ~ usage ~ ":") {
101       return true;
102     } else if (this.requireColons) {
103       return false;
104     } else {
105       return this.name == usage;
106     }
107   }
108 }
109 
110 class GuildMember : IModel {
111   mixin Model;
112 
113   User    user;
114   Guild   guild;
115   string  nick;
116   string  joinedAt;
117   bool    mute;
118   bool    deaf;
119 
120   Snowflake[]  roles;
121 
122   this(Client client, ref JSON obj) {
123     super(client, obj);
124   }
125 
126   this(Guild guild, ref JSON obj) {
127     this.guild = guild;
128     super(guild.client, obj);
129   }
130 
131   override void load(ref JSON obj) {
132     obj.keySwitch!(
133       "user", "guild_id", "roles", "nick", "mute", "deaf", "joined_at"
134     )(
135       { this.user = new User(this.client, obj); },
136       { this.guild = this.client.state.guilds.get(readSnowflake(obj)); },
137       { this.roles = obj.read!(string[]).map!((c) => c.to!Snowflake).array; },
138       { this.nick = obj.read!string; },
139       { this.mute = obj.read!bool; },
140       { this.deaf = obj.read!bool; },
141       { this.joinedAt = obj.read!string; },
142     );
143 
144     // If the state has a user, lets use that version (and trash our local one)
145     //  in theory this could leave things dirty, which isn't great...
146     if (this.client.state.users.has(this.user.id)) {
147       this.user = this.client.state.users.get(this.user.id);
148     }
149   }
150 
151   Snowflake getID() {
152     return this.user.id;
153   }
154 
155   bool hasRole(Role role) {
156     return this.hasRole(role.id);
157   }
158 
159   bool hasRole(Snowflake id) {
160     return this.roles.canFind(id);
161   }
162 }
163 
164 class Guild : IModel {
165   mixin Model;
166 
167   Snowflake  id;
168   Snowflake  ownerID;
169   Snowflake  afkChannelID;
170   Snowflake  embedChannelID;
171   string     name;
172   string     icon;
173   string     splash;
174   string     region;
175   uint       afkTimeout;
176   bool       embedEnabled;
177   ushort     verificationLevel;
178   string[]   features;
179 
180   bool  unavailable;
181 
182   // Mappings
183   GuildMemberMap  members;
184   VoiceStateMap   voiceStates;
185   ChannelMap      channels;
186   RoleMap         roles;
187   EmojiMap        emojis;
188 
189   override void init() {
190     this.members = new GuildMemberMap;
191     this.voiceStates = new VoiceStateMap;
192     this.channels = new ChannelMap;
193     this.roles = new RoleMap;
194     this.emojis = new EmojiMap;
195   }
196 
197   override void load(ref JSON obj) {
198     obj.keySwitch!(
199       "id", "unavailable", "owner_id", "name", "icon",
200       "region", "verification_level", "afk_channel_id",
201       "splash", "afk_timeout", "channels", "roles", "members",
202       "voice_states", "emojis", "features",
203     )(
204       { this.id = readSnowflake(obj); },
205       { this.unavailable = obj.read!bool; },
206       { this.ownerID = readSnowflake(obj); },
207       { this.name = obj.read!string; },
208       { this.icon = obj.read!string; },
209       { this.region = obj.read!string; },
210       { this.verificationLevel = obj.read!ushort; },
211       { this.afkChannelID = readSnowflake(obj); },
212       { this.splash = obj.read!string; },
213       { this.afkTimeout = obj.read!uint; },
214       {
215         loadManyComplex!(Guild, Channel)(this, obj, (c) { this.channels[c.id] = c; });
216       },
217       {
218         loadManyComplex!(Guild, Role)(this, obj, (r) { this.roles[r.id] = r; });
219       },
220       {
221         loadManyComplex!(Guild, GuildMember)(this, obj, (m) { this.members[m.user.id] = m; });
222       },
223       {
224         loadMany!VoiceState(this.client, obj, (v) { this.voiceStates[v.sessionID] = v; });
225       },
226       {
227         loadManyComplex!(Guild, Emoji)(this, obj, (e) { this.emojis[e.id] = e; });
228       },
229       { this.features = obj.read!(string[]); });
230   }
231 
232   GuildMember getMember(User obj) {
233     return this.getMember(obj.id);
234   }
235 
236   GuildMember getMember(Snowflake id) {
237     return this.members[id];
238   }
239 
240   Snowflake getID() {
241     return this.id;
242   }
243 
244   void kick(GuildMember member) {
245     this.kick(member.user);
246   }
247 
248   void kick(User user) {
249     this.client.api.guildRemoveMember(this.id, user.id);
250   }
251 }