/*
         * The following types can be converted to XML SimpleTypes,
         * and as such are valid Content for XElement/XAttribute objects:
         * <//docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/valid-content-of-xelement-and-xdocument-objects3>
         * - string
         * - bool
         * - float
         * - double
         * - decimal
         * - DateTime
         * - DateTimeOffset
         * - TimeSpan
         * ToString is called for other types; IEnumerable types have their constituent elements added
         */
        /*
         * The following types can be converted to from XML SimpleTypes,
         * such as XAttribute objects or XElement with Simple Content:
         * <//docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/how-to-retrieve-the-value-of-an-element-linq-to-xml>
         * - Nullable<T> of any of the below
         * - string
         * - bool
         * - int
         * - uint
         * - long
         * - ulong
         * - float
         * - double
         * - decimal
         * - DateTime
         * - TimeSpan
         * - GUID
         */

        public async Task <IReadOnlyDictionary <string, Taglist> > ReadAllHeaders()
        {
            XDocument DataDocument = await XMLDataFileHandler.LoadFile(FileAccess.Read, FileShare.Read, true);

            IEnumerable <Taglist> Results =
                from TL in DataDocument.Root.Elements(xmlns + "Taglist")
                select new Taglist(
                    (string)TL.Attribute("Name"),
                    (ulong)TL.Attribute("SafeArchiveChannelID"),
                    (ulong)TL.Attribute("QuestionableArchiveChannelID"),
                    (ulong)TL.Attribute("ExplicitArchiveChannelID"),
                    ImmutableHashSet <TaglistRegisteredUser> .Empty
                    )
            ;

            return(TaglistsDictionary(Results));
        }
        public async Task <ApplicationConfiguration> LoadConfiguration()
        {
            XDocument DataDocument = await XMLDataFileHandler.LoadFile(FileAccess.Read, FileShare.Read);

            XElement ConfigurationElement           = DataDocument.Root.Elements(xmlns + "Configuration").First();
            XElement ConfigurationImgurElement      = ConfigurationElement.Elements(xmlns + "Imgur").First();
            XElement ConfigurationImgurOAuthElement = ConfigurationImgurElement.Elements(xmlns + "OAuthToken").First();
            XElement ConfigurationDiscordElement    = ConfigurationElement.Elements(xmlns + "Discord").First();
            XElement ConfigurationLoggingElement    = ConfigurationElement.Elements(xmlns + "Logging").First();
            XElement StaticSettingsElement          = DataDocument.Root.Elements(xmlns + "StaticSettings").First();

            return(new ApplicationConfiguration(
                       Enum.Parse <SourceLevels>((string)ConfigurationLoggingElement.Attribute("BootstrapLogLevel")),
                       Enum.Parse <SourceLevels>((string)ConfigurationLoggingElement.Attribute("ApplicationLogLevel")),
                       Enum.Parse <SourceLevels>((string)ConfigurationLoggingElement.Attribute("ImgurLogLevel")),
                       Enum.Parse <SourceLevels>((string)ConfigurationLoggingElement.Attribute("DiscordLogLevel")),
                       Enum.Parse <SourceLevels>((string)ConfigurationLoggingElement.Attribute("DiscordLibraryLogLevel")),
                       Enum.Parse <SourceLevels>((string)ConfigurationLoggingElement.Attribute("ImgurBandwidthLogLevel")),
                       (bool)ConfigurationLoggingElement.Attribute("LogToDiscord"),
                       (string)ConfigurationImgurElement.Attribute("ClientID"),
                       (string)ConfigurationImgurElement.Attribute("ClientSecret"),
                       (string)ConfigurationImgurOAuthElement.Attribute("Username"),
                       (int)ConfigurationImgurOAuthElement.Attribute("UserID"),
                       (string)ConfigurationImgurOAuthElement.Attribute("AccessToken"),
                       (string)ConfigurationImgurOAuthElement.Attribute("RefreshToken"),
                       (string)ConfigurationImgurOAuthElement.Attribute("TokenType"),
                       (DateTimeOffset)ConfigurationImgurOAuthElement.Attribute("ExpiresAt"),
                       //Will always be positive and within range due to the schema
                       (TimeSpan)StaticSettingsElement.Attribute("ImgurCommentPostingDelay"),
                       //Will always be within the inclusive range 0–100 due to the schema
                       (short)StaticSettingsElement.Attribute("ImgurAPIBandwidthWarningThreshholdPercentage") / 100F,
                       //Will always be positive and no greater than 2^31-1 milliseconds due to the schema
                       (short)StaticSettingsElement.Attribute("ImgurMaximumCommentLengthUTF16CodeUnits"),
                       (string)ConfigurationDiscordElement.Attribute("Token"),
                       (ulong)ConfigurationDiscordElement.Attribute("GuildID"),
                       (ulong)ConfigurationDiscordElement.Attribute("LogChannelID"),
                       (ulong)ConfigurationDiscordElement.Attribute("CommandChannelID"),
                       (string)StaticSettingsElement.Attribute("DiscordCommandPrefix"),
                       (ushort)(int)StaticSettingsElement.Attribute("DiscordMaximumMessageLengthUTF16CodeUnits"),
                       (string)StaticSettingsElement.Attribute("TaglistDatafilePath"),
                       (string)StaticSettingsElement.Attribute("ImgurCommandPrefix"),
                       (string)StaticSettingsElement.Attribute("ImgurMentionPrefix")
                       ));
        }