/*
 * 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
 */

const Utils = require("./../../../unisharp/Utils");
const Hashtable = require("./../../../unisharp/Hashtable");
const RefOutArgWrapper = require("./../../../unisharp/RefOutArgWrapper");

const HtmlNode = require("./HtmlNode");
const HtmlParserNodeTagTypes = require("./HtmlParserNodeTagTypes");
const HtmlTag = require("./HtmlTag");
const HtmlParserNode = require("./HtmlParserNode");

// Парсинг Html-текста
class HtmlParser {
    
    static parse(sHtml, preserveWhitespaces = false) {
        let i = 0;
        let j = 0;
        let k = 0;
        let par = null;
        let nod = null;
        let tmpHtml = sHtml.toString();
        sHtml.length = 0;
        for (i = 0; i < tmpHtml.length; i++) {
            if (!Utils.isWhitespace(tmpHtml[i])) 
                break;
        }
        let newLine = "\r";
        for (; i < tmpHtml.length; i++) {
            let ch = tmpHtml[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[i + 1] === '\n') 
                    i++;
                sHtml.append(newLine);
            }
        }
        let _html = sHtml.toString();
        let items = new Array();
        let pn = new HtmlParserNode();
        let preserve = 0;
        for (i = 0; i < _html.length; i++) {
            let tag = null;
            for (j = items.length - 1; j >= 0; j--) {
                if (items[j].tagName !== null) {
                    if (items[j].tagName === "SCRIPT" && items[j].tagType === HtmlParserNodeTagTypes.OPEN) 
                        tag = "SCRIPT";
                    break;
                }
            }
            if (items.length === 47) {
            }
            if (!pn.analize(_html, i, tag, preserve > 0 || preserveWhitespaces)) 
                break;
            i = pn.indexTo;
            if (pn.tagName === "PRE") {
                if (pn.tagType === HtmlParserNodeTagTypes.OPEN) 
                    preserve++;
                else if (pn.tagType === HtmlParserNodeTagTypes.CLOSE) 
                    preserve--;
            }
            if (pn.tagName === "META") {
                let val = null;
                let wrapval24 = new RefOutArgWrapper();
                let inoutres25 = pn.attributes.tryGetValue("CONTENT", wrapval24);
                val = wrapval24.value;
                if (pn.attributes !== null && inoutres25) {
                    if (val === "Word.Document") 
                        preserve = 1;
                    else if (val.includes("Microsoft Word")) 
                        preserve = 1;
                }
            }
            pn.whitespacePreserve = preserve > 0 || preserveWhitespaces;
            if (pn.isEmpty) 
                continue;
            items.push(pn);
            if (pn.tagName !== null) 
                pn.tag = HtmlTag.findTag(pn.tagName);
            pn.closeTagIndex = -1;
            pn = new HtmlParserNode();
        }
        let stack = new Array();
        let error = false;
        for (i = 0; i < items.length; i++) {
            pn = items[i];
            if (pn.tag === null) 
                continue;
            if (pn.tagType === HtmlParserNodeTagTypes.CLOSE) {
                if (!pn.tag.endtagRequired || stack.length === 0) 
                    continue;
                let pp = stack[stack.length - 1];
                if (pp.tag === pn.tag) {
                    stack.splice(stack.length - 1, 1);
                    pp.closeTagIndex = i;
                    continue;
                }
                for (j = stack.length - 1; j >= 0; j--) {
                    if (stack[j].tag === pn.tag) 
                        break;
                }
                if (j < 0) 
                    continue;
                stack[j].closeTagIndex = i;
                stack.splice(j, stack.length - j);
                continue;
            }
            if (pn.tagType === HtmlParserNodeTagTypes.OPENCLOSE) {
                pn.closeTagIndex = i;
                continue;
            }
            if (pn.tagType !== HtmlParserNodeTagTypes.OPEN) 
                continue;
            if (pn.tag.isEmpty) {
                pn.closeTagIndex = i;
                continue;
            }
            if (pn.tag.endtagRequired) 
                stack.push(pn);
        }
        if (stack.length > 0) 
            error = true;
        if (error) {
        }
        for (i = 0; i < items.length; i++) {
            pn = items[i];
            if (pn.tagName === "BR") {
            }
            if (pn.closeTagIndex >= 0 || pn.tagName === null || pn.tagType !== HtmlParserNodeTagTypes.OPEN) 
                continue;
            let maxi = -1;
            for (j = i - 1; j >= 0; j--) {
                if (items[j].closeTagIndex > i) {
                    maxi = items[j].closeTagIndex;
                    break;
                }
            }
            if (maxi < 0) 
                maxi = items.length - 1;
            let firstItemWithSameTag = -1;
            k = 1;
            for (j = i + 1; j <= maxi; j++) {
                if (items[j].closeTagIndex >= j) 
                    j = items[j].closeTagIndex;
                else if (items[j].tagName === pn.tagName) {
                    if (items[j].tagType !== HtmlParserNodeTagTypes.CLOSE && (firstItemWithSameTag < 0)) 
                        firstItemWithSameTag = j;
                    if (items[j].tagType === HtmlParserNodeTagTypes.OPEN) 
                        k++;
                    else if (items[j].tagType === HtmlParserNodeTagTypes.CLOSE) {
                        k--;
                        if (k === 0) {
                            pn.closeTagIndex = j;
                            break;
                        }
                    }
                }
            }
            if (pn.closeTagIndex >= 0) 
                continue;
            if (pn.tagName === "HTML") {
                pn.closeTagIndex = items.length - 1;
                continue;
            }
            if (firstItemWithSameTag >= 0) 
                pn.closeTagIndex = firstItemWithSameTag - 1;
            else {
                if (items[maxi].tagName !== null) 
                    pn.closeTagIndex = maxi - 1;
                else 
                    pn.closeTagIndex = maxi;
                if (pn.tagName === "HEAD") {
                    for (j = i + 1; j < items.length; j++) {
                        if (items[j].tagName === "BODY") {
                            pn.closeTagIndex = j - 1;
                            break;
                        }
                    }
                }
                else if (pn.tagName === "P") {
                    for (j = i + 1; j < items.length; j++) {
                        if (items[j].tag !== null && !items[j].tag.isInline) {
                            pn.closeTagIndex = j - 1;
                            break;
                        }
                    }
                }
            }
        }
        let resList = new Array();
        for (i = 0; i < items.length; i++) {
            items[i].printed = false;
        }
        for (i = 0; i < items.length; i++) {
            if (items[i].printed) 
                continue;
            let wrapj26 = new RefOutArgWrapper();
            nod = HtmlParser.createNode(items, i, wrapj26);
            j = wrapj26.value;
            if (j < 0) 
                break;
            if (j < i) {
            }
            if (nod === null) {
                i = j;
                continue;
            }
            if (i === 0 && j === (items.length - 1)) {
                nod.correctRusTexts(0);
                return nod;
            }
            resList.push(nod);
            i = j;
        }
        if (resList.length === 0) 
            return null;
        for (const li of resList) {
            li.correctRusTexts(0);
        }
        if (resList.length === 1) 
            return resList[0];
        let res = new HtmlNode();
        res.tagName = "HTML";
        res.sourceHtmlPosition = 0;
        res.sourceHtmlLength = _html.length;
        for (const ch of resList) {
            res.children.push(ch);
            ch.parent = res;
        }
        return res;
    }
    
    static createNode(list, indFrom, indTo) {
        indTo.value = indFrom;
        if ((indFrom < 0) || indFrom >= list.length) 
            return null;
        let pn = list[indFrom];
        if (pn.tagType === HtmlParserNodeTagTypes.CLOSE) {
            pn.printed = true;
            indTo.value = indFrom;
            return null;
        }
        if (pn.printed) 
            return null;
        let 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 (res.tagName === "SPAN") {
        }
        if (pn.closeTagIndex <= indFrom) 
            return res;
        indTo.value = pn.closeTagIndex;
        let cl = list[pn.closeTagIndex];
        if (cl.tagType === HtmlParserNodeTagTypes.CLOSE && cl.tagName === pn.tagName) {
            res.sourceHtmlEndPosition = cl.indexTo;
            if ((indFrom + 2) === pn.closeTagIndex && list[indFrom + 1].tagName === null) {
                res.text = list[indFrom + 1].pureText;
                return res;
            }
        }
        else if (pn.closeTagIndex > indFrom) {
            res.sourceHtmlEndPosition = list[pn.closeTagIndex].indexTo;
            if ((indFrom + 1) === pn.closeTagIndex && list[indFrom + 1].tagName === null) {
                res.text = list[indFrom + 1].pureText;
                indTo.value = indFrom + 1;
                return res;
            }
        }
        else {
        }
        for (let i = indFrom + 1; i <= pn.closeTagIndex; i++) {
            if (list[i].printed) 
                continue;
            let j = 0;
            let wrapj27 = new RefOutArgWrapper();
            let chi = HtmlParser.createNode(list, i, wrapj27);
            j = wrapj27.value;
            if (j < i) 
                break;
            if (chi !== null) {
                if (chi.totalChildren > 100) {
                }
                res.children.push(chi);
                chi.parent = res;
                if (chi.tagName === "UL") {
                }
            }
            i = j;
        }
        return res;
    }
    
    static static_constructor() {
        HtmlParser.m_TableTags = null;
        HtmlParser.m_TableTags = new Hashtable();
        HtmlParser.m_TableTags.put("TABLE", 0);
        HtmlParser.m_TableTags.put("TBODY", 1);
        HtmlParser.m_TableTags.put("THEAD", 1);
        HtmlParser.m_TableTags.put("TFOOT", 1);
        HtmlParser.m_TableTags.put("TR", 2);
        HtmlParser.m_TableTags.put("TH", 3);
        HtmlParser.m_TableTags.put("TD", 3);
        HtmlParser.m_TableTags.put("UL", 0);
        HtmlParser.m_TableTags.put("OL", 0);
        HtmlParser.m_TableTags.put("DL", 0);
        HtmlParser.m_TableTags.put("LI", 1);
        HtmlParser.m_TableTags.put("DT", 1);
        HtmlParser.m_TableTags.put("DD", 1);
    }
}


HtmlParser.static_constructor();

module.exports = HtmlParser