/// <summary>
        /// Gets the details of the provided Pokemon.
        /// </summary>
        /// <param name="id">The Pokemon number.</param>
        /// <returns>The details of the Pokemon, or null if the id is not valid.</returns>
        public async Task <PokemonDetails> GetDetails(int id)
        {
            PokemonReference reference = await this.GetReference(id).ConfigureAwait(false);

            if (reference == null)
            {
                return(null);
            }

            // We currently do not cache Pokemon details. We probably should add this in the
            // long term to improve performance and reduce the load on the Bulbapedia servers.
            return(await this.bulbapedia.GetDetails(reference).ConfigureAwait(false));
        }
        /// <summary>
        /// Gets detailed information about the provided Pokemon.
        /// </summary>
        /// <param name="reference">The Pokemon reference.</param>
        /// <returns>The detailed information about the Pokemon.</returns>
        public async Task <PokemonDetails> GetDetails(PokemonReference reference)
        {
            IDocument document = await this.GetPage(reference.Name + "_(Pokémon)").ConfigureAwait(false);

            // The layout of the body content is as follows:
            // - Table with the top navigation bar (to navigate between Pokemon species)
            // - Table with Pokemon information (right side panel)
            // - One or more paragraph tags with the leading introduction of the Pokemon (this is what we want).
            // - A div element that encapsulates the table of contents.
            // Note that HTML tag names are always upper case (https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName)
            string description = string.Join("\n", document.GetElementById("mw-content-text").Children
                                             .SkipWhile(e => e.TagName == "TABLE")
                                             .TakeWhile(e => e.TagName == "P")
                                             .Select(e => e.TextContent.Trim())
                                             .Where(line => !string.IsNullOrWhiteSpace(line)));

            // This is the table on the left of the page with the general info of the Pokemon.
            IElement infoTable = document.QuerySelectorAll("table + table.roundy")
                                 .Single(table => table.QuerySelector("table table > tbody > tr:first-child > td:first-child > big > big > b") != null);

            string catchRate            = this.GetPokemonInfoPanelValue(infoTable, "Catch rate");
            string baseExpYield         = this.GetPokemonInfoPanelValue(infoTable, "Base experience yield");
            string hatchTimeDescription = this.GetPokemonInfoPanelValue(infoTable, "Hatch time");
            string baseFriendship       = this.GetPokemonInfoPanelValue(infoTable, "Base friendship");

            int[] hatchTime = hatchTimeDescription == null
                ? new[] { 0 }
                : hatchTimeDescription.Split('-').Select(s => this.TryParseInt32(s, 0)).ToArray();

            return(new PokemonDetails
            {
                Number = reference.Number,
                Name = reference.Name,
                Description = description,
                Types = this.GetTypes(infoTable),
                CatchRate = this.TryParseInt32(catchRate, 0),
                BaseExperienceYield = this.TryParseInt32(baseExpYield, 0),
                HatchTimeMin = hatchTime[0],
                HatchTimeMax = hatchTime.Length > 1 ? hatchTime[1] : hatchTime[0],
                BaseFriendship = this.TryParseInt32(baseFriendship, 0),
            });
        }