/// <summary>
        /// Gets a contents listing for the section formatted according to the TEN standard
        /// </summary>
        /// <param name="sectionNumber">The number of the current section</param>
        /// <param name="startItemNumber">Start numbering of articles at this number</param>
        /// <returns></returns>
        public string ToContentsString(int sectionNumber, int startItemNumber)
        {
            StringBuilder sb = new StringBuilder();

            // build the title of the section
            sb.Append(Environment.NewLine);
            sb.Append(Properties.Resources.Section + " ");
            sb.Append(sectionNumber.ToString(CultureInfo.CurrentCulture));
            sb.Append(Properties.Resources.SectionNumberSeparator);
            sb.Append(TextEmailNewsletter.EnsureFullStop(this.Title));
            sb.Append(Environment.NewLine);
            sb.Append(Environment.NewLine);

            // get a listing of each article in the section
            for (int i = 0; i < this.articles.Count; i++)
            {
                sb.Append(this.articles[i].ToContentsString(startItemNumber));
                startItemNumber++;
            }

            return(sb.ToString());
        }
        /// <summary>
        /// Gets the text of the section formatted according to the TEN standard
        /// </summary>
        /// <param name="sectionNumber">The number of this section in the newsletter (eg Section 2)</param>
        /// <param name="startItemNumber">The number of the first article in this section (article numbering continues across sections)</param>
        /// <returns></returns>
        public string ToString(int sectionNumber, int startItemNumber)
        {
            StringBuilder sb = new StringBuilder();

            // build the title of the section
            if (this.title.Length > 0)
            {
                sb.Append(Environment.NewLine);
                sb.Append(Properties.Resources.SectionStructurePrefix + Properties.Resources.Section + " ");
                sb.Append(sectionNumber.ToString(CultureInfo.CurrentCulture));
                sb.Append(Properties.Resources.SectionNumberSeparator);
                sb.Append(TextEmailNewsletter.EnsureFullStop(this.title));
                sb.Append(Environment.NewLine);
                sb.Append(Environment.NewLine);
                sb.Append(Environment.NewLine);
            }

            // build each article in the section
            for (int i = 0; i < this.articles.Count; i++)
            {
                sb.Append(this.articles[i].ToString(startItemNumber));
                startItemNumber++;
            }

            // build a section footer (specified by the TEN standard)
            if (this.title.Length > 0)
            {
                sb.Append("[");
                sb.Append(this.title);
                sb.Append(" " + Properties.Resources.Section.ToLower(CultureInfo.CurrentCulture) + Properties.Resources.Ends + "].");
                sb.Append(Environment.NewLine);
                sb.Append(Environment.NewLine);
            }

            return(sb.ToString());
        }
        /// <summary>
        /// Text should be wrapped at 70 characters wide for less capable email clients
        /// </summary>
        /// <param name="text">Text to be wrapped</param>
        /// <returns>Wrapped text</returns>
        public static string WrapLines(string text)
        {
            if (text == null)
            {
                return(String.Empty);
            }

            int wrapAt = 70;

            StringBuilder sb = new StringBuilder();

            // remove \r to make new lines less complicated to deal with
            text = text.Replace("\r", "");

            // split text into lines to work with a line at a time
            string[] lines = text.Split('\n');
            string[] words;
            int      iLine;
            int      lineLength;

            for (iLine = 0; iLine < lines.Length; iLine++)
            {
                // leave URLs on their own line no matter how long
                // Note: MatchEvaluator_ConvertLinks will have put them on their own line when called from FilteredText property
                if (lines[iLine].StartsWith("#MatchedUrl#", StringComparison.Ordinal))
                {
                    sb.Append(Environment.NewLine);
                    sb.Append(lines[iLine].Substring(12));
                    sb.Append(Environment.NewLine);
                    lineLength = 0;
                    continue;
                }

                // ensure line ends with fullstop, according to TEN spec
                lines[iLine] = TextEmailNewsletter.EnsureFullStop(lines[iLine]);

                // split into words so that we don't split lines mid-word
                words = lines[iLine].Trim().Split(' ');

                // monitor how long the line we're building has become
                lineLength = 0;
                int i = 0;

                do
                {
                    // an "empty" word was a paragraph break
                    if (words[i].Length == 0)
                    {
                        sb.Append(Environment.NewLine);
                        sb.Append(Environment.NewLine);
                        i++;
                        continue;
                    }

                    // If adding this word would make the line too long, start a new line
                    if ((lineLength + words[i].Length) >= wrapAt)
                    {
                        sb.Append(Environment.NewLine);
                        lineLength = 0;
                    }

                    // make sure line doesn't start with a full stop (which can happen if a link is at the end of a sentence, but not the end of a para)
                    if (words[i] == ".")
                    {
                    }
                    else
                    {
                        // add the word
                        sb.Append(words[i] + " ");
                        lineLength += (words[i].Length + 1);
                    }
                    i++;
                }while (i < words.Length);
            }

            // don't allow it to end with a fullstop on a new line
            if (sb.ToString().EndsWith(Environment.NewLine + ". ", StringComparison.Ordinal))
            {
                // sb.Remove(sb.Length-2-Environment.NewLine.Length,Environment.NewLine.Length); // remove the newline
                sb.Remove(sb.Length - 2 - Environment.NewLine.Length, Environment.NewLine.Length + 1); // remove the newline and fullstop
            }

            return(sb.ToString());
        }