/// <summary>
        ///     Assembles a randomly generated string from the characters provided by allChars string.
        ///     The secret is assured to have at least one instance of a character from each of the
        ///     four sub-pools: integers, uppercase letters, lowercase letters, and special characters.
        /// </summary>
        /// <returns>Returns a string of length "length" with a minimum length of 4.</returns>
        public string getNewSecret()
        {
            // Initialize global variables.
            numberPoolCompensated    = false;
            lowerPoolCompensated     = false;
            upperPoolCompensated     = false;
            specialPoolCompensated   = false;
            numberOfPoolsCompensated = 0;

            // Object where the secret is assembled.
            var sBuilder = new StringBuilder(secretStringLength);

            // Object that generates the random indexes.
            var newRandomSource = new CryptoRandomIndexProvider();

            // Add one char from each of the four sub-pools ensuring the secret
            // contains at least one char from each sub-pool.
            addCharsToBuilder(numberPool, 1, sBuilder, newRandomSource, false);
            addCharsToBuilder(lowerPool, 1, sBuilder, newRandomSource, false);
            addCharsToBuilder(upperPool, 1, sBuilder, newRandomSource, false);
            addCharsToBuilder(specialPool, 1, sBuilder, newRandomSource, false);

            // Add the remaining chars from allCharsPool.
            // Note: Bias introduce in previous steps is mitigated in this step.
            addCharsToBuilder(allCharsPool, secretStringLength - minSecretLength, sBuilder, newRandomSource, true);

            // Shuffle the entire string randomly relocating the first four chars added.
            shuffle(sBuilder, newRandomSource);

            // Return the assembled string.
            return(sBuilder.ToString());
        }
        /// Performs an in place shuffle on a StringBuilder's array.
        /// The stack of randomly selected chars builds from the end of the array.
        /// The top of the stack tracks with i as i gets smaller.
        /// </summary>
        /// <param name="builder">string builder that gets shuffled</param>
        /// <param name="provider">random generator provider</param>
        private void shuffle(StringBuilder builder, CryptoRandomIndexProvider provider)
        {
            char copiedChar;

            for (int i = builder.Length - 1; i > 1; i--)
            {
                // Get a random number in the range of 0 to i.
                //processRandomIndex(provider, i, getBitsToShift(i + 1));
                var randomIndex = provider.getRandomIndex(i - 1);

                // Copy the char at i making room above the stack for the randomly selected char.
                copiedChar = builder[i];

                // Grab the char at that random position and place it on the stack.
                builder[i] = builder[randomIndex];

                // Place the char that was at i in the position the random char came from.
                builder[randomIndex] = copiedChar;
            }
        }
        /// <summary>
        ///     Adds randomly selected chars from a selection pool to the string builder.
        /// </summary>
        /// <param name="pool">Selection pool</param>
        /// <param name="numberOfCharsToAdd">Number of chars to add</param>
        /// <param name="builder">string builder chars are added to</param>
        /// <param name="provider">random generator provider</param>
        /// <prram name="compensate">Flag to check if compensation is necessary</prram>
        private void addCharsToBuilder(
            string pool,
            int numberOfCharsToAdd,
            StringBuilder builder,
            CryptoRandomIndexProvider provider,
            bool compensate)
        {
            for (int i = 0; i < numberOfCharsToAdd; i++)
            {
                // load randomIndex with a random number.
                var randomIndex = provider.getRandomIndex(pool.Length - 1);

                // Discussion: The program starts by selecting one random character from each of the four sub-strings.  This
                // ensures the secret generated will contain at least one character from each of the sub-strings.  This, however
                // introduces a bias.  Disproportionately more characters are generated from the shorter sub-strings than the
                // longer ones.  The bias can be significant and increases with shorter pools and shorter generated secrets.  The
                // bias is reduced by ignoring the next reference to each sub-string after the initial selections.  The bias
                // becomes insignificant falling below three sigma when generating secrets of 64 characters or more.

                // The following block of code implements a trap that bypasses the second instance of a character being selected
                // from each of the four sub-strings. See discussion above.
                if (!allPoolsCompensated && compensate)
                {
                    if (randomIndex <= numberPoolEnd)
                    {
                        if (!numberPoolCompensated)
                        {
                            numberPoolCompensated = true;
                            numberOfPoolsCompensated++;
                            i--;
                            continue;
                        }
                    }
                    else if (randomIndex <= lowerPoolEnd)
                    {
                        if (!lowerPoolCompensated)
                        {
                            lowerPoolCompensated = true;
                            numberOfPoolsCompensated++;
                            i--;
                            continue;
                        }
                    }
                    else if (randomIndex <= upperPoolEnd)
                    {
                        if (!upperPoolCompensated)
                        {
                            upperPoolCompensated = true;
                            numberOfPoolsCompensated++;
                            i--;
                            continue;
                        }
                    }
                    else if (true) // (randomSort <= specialPoolEnd)
                    {
                        if (!specialPoolCompensated)
                        {
                            specialPoolCompensated = true;
                            numberOfPoolsCompensated++;
                            i--;
                            continue;
                        }
                    }
                }

                // Add the selected character to the builder.
                builder.Append(pool[randomIndex]);
            }
        }