/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter Unisharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

package com.pullenti.unitext.internal.html;

// Парсинг Html-текста
public class HtmlParser {

    public static HtmlNode parse(StringBuilder sHtml, boolean preserveWhitespaces) {
        int i;
        int j;
        int k;
        HtmlNode par;
        HtmlNode nod;
        String tmpHtml = sHtml.toString();
        sHtml.setLength(0);
        for (i = 0; i < tmpHtml.length(); i++) {
            if (!com.pullenti.unisharp.Utils.isWhitespace(tmpHtml.charAt(i))) 
                break;
        }
        String newLine = "\r";
        for (; i < tmpHtml.length(); i++) {
            char ch = tmpHtml.charAt(i);
            if (ch == '\t') 
                sHtml.append("    ");
            else if (ch != '\r' && ch != '\n') 
                sHtml.append(ch);
            else if (ch == '\n') 
                sHtml.append(newLine);
            else if (ch == '\r') {
                if (((i + 1) < tmpHtml.length()) && tmpHtml.charAt(i + 1) == '\n') 
                    i++;
                sHtml.append(newLine);
            }
        }
        String _html = sHtml.toString();
        java.util.ArrayList<HtmlParserNode> items = new java.util.ArrayList<HtmlParserNode>();
        HtmlParserNode pn = new HtmlParserNode();
        int preserve = 0;
        for (i = 0; i < _html.length(); i++) {
            String tag = null;
            for (j = items.size() - 1; j >= 0; j--) {
                if (items.get(j).tagName != null) {
                    if (com.pullenti.unisharp.Utils.stringsEq(items.get(j).tagName, "SCRIPT") && items.get(j).tagType == HtmlParserNode.TagTypes.OPEN) 
                        tag = "SCRIPT";
                    break;
                }
            }
            if (items.size() == 47) {
            }
            if (!pn.analize(_html, i, tag, preserve > 0 || preserveWhitespaces)) 
                break;
            i = pn.indexTo;
            if (com.pullenti.unisharp.Utils.stringsEq(pn.tagName, "PRE")) {
                if (pn.tagType == HtmlParserNode.TagTypes.OPEN) 
                    preserve++;
                else if (pn.tagType == HtmlParserNode.TagTypes.CLOSE) 
                    preserve--;
            }
            if (com.pullenti.unisharp.Utils.stringsEq(pn.tagName, "META")) {
                String val = null;
                com.pullenti.unisharp.Outargwrapper<String> wrapval24 = new com.pullenti.unisharp.Outargwrapper<String>();
                boolean inoutres25 = com.pullenti.unisharp.Utils.tryGetValue(pn.attributes, "CONTENT", wrapval24);
                val = wrapval24.value;
                if (pn.attributes != null && inoutres25) {
                    if (com.pullenti.unisharp.Utils.stringsEq(val, "Word.Document")) 
                        preserve = 1;
                    else if ((val.indexOf("Microsoft Word") >= 0)) 
                        preserve = 1;
                }
            }
            pn.whitespacePreserve = preserve > 0 || preserveWhitespaces;
            if (pn.isEmpty()) 
                continue;
            items.add(pn);
            if (pn.tagName != null) 
                pn.tag = HtmlTag.findTag(pn.tagName);
            pn.closeTagIndex = -1;
            pn = new HtmlParserNode();
        }
        java.util.ArrayList<HtmlParserNode> stack = new java.util.ArrayList<HtmlParserNode>();
        boolean error = false;
        for (i = 0; i < items.size(); i++) {
            pn = items.get(i);
            if (pn.tag == null) 
                continue;
            if (pn.tagType == HtmlParserNode.TagTypes.CLOSE) {
                if (!pn.tag.getEndtagRequired() || stack.size() == 0) 
                    continue;
                HtmlParserNode pp = stack.get(stack.size() - 1);
                if (pp.tag == pn.tag) {
                    stack.remove(stack.size() - 1);
                    pp.closeTagIndex = i;
                    continue;
                }
                for (j = stack.size() - 1; j >= 0; j--) {
                    if (stack.get(j).tag == pn.tag) 
                        break;
                }
                if (j < 0) 
                    continue;
                stack.get(j).closeTagIndex = i;
                for(int jjj = j + stack.size() - j - 1, mmm = j; jjj >= mmm; jjj--) stack.remove(jjj);
                continue;
            }
            if (pn.tagType == HtmlParserNode.TagTypes.OPENCLOSE) {
                pn.closeTagIndex = i;
                continue;
            }
            if (pn.tagType != HtmlParserNode.TagTypes.OPEN) 
                continue;
            if (pn.tag.isEmpty()) {
                pn.closeTagIndex = i;
                continue;
            }
            if (pn.tag.getEndtagRequired()) 
                stack.add(pn);
        }
        if (stack.size() > 0) 
            error = true;
        if (error) {
        }
        for (i = 0; i < items.size(); i++) {
            pn = items.get(i);
            if (com.pullenti.unisharp.Utils.stringsEq(pn.tagName, "BR")) {
            }
            if (pn.closeTagIndex >= 0 || pn.tagName == null || pn.tagType != HtmlParserNode.TagTypes.OPEN) 
                continue;
            int maxi = -1;
            for (j = i - 1; j >= 0; j--) {
                if (items.get(j).closeTagIndex > i) {
                    maxi = items.get(j).closeTagIndex;
                    break;
                }
            }
            if (maxi < 0) 
                maxi = items.size() - 1;
            int firstItemWithSameTag = -1;
            k = 1;
            for (j = i + 1; j <= maxi; j++) {
                if (items.get(j).closeTagIndex >= j) 
                    j = items.get(j).closeTagIndex;
                else if (com.pullenti.unisharp.Utils.stringsEq(items.get(j).tagName, pn.tagName)) {
                    if (items.get(j).tagType != HtmlParserNode.TagTypes.CLOSE && (firstItemWithSameTag < 0)) 
                        firstItemWithSameTag = j;
                    if (items.get(j).tagType == HtmlParserNode.TagTypes.OPEN) 
                        k++;
                    else if (items.get(j).tagType == HtmlParserNode.TagTypes.CLOSE) {
                        k--;
                        if (k == 0) {
                            pn.closeTagIndex = j;
                            break;
                        }
                    }
                }
            }
            if (pn.closeTagIndex >= 0) 
                continue;
            if (com.pullenti.unisharp.Utils.stringsEq(pn.tagName, "HTML")) {
                pn.closeTagIndex = items.size() - 1;
                continue;
            }
            if (firstItemWithSameTag >= 0) 
                pn.closeTagIndex = firstItemWithSameTag - 1;
            else {
                if (items.get(maxi).tagName != null) 
                    pn.closeTagIndex = maxi - 1;
                else 
                    pn.closeTagIndex = maxi;
                if (com.pullenti.unisharp.Utils.stringsEq(pn.tagName, "HEAD")) {
                    for (j = i + 1; j < items.size(); j++) {
                        if (com.pullenti.unisharp.Utils.stringsEq(items.get(j).tagName, "BODY")) {
                            pn.closeTagIndex = j - 1;
                            break;
                        }
                    }
                }
                else if (com.pullenti.unisharp.Utils.stringsEq(pn.tagName, "P")) {
                    for (j = i + 1; j < items.size(); j++) {
                        if (items.get(j).tag != null && !items.get(j).tag.isInline()) {
                            pn.closeTagIndex = j - 1;
                            break;
                        }
                    }
                }
            }
        }
        java.util.ArrayList<HtmlNode> resList = new java.util.ArrayList<HtmlNode>();
        for (i = 0; i < items.size(); i++) {
            items.get(i).printed = false;
        }
        for (i = 0; i < items.size(); i++) {
            if (items.get(i).printed) 
                continue;
            com.pullenti.unisharp.Outargwrapper<Integer> wrapj26 = new com.pullenti.unisharp.Outargwrapper<Integer>();
            nod = createNode(items, i, wrapj26);
            j = (wrapj26.value != null ? wrapj26.value : 0);
            if (j < 0) 
                break;
            if (j < i) {
            }
            if (nod == null) {
                i = j;
                continue;
            }
            if (i == 0 && j == (items.size() - 1)) {
                nod.correctRusTexts(0);
                return nod;
            }
            resList.add(nod);
            i = j;
        }
        if (resList.size() == 0) 
            return null;
        for (HtmlNode li : resList) {
            li.correctRusTexts(0);
        }
        if (resList.size() == 1) 
            return resList.get(0);
        HtmlNode res = new HtmlNode();
        res.tagName = "HTML";
        res.sourceHtmlPosition = 0;
        res.sourceHtmlLength = _html.length();
        for (HtmlNode ch : resList) {
            res.children.add(ch);
            ch.parent = res;
        }
        return res;
    }

    private static HtmlNode createNode(java.util.ArrayList<HtmlParserNode> list, int indFrom, com.pullenti.unisharp.Outargwrapper<Integer> indTo) {
        indTo.value = indFrom;
        if ((indFrom < 0) || indFrom >= list.size()) 
            return null;
        HtmlParserNode pn = list.get(indFrom);
        if (pn.tagType == HtmlParserNode.TagTypes.CLOSE) {
            pn.printed = true;
            indTo.value = indFrom;
            return null;
        }
        if (pn.printed) 
            return null;
        HtmlNode res = new HtmlNode();
        res.sourceHtmlPosition = pn.indexFrom;
        res.sourceHtmlEndPosition = pn.indexTo;
        res.whitespacePreserve = pn.whitespacePreserve;
        res.whitespaceBefore = pn.whitespaceBefore;
        if (pn.tagName == null) {
            if (pn.pureText == null) 
                return null;
            res.text = pn.pureText;
            pn.printed = true;
            return res;
        }
        res.tagName = pn.tagName;
        res.attrs = pn.attributes;
        res.text = pn.pureText;
        pn.printed = true;
        if (com.pullenti.unisharp.Utils.stringsEq(res.tagName, "SPAN")) {
        }
        if (pn.closeTagIndex <= indFrom) 
            return res;
        indTo.value = pn.closeTagIndex;
        HtmlParserNode cl = list.get(pn.closeTagIndex);
        if (cl.tagType == HtmlParserNode.TagTypes.CLOSE && com.pullenti.unisharp.Utils.stringsEq(cl.tagName, pn.tagName)) {
            res.sourceHtmlEndPosition = cl.indexTo;
            if ((indFrom + 2) == pn.closeTagIndex && list.get(indFrom + 1).tagName == null) {
                res.text = list.get(indFrom + 1).pureText;
                return res;
            }
        }
        else if (pn.closeTagIndex > indFrom) {
            res.sourceHtmlEndPosition = list.get(pn.closeTagIndex).indexTo;
            if ((indFrom + 1) == pn.closeTagIndex && list.get(indFrom + 1).tagName == null) {
                res.text = list.get(indFrom + 1).pureText;
                indTo.value = indFrom + 1;
                return res;
            }
        }
        else {
        }
        for (int i = indFrom + 1; i <= pn.closeTagIndex; i++) {
            if (list.get(i).printed) 
                continue;
            int j;
            com.pullenti.unisharp.Outargwrapper<Integer> wrapj27 = new com.pullenti.unisharp.Outargwrapper<Integer>();
            HtmlNode chi = createNode(list, i, wrapj27);
            j = (wrapj27.value != null ? wrapj27.value : 0);
            if (j < i) 
                break;
            if (chi != null) {
                if (chi.getTotalChildren() > 100) {
                }
                res.children.add(chi);
                chi.parent = res;
                if (com.pullenti.unisharp.Utils.stringsEq(chi.tagName, "UL")) {
                }
            }
            i = j;
        }
        return res;
    }


    private static java.util.HashMap<String, Integer> m_TableTags;
    public HtmlParser() {
    }
    
    static {
        m_TableTags = new java.util.HashMap<String, Integer>();
        m_TableTags.put("TABLE", 0);
        m_TableTags.put("TBODY", 1);
        m_TableTags.put("THEAD", 1);
        m_TableTags.put("TFOOT", 1);
        m_TableTags.put("TR", 2);
        m_TableTags.put("TH", 3);
        m_TableTags.put("TD", 3);
        m_TableTags.put("UL", 0);
        m_TableTags.put("OL", 0);
        m_TableTags.put("DL", 0);
        m_TableTags.put("LI", 1);
        m_TableTags.put("DT", 1);
        m_TableTags.put("DD", 1);
    }
}
