/// <summary>
        /// Balances the HTML and safely truncates it, using a custom algorithm
        /// to determine how much each character/string counts against maxCost.
        /// </summary>
        public static string Balance(string html, int maxCost, HTMLBalancerCostFilter costFilter, bool ellipsis)
        {
            bool appendEllipsis = false;
            SimpleHtmlParser parser = new SimpleHtmlParser(html);

            ArrayList openTags = new ArrayList();
            StringBuilder output = new StringBuilder();
            long balance = 0;  // long to make sure that int32.MaxValue does not cause overflow

            if (costFilter == null)
                costFilter = new DefaultCostFilter();

            Element el;
            while (null != (el = parser.Next()))
            {
                if (el is StyleElement ||
                   el is ScriptElement ||
                   el is Comment ||
                   el is MarkupDirective)
                {
                    continue;
                }

                long lenLeft = Math.Max(0, maxCost - balance - LengthToClose(costFilter, openTags));

                if (el is Tag)
                {
                    if (el is BeginTag && ((BeginTag)el).Unterminated)
                        continue;  // skip corrupted tags

                    if (TagCost(costFilter, openTags, (Tag)el) > lenLeft)
                        break;  // don't use this tag; we're done
                    else
                    {
                        RegisterTag(openTags, (Tag)el);
                        output.Append(el.ToString());
                        balance += costFilter.ElementCost(el);
                    }
                }
                else if (el is Text)
                {
                    if (costFilter.ElementCost(el) > lenLeft)
                    {
                        // shrink down the text to fit
                        output.Append(costFilter.TruncateText((Text)el, (int)lenLeft));
                        appendEllipsis = true;
                        break;
                    }
                    else
                    {
                        // plenty of room
                        output.Append(el.ToString());
                        balance += costFilter.ElementCost(el);
                    }

                    //update the text end index
                }
                else
                {
                    if (costFilter.ElementCost(el) > lenLeft)
                        break;
                    else
                    {
                        output.Append(el.ToString());
                        balance += costFilter.ElementCost(el);
                    }
                }
            }

            // Append an ellipsis if we truncated text
            // We use "..." here rather than TextHelper.Ellipsis, because some mail clients don't understand "\u2026".
            if (ellipsis && appendEllipsis)
                output.Append("...");

            for (int i = openTags.Count - 1; i >= 0; i--)
            {
                output.Append(MakeEndTag((string)openTags[i]));
            }

            return output.ToString();
        }
        /// <summary>
        /// Balances the HTML and safely truncates it, using a custom algorithm
        /// to determine how much each character/string counts against maxCost.
        /// </summary>
        public static string Balance(string html, int maxCost, HTMLBalancerCostFilter costFilter, bool ellipsis)
        {
            bool             appendEllipsis = false;
            SimpleHtmlParser parser         = new SimpleHtmlParser(html);

            ArrayList     openTags = new ArrayList();
            StringBuilder output   = new StringBuilder();
            long          balance  = 0; // long to make sure that int32.MaxValue does not cause overflow

            if (costFilter == null)
            {
                costFilter = new DefaultCostFilter();
            }

            Element el;

            while (null != (el = parser.Next()))
            {
                if (el is StyleElement ||
                    el is ScriptElement ||
                    el is Comment ||
                    el is MarkupDirective)
                {
                    continue;
                }

                long lenLeft = Math.Max(0, maxCost - balance - LengthToClose(costFilter, openTags));

                if (el is Tag)
                {
                    if (el is BeginTag && ((BeginTag)el).Unterminated)
                    {
                        continue;  // skip corrupted tags
                    }
                    if (TagCost(costFilter, openTags, (Tag)el) > lenLeft)
                    {
                        break;  // don't use this tag; we're done
                    }
                    else
                    {
                        RegisterTag(openTags, (Tag)el);
                        output.Append(el.ToString());
                        balance += costFilter.ElementCost(el);
                    }
                }
                else if (el is Text)
                {
                    if (costFilter.ElementCost(el) > lenLeft)
                    {
                        // shrink down the text to fit
                        output.Append(costFilter.TruncateText((Text)el, (int)lenLeft));
                        appendEllipsis = true;
                        break;
                    }
                    else
                    {
                        // plenty of room
                        output.Append(el.ToString());
                        balance += costFilter.ElementCost(el);
                    }

                    //update the text end index
                }
                else
                {
                    if (costFilter.ElementCost(el) > lenLeft)
                    {
                        break;
                    }
                    else
                    {
                        output.Append(el.ToString());
                        balance += costFilter.ElementCost(el);
                    }
                }
            }

            // Append an ellipsis if we truncated text
            // We use "..." here rather than TextHelper.Ellipsis, because some mail clients don't understand "\u2026".
            if (ellipsis && appendEllipsis)
            {
                output.Append("...");
            }

            for (int i = openTags.Count - 1; i >= 0; i--)
            {
                output.Append(MakeEndTag((string)openTags[i]));
            }

            return(output.ToString());
        }