private void TemplateToWords(IEnumerable <Template> template, GenerateTarget target, string wordDelimiter)
        {
            var             chosenWords     = new HashSet <Word>();
            ArticleTemplate?previousArticle = null;

            foreach (var t in template)
            {
                if (t.GetType() == typeof(ArticleTemplate))
                {
                    // Can't directly append an article because it's form depends on the next word (whether it starts with a vowel sound or not).
                    previousArticle = (ArticleTemplate)t;
                }
                else
                {
                    var tuple = t.ChooseWord(this.Dictionary, this.Randomness, chosenWords);
                    if (t.IncludeInAlreadyUsedList)
                    {
                        chosenWords.Add(tuple.Word);
                    }

                    // Check for a previous article which must be returned before the current word.
                    if (previousArticle != null)
                    {
                        var w = previousArticle.ChooseBasedOnFollowingWord(this.Dictionary, tuple.FinalWord);
                        previousArticle = null;
                        this.AppendWord(target, wordDelimiter, w);
                    }

                    // Rather than returning IEnumerable<String>, we build directly into the target (which may be backed by either a StringBuilder or a SecureString).
                    // This interface is required by SecureString as we can only append Char to it and can't easily read its contents back.
                    this.AppendWord(target, wordDelimiter, tuple.FinalWord);
                }
            }
        }
        private void AppendWord(GenerateTarget target, string wordDelimiter, string word)
        {
            // Remember that some words in the dictionary are actually multiple words (verbs often have a helper verb with them).
            // So, if there are no spaces, we must remove spaces from words.
            // Also need to replace spaces in the word with our supplied word delimiter.

            var toAppend = word;

            toAppend = toAppend.Replace(" ", wordDelimiter);
            target.Append(toAppend);
            target.Append(wordDelimiter);
        }
        private void GenerateInternal(IEnumerable <Clause> phraseDescription, string wordDelimiter, GenerateTarget result)
        {
            if (phraseDescription == null)
            {
                throw new ArgumentNullException("phraseDescription");
            }
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (this.Dictionary == null || this.Dictionary.Count == 0)
            {
                throw new InvalidOperationException("You must call LoadDictionary() before any Generate() method.");
            }

            // Build a detailed template by translating the clauses to something which is 1:1 with words.
            var template = this.PhrasesToTemplate(phraseDescription);

            // Build the phrase based on that template.
            this.TemplateToWords(template, result, wordDelimiter ?? "");
        }