private void RandomizeLessConsistent(bool quoteStartExpected, ref QuotePosition startQuote, ref QuotePosition endQuote)
        {
            var randomizer = m_random.Next(50);

            if (!quoteStartExpected)
            {
                switch (randomizer)
                {
                case 1:
                    startQuote = QuotePosition.MiddleOfVerse;
                    endQuote   = QuotePosition.MiddleOfVerse;
                    break;

                case 2:
                    endQuote = QuotePosition.MiddleOfVerse;
                    break;

                case 3:
                case 4:
                case 5:
                case 6:
                    endQuote = QuotePosition.EndOfVerse;
                    break;
                }
            }
            else
            {
                switch (randomizer)
                {
                case 1:
                case 2:
                case 3:
                    startQuote = QuotePosition.None;
                    endQuote   = QuotePosition.EndOfVerse;
                    break;

                case 4:
                case 5:
                case 6:
                    startQuote = QuotePosition.StartOfVerse;
                    break;

                case 7:
                case 8:
                case 9:
                case 10:
                    startQuote = QuotePosition.OutOfOrder;
                    endQuote   = QuotePosition.OutOfOrder;
                    break;

                case 11:
                case 12:
                case 13:
                case 14:
                    endQuote = QuotePosition.MiddleOfVerse;
                    break;

                case 15:
                case 16:
                case 17:
                case 18:
                case 19:
                case 20:
                    endQuote = QuotePosition.EndOfVerse;
                    break;

                case 21:
                case 22:
                case 23:
                case 24:
                case 25:
                case 26:
                case 27:
                    startQuote = QuotePosition.None;
                    break;
                }
            }
        }
        public string GetVerseText(int chapter, int verse)
        {
            if (m_desiredQuoteSystem == null)
            {
                return(BlockTestExtensions.RandomString());
            }

            var verseText = new StringBuilder();

            var characters = ControlCharacterVerseData.Singleton.GetCharacters(BookId, chapter, verse).ToList();
            // If previous verse had same character talking, it's probably a longer discourse, so minimize the number of start quotes.
            bool quoteStartExpected = (verse == 1 || characters.Count > 1 || !ControlCharacterVerseData.Singleton.GetCharacters(BookId, chapter, verse - 1)
                                       .SequenceEqual(characters) || verse % 5 == 0);

            // The following attempts to more-or-less simulate real data.
            // When this method is called for verses that are expected to begin a quote, not having
            // a start quote needs to be fairly rare.
            QuotePosition startQuote = quoteStartExpected ? QuotePosition.MiddleOfVerse : QuotePosition.None;
            QuotePosition endQuote   = QuotePosition.None;

            if (m_secondLevelQuoteCloserPending && startQuote != QuotePosition.None)
            {
                m_secondLevelQuoteCloserPending = false;
            }

            if (m_highlyConsistentData)
            {
                RandomizeHighlyConsistent(quoteStartExpected, ref startQuote, ref endQuote);
            }
            else
            {
                RandomizeLessConsistent(quoteStartExpected, ref startQuote, ref endQuote);
            }


            string startQuoteMarker = m_desiredQuoteSystem.FirstLevel.Open;
            string endQuoteMarker   = m_desiredQuoteSystem.FirstLevel.Close;

            if (!String.IsNullOrEmpty(m_desiredQuoteSystem.QuotationDashMarker))
            {
                if (quoteStartExpected && characters[0].IsDialogue)
                {
                    if (m_random.Next(10) > 1)
                    {
                        // 90% of expected dialogue quotes will, in fact, use the dialogue quote marker.
                        startQuoteMarker = m_desiredQuoteSystem.QuotationDashMarker;
                        if (!String.IsNullOrEmpty(m_desiredQuoteSystem.QuotationDashEndMarker))
                        {
                            endQuoteMarker = m_desiredQuoteSystem.QuotationDashEndMarker;
                        }
                        else
                        {
                            endQuote = QuotePosition.None;
                        }
                    }
                }
                else
                {
                    if (m_random.Next(50) > 1)
                    {
                        // 2% of quotes that were not expected to be dialogue will, nonetheless, use the dialogue quote marker.
                        startQuoteMarker = m_desiredQuoteSystem.QuotationDashMarker;
                        endQuoteMarker   = m_desiredQuoteSystem.QuotationDashEndMarker;
                    }
                }
            }

            int startQuotePos = -1;
            int endQuotePos   = -1;

            if (startQuote == QuotePosition.StartOfVerse)
            {
                verseText.Append(startQuoteMarker);
                startQuotePos = verseText.Length;
            }
            if (endQuote == QuotePosition.StartOfVerse)
            {
                verseText.Append(endQuoteMarker);
            }

            verseText.Append(BlockTestExtensions.RandomString());

            if (m_highlyConsistentData && startQuote != QuotePosition.None && startQuote != QuotePosition.StartOfVerse)
            {
                verseText.Replace('\u2014', '-');                 // Prevent spurious em-dashes before starting quote mark
            }

            if (startQuote == QuotePosition.MiddleOfVerse)
            {
                verseText.Append(startQuoteMarker);
                startQuotePos = verseText.Length;
                verseText.Append(BlockTestExtensions.RandomString());
            }

            if (endQuote == QuotePosition.MiddleOfVerse || endQuote == QuotePosition.OutOfOrder)
            {
                endQuotePos = verseText.Length;
                verseText.Append(endQuoteMarker);
                verseText.Append(BlockTestExtensions.RandomString());
            }

            if (startQuote == QuotePosition.OutOfOrder)
            {
                verseText.Append(startQuoteMarker);
                startQuotePos = verseText.Length;
                verseText.Append(BlockTestExtensions.RandomString());
            }

            if (startQuote == QuotePosition.EndOfVerse)
            {
                verseText.Append(startQuoteMarker);
            }
            if (endQuote == QuotePosition.EndOfVerse)
            {
                endQuotePos = verseText.Length;
                verseText.Append(endQuoteMarker);
            }

            if (m_includeSecondLevelQuotes && startQuoteMarker != m_desiredQuoteSystem.QuotationDashMarker)
            {
                float likelihoodFactor = m_highlyConsistentData ? 2F : 4F;

                if (startQuotePos > 0 && endQuotePos > startQuotePos)
                {
                    var pos = m_random.Next(startQuotePos, (int)(verseText.Length * likelihoodFactor));
                    if (pos + 3 < endQuotePos)
                    {
                        verseText.Insert(pos, m_desiredQuoteSystem.NormalLevels[1].Open);

                        if (characters.Count == 1 && ControlCharacterVerseData.Singleton.GetCharacters(BookId, chapter, verse + 1)
                            .SequenceEqual(characters) && (verse + 1) % 5 == 0)
                        {
                            likelihoodFactor = 1;
                        }

                        pos = m_random.Next(pos + 2, (int)(endQuotePos + (endQuotePos - pos) * likelihoodFactor));
                        if (pos < endQuotePos)
                        {
                            verseText.Insert(pos, m_desiredQuoteSystem.NormalLevels[1].Close);
                        }
                        else
                        {
                            m_secondLevelQuoteCloserPending = true;
                        }
                    }
                }
                else if (m_secondLevelQuoteCloserPending)
                {
                    int pos = m_random.Next(startQuotePos, verseText.Length);
                    if (pos < endQuotePos)
                    {
                        verseText.Insert(pos, m_desiredQuoteSystem.NormalLevels[1].Close);
                    }
                }
            }

            return(verseText.ToString());
        }