public async Task SetEntry([Remainder][Summary("description of your art trade entry (`optional`)")] string description = null)
        {
            var user = Context.Message.Author;

            if (Storage.xs.Settings.IsTradeMonthActive())
            {
                await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_ERROR, user.Id, "**trade** already started, entries can't be changed anymore"), Utils.Emotion.neutral));

                return;
            }

            Storage.ApplicationData artHistory0 = Utils.GetAppDataFromHistory(0);
            if (artHistory0 != null)
            {
                Storage.UserData userData = Utils.GetMissingArt(artHistory0).Find(x => x.UserId == user.Id);
                if (userData != null)
                {
                    await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.REF_TRADE_LAST_MONTH_ART_MISSING, user.Id, artHistory0.GetTheme())
                                                                + $"\n{string.Format(Properties.Resources.GLOBAL_CMDHELP, Config.CmdPrefix, $"reveal art {artHistory0.GetTheme()}", "register the missing art and I will let you enter")}", Utils.Emotion.negative));

                    return;
                }
            }

            var attachments = Context.Message.Attachments;

            if (attachments.Count <= 0 && string.IsNullOrWhiteSpace(description))
            {
                await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_MISSING_INPUT, user.Id, "description and/or embeded image"), Utils.Emotion.neutral));

                return;
            }

            Storage.UserData data = new Storage.UserData(user.Id, user.Username);
            if (attachments.Count > 0)
            {
                data.ReferenceUrl = attachments.FirstOrDefault().Url;
            }
            if (!string.IsNullOrWhiteSpace(description))
            {
                data.ReferenceDescription = description;
            }
            if (user is IGuildUser guildUser)
            {
                data.NickName = guildUser.Nickname;
            }

            Storage.xs.Entries.Set(data);

            await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_SUCCESS, user.Id, "I saved your entry"), Utils.Emotion.positive));
        }
        public async Task Swap([Summary("first partner's id, this can be either his name, nickname or discord user UUID")] string partner1Id
                               , [Summary("second partner's id, if not entered, the caller is set as the second partner (optional)")] string partner2Id = null
                               , [Summary("third partner's id, needed for non-forceful partner change (optional)")] string partner3Id = null)
        {
            var ourUser = Context.Message.Author;

            if (!Utils.IsAdminUser(ourUser))
            {
                await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_ERROR, ourUser.Id, "admin only command"), Utils.Emotion.neutral));

                return;
            }

            var guild = Utils.FindGuild(ourUser);

            if (guild == null)
            {
                await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_ERROR, ourUser.Id, "guild user not found"), Utils.Emotion.neutral));

                return;
            }

            SocketUser partner1 = Utils.FindUser(guild, partner1Id);

            if (partner1 == null)
            {
                await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_UNKNOW_ARG, ourUser.Id), Utils.Emotion.neutral));

                return;
            }

            SocketUser partner2 = null;

            if (!string.IsNullOrWhiteSpace(partner2Id))
            {
                partner2 = Utils.FindUser(guild, partner2Id);
                if (partner2 == null)
                {
                    await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_UNKNOW_ARG, ourUser.Id), Utils.Emotion.neutral));

                    return;
                }
            }
            else
            {
                partner2 = ourUser;
            }

            if (partner1 == partner2)
            {
                await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_UNKNOW_ARG, ourUser.Id), Utils.Emotion.neutral));

                return;
            }

            ulong?partner3IdVal = null;

            if (!string.IsNullOrWhiteSpace(partner3Id))
            {
                SocketUser partner3 = Utils.FindUser(guild, partner3Id);
                if (partner3 == null || partner3 == partner2 || partner3 == partner1)
                {
                    await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_UNKNOW_ARG, ourUser.Id), Utils.Emotion.neutral));

                    return;
                }
                else
                {
                    partner3IdVal = partner3.Id;
                }
            }

            Storage.xs.BackupStorage(Storage.xs.Entries);

            if (Storage.xs.Settings.IsEntryWeekActive())
            {
                Storage.UserData data = new Storage.UserData(partner2.Id);
                data.PreferenceId = partner1.Id;
                Storage.xs.Entries.Set(data);
                await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_SUCCESS, ourUser.Id, "preferred partner has been marked"), Utils.Emotion.positive));
            }
            else
            {
                List <Storage.UserData> needNotify;
                if (Storage.xs.Entries.ResetNext(partner2.Id, partner1.Id, partner3IdVal, out needNotify))
                {
                    if (await SendPartnersResponse(Context.Client, needNotify))
                    {
                        await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_SUCCESS, ourUser.Id, "partners have been swapped"), Utils.Emotion.positive));
                    }
                    else
                    {
                        await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_ERROR, ourUser.Id, "unable to notify partners related to the swap"), Utils.Emotion.neutral));
                    }
                }
                else
                {
                    await ReplyAsync(embed : Utils.EmbedMessage(Context.Client, string.Format(Properties.Resources.GLOBAL_ERROR, ourUser.Id, "unable to swap partners"), Utils.Emotion.neutral));
                }
            }
        }
        public static async Task <bool> SendPartnerArtResponse(DiscordSocketClient client, Storage.UserData partnerData, SocketUser user, string monthTheme, bool notifyChannel = false)
        {
            if (string.IsNullOrWhiteSpace(partnerData.ArtUrl))
            {
                return(false);
            }

            string message = string.Format(Properties.Resources.REF_REVEAL_FINAL, user.Id, partnerData.UserName
                                           + (string.IsNullOrWhiteSpace(partnerData.NickName) ? "" : $" ({partnerData.NickName})"), monthTheme);

            Embed msg = Utils.EmbedMessage(client, message, Utils.Emotion.positive, partnerData.ArtUrl);

            await user.SendMessageAsync(embed : msg);

            if (notifyChannel)
            {
                SocketTextChannel channel = Utils.FindChannel(client, Storage.xs.Settings.GetWorkingChannel());
                if (channel == null)
                {
                    return(false);
                }

                await channel.SendMessageAsync(embed : msg);
            }

            return(true);
        }
        public static async Task <bool> SendPartnerResponse(DiscordSocketClient client, Storage.UserData partnerData, Discord.WebSocket.SocketUser user, bool bThemeOnly = false)
        {
            if (bThemeOnly)
            {
                var message = (string.IsNullOrWhiteSpace(Storage.xs.Entries.GetTheme()) ? "none" : string.Format(Properties.Resources.TRADE_THIS_THEME, Storage.xs.Entries.GetTheme())) + "\n";
                await user.SendMessageAsync(embed : Utils.EmbedMessage(client, message, Utils.Emotion.positive));
            }
            else
            {
                if (string.IsNullOrWhiteSpace(partnerData.ReferenceDescription) && string.IsNullOrWhiteSpace(partnerData.ReferenceUrl))
                {
                    return(false);
                }

                string message = string.Format(Properties.Resources.REF_TRADE_PARTNER, user.Id, $"{partnerData.UserName}" + (string.IsNullOrWhiteSpace(partnerData.NickName) ? "" : $" ({partnerData.NickName})"));

                if (!string.IsNullOrWhiteSpace(Storage.xs.Entries.GetTheme()))
                {
                    message += $"\n{string.Format(Properties.Resources.TRADE_THIS_THEME, Storage.xs.Entries.GetTheme())}";
                }

                if (Storage.xs.Settings.GetTradeDays() != 0)
                {
                    message += $"\n{string.Format(Properties.Resources.TRADE_ENDS_ON, Storage.xs.Settings.GetTradeDays(), Storage.xs.Settings.GetTradeStart(Storage.xs.Settings.GetTradeDays()).ToString("dd-MMMM"))}";
                }

                if (!string.IsNullOrWhiteSpace(partnerData.ReferenceDescription))
                {
                    message += $"\n`description` : *\"{partnerData.ReferenceDescription}\"*";
                }

                await user.SendMessageAsync(embed : Utils.EmbedMessage(client, message, Utils.Emotion.positive, partnerData.ReferenceUrl));
            }

            return(true);
        }