/*
 * 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 fs = require('fs');
const path = require('path');
const Utils = require("./../../../unisharp/Utils");
const Hashtable = require("./../../../unisharp/Hashtable");
const RefOutArgWrapper = require("./../../../unisharp/RefOutArgWrapper");
const StringBuilder = require("./../../../unisharp/StringBuilder");

const UnitextPlaintextType = require("./../../UnitextPlaintextType");
const UnitextPlaintext = require("./../../UnitextPlaintext");
const UnitextList = require("./../../UnitextList");
const GetPlaintextParam = require("./../../GetPlaintextParam");
const UniTextGenCell = require("./../uni/UniTextGenCell");
const WebdingsHelper = require("./../misc/WebdingsHelper");
const SymbolHelper = require("./../misc/SymbolHelper");
const WingdingsHelper = require("./../misc/WingdingsHelper");
const UnitextHyperlink = require("./../../UnitextHyperlink");
const UnitextImage = require("./../../UnitextImage");
const UnitextGenTable = require("./../uni/UnitextGenTable");
const HtmlNode = require("./HtmlNode");
const UnitextItem = require("./../../UnitextItem");
const FileFormat = require("./../../FileFormat");
const UnitextFootnote = require("./../../UnitextFootnote");
const UnitextDocument = require("./../../UnitextDocument");
const HtmlTag = require("./HtmlTag");
const UnitextListitem = require("./../../UnitextListitem");
const UnitextComment = require("./../../UnitextComment");
const UnitextGen = require("./../uni/UnitextGen");
const UnitextHelper = require("./../uni/UnitextHelper");
const UnitextPagesectionItem = require("./../../UnitextPagesectionItem");
const UnitextPagesection = require("./../../UnitextPagesection");
const HtmlSection = require("./HtmlSection");

class UnitextHtmlGen {
    
    constructor() {
        this.m_DirName = null;
        this.m_Images = null;
        this.m_Foots = new Hashtable();
        this.m_Anno = new Hashtable();
        this.m_Shapes = new Hashtable();
        this.m_Ignored = new Array();
    }
    
    create(nod, dirName, images, pars) {
        if (dirName !== null && fs.existsSync(dirName) && fs.statSync(dirName).isDirectory()) 
            this.m_DirName = dirName;
        this.m_Images = images;
        let doc = UnitextDocument._new47(FileFormat.HTML);
        this._prepare(nod, false);
        if (pars.loadDocumentStructure) {
            let s = HtmlSection.create(nod);
            if (s !== null) {
                doc.content = s.generate(this);
                if (s.head.length > 0 || s.tail.length > 0) {
                    doc.sections.push(new UnitextPagesection());
                    if (s.head.length > 0) {
                        let gen = new UnitextGen();
                        for (const n of s.head) {
                            this.getUniText(n, gen, null, 0);
                        }
                        doc.sections[0].items.push(UnitextPagesectionItem._new48(gen.finish(true, null)));
                    }
                    if (s.tail.length > 0) {
                        let gen = new UnitextGen();
                        for (const n of s.tail) {
                            this.getUniText(n, gen, null, 0);
                        }
                        doc.sections[0].items.push(UnitextPagesectionItem._new49(true, gen.finish(true, null)));
                    }
                }
            }
        }
        if (doc.content === null) {
            let gen = new UnitextGen();
            this.getUniText(nod, gen, null, 0);
            doc.content = gen.finish(true, null);
        }
        let h = nod.findSubnode("HEAD", null, null);
        let ti = (h !== null ? h.findSubnode("TITLE", null, null) : null);
        if (ti !== null && ti.text !== null && !doc.attrs.containsKey("title")) 
            doc.attrs.put("title", ti.text.trim());
        doc.optimize(false, null);
        return doc;
    }
    
    _prepare(nod, okFoots) {
        let val = nod.getAttribute("STYLE");
        if (val !== null && ((val.includes("footnote-list") || val.includes("endnote-list") || val.includes("comment-list")))) {
            okFoots = true;
            this.m_Ignored.push(nod);
        }
        if (okFoots && nod.tagName === "P") {
            val = nod.getAttribute("CLASS");
            if (val === "MsoFootnoteText" || val === "MsoEndnoteText" || val === "MsoCommentText") {
                let nam = null;
                let val1 = null;
                if ((((val1 = nod.getAttribute("NAME")))) !== null) 
                    nam = val1;
                else {
                    let ch = nod.findSubnode("A", "NAME", null);
                    if (ch === null && nod.parent !== null && val === "MsoCommentText") 
                        ch = nod.parent.findSubnode("A", "NAME", null);
                    if (ch !== null) {
                        nam = (val1 = ch.getAttribute("NAME"));
                        if (nam !== null) 
                            this.m_Ignored.push(ch);
                    }
                }
                if (nam !== null) {
                    if (val.includes("Comment")) {
                        if (!this.m_Anno.containsKey(nam)) {
                            let gg = new UnitextGen();
                            this.getUniText(nod, gg, null, 0);
                            let it = gg.finish(true, null);
                            if (it !== null) {
                                let tmp = new StringBuilder();
                                it.getPlaintext(tmp, null);
                                if (tmp.length > 0) {
                                    if (tmp.toString().indexOf('[') >= 0) {
                                        let ii = tmp.toString().indexOf(']');
                                        if (ii > 0) 
                                            tmp.remove(0, ii + 1);
                                    }
                                    this.m_Anno.put(nam, UnitextComment._new50(tmp.toString().trim()));
                                }
                            }
                        }
                    }
                    else {
                        let gg = new UnitextGen();
                        this.getUniText(nod, gg, null, 0);
                        let fn = new UnitextFootnote();
                        fn.isEndnote = val.includes("Endnote");
                        fn.content = gg.finish(true, null);
                        if (!this.m_Foots.containsKey(nam)) 
                            this.m_Foots.put(nam, fn);
                    }
                }
                return;
            }
        }
        for (let ii = 0; ii < nod.children.length; ii++) {
            this._prepare(nod.children[ii], okFoots);
        }
    }
    
    getUniText(nod, res, blk, lev) {
        if (lev > 100) 
            return;
        let tagName = nod.tagName;
        if ((tagName === "SCRIPT" || tagName === "NOSCRIPT" || tagName === "STYLE") || tagName === "META" || tagName === "TITLE") 
            return;
        if (tagName === "DEL") 
            return;
        if (tagName === "TEMPLATE") 
            return;
        if (this.m_Ignored.includes(nod)) 
            return;
        let tag = HtmlTag.findTag(tagName);
        let st = nod.getAttribute("STYLE");
        if (st !== null && st.toLowerCase().includes("page-break-before")) 
            res.appendPagebreak();
        if (tag !== null && tag.name === "BR") {{
                    if (res !== null) 
                        res.appendNewline(false, false);
                    return;
                }
        }
        if (tag !== null && tag.name === "TABLE") {
            let tbl = new UnitextGenTable();
            for (let ii = 0; ii < nod.children.length; ii++) {
                this.getUniText(nod.children[ii], null, tbl, lev + 1);
            }
            if (res !== null) {
                let tab = tbl.convert();
                if (tab !== null) {
                    if ((((tab.width = nod.getStyleValue("width")))) === null) 
                        tab.width = nod.getAttribute("WIDTH");
                    let vv = nod.getAttribute("BORDER");
                    if (vv !== null) {
                        if (vv.startsWith("0")) 
                            tab.hideBorders = true;
                    }
                    else if ((((vv = nod.getStyleValue("border")))) !== null) {
                        if (vv.startsWith("0")) 
                            tab.hideBorders = true;
                    }
                    else if ((((vv = nod.getStyleValue("border-width")))) !== null) {
                        if (vv.startsWith("0")) 
                            tab.hideBorders = true;
                    }
                    if (nod.getStyleValue("BORDER") === "none") {
                        if (nod.getStyleValue("MSO-BORDER-ALT") === null) 
                            tab.hideBorders = true;
                    }
                    if (res.lastChar !== '\r') 
                        res.appendNewline(false, false);
                    res.append(tab, null, -1, false);
                }
                res.appendNewline(false, false);
            }
            return;
        }
        if (tag !== null && tag.name === "TR") {
            let tab = Utils.as(blk, UnitextGenTable);
            if (tab === null) 
                return;
            let row = new Array();
            tab.cells.push(row);
            for (let ii = 0; ii < nod.children.length; ii++) {
                let ch = nod.children[ii];
                let tag2 = HtmlTag.findTag(ch.tagName);
                if (tag2 === null || ((tag2.name !== "TD" && tag2.name !== "TH"))) 
                    continue;
                let cel = new UniTextGenCell();
                row.push(cel);
                let colsp = 1;
                let rowsp = 1;
                if (ch.getAttribute("ROWSPAN") !== null) {
                    let wraprowsp51 = new RefOutArgWrapper();
                    let inoutres52 = Utils.tryParseInt(ch.getAttribute("ROWSPAN"), wraprowsp51);
                    rowsp = wraprowsp51.value;
                    if (inoutres52) {
                        if (rowsp > 65534) 
                            rowsp = 65534;
                        cel.rowSpan = rowsp;
                    }
                }
                if (ch.getAttribute("COLSPAN") !== null) {
                    let wrapcolsp53 = new RefOutArgWrapper();
                    let inoutres54 = Utils.tryParseInt(ch.getAttribute("COLSPAN"), wrapcolsp53);
                    colsp = wrapcolsp53.value;
                    if (inoutres54) {
                        if (colsp < 100) 
                            cel.colSpan = colsp;
                    }
                }
                if (colsp <= 1) {
                    let wi = Utils.notNull(ch.getStyleValue("width"), ch.getAttribute("WIDTH"));
                    if (wi !== null) 
                        cel.width = wi;
                }
                let gg = new UnitextGen();
                this.getUniText(ch, gg, null, lev + 1);
                cel.content = gg.finish(true, null);
            }
            return;
        }
        if (tag !== null && tag.name === "COLGROUP") {
            let tab = Utils.as(blk, UnitextGenTable);
            if (tab === null) 
                return;
            for (let ii = 0; ii < nod.children.length; ii++) {
                let ch = nod.children[ii];
                let tag2 = HtmlTag.findTag(ch.tagName);
                if (tag2 === null || tag2.name !== "COL") 
                    continue;
                let wi = Utils.notNull(ch.getStyleValue("width"), ch.getAttribute("WIDTH"));
                tab.m_ColWidth.push(wi);
            }
            return;
        }
        if (tag !== null && ((tag.name === "OL" || tag.name === "UL"))) {
            let li = new UnitextList();
            let liNum = 0;
            let liTyp = null;
            if (tag.name === "OL") {
                let wrapliNum55 = new RefOutArgWrapper();
                let inoutres56 = Utils.tryParseInt(Utils.notNull(nod.getAttribute("START"), ""), wrapliNum55);
                liNum = wrapliNum55.value;
                if (!inoutres56) 
                    liNum = 1;
                liTyp = Utils.notNull(nod.getAttribute("TYPE"), "1");
            }
            else 
                li.unorderPrefix = "";
            for (let ii = 0; ii < nod.children.length; ii++) {
                let ch = nod.children[ii];
                let tag2 = HtmlTag.findTag(ch.tagName);
                if (tag2 === null || tag2.name !== "LI") 
                    continue;
                let it = new UnitextListitem();
                li.items.push(it);
                let gg = new UnitextGen();
                this.getUniText(ch, gg, null, lev + 1);
                it.content = gg.finish(true, null);
                if (liNum > 0 && liTyp !== null && li.unorderPrefix === null) {
                    let pref = HtmlNode._getLiNum(liNum, liTyp);
                    if (pref !== null) 
                        it.prefix = UnitextPlaintext._new57(pref);
                    liNum++;
                }
            }
            if (res !== null) 
                res.append(li, null, -1, false);
            return;
        }
        if (tag !== null && ((tag.name === "SUP" || tag.name === "SUB"))) {
            let tmp = new StringBuilder();
            if (nod.children.length === 0) 
                tmp.append(nod.text);
            else 
                for (let ii = 0; ii < nod.children.length; ii++) {
                    nod.children[ii]._getFullText(tmp, null, null);
                }
            let tt = tmp.toString().trim();
            if (tt.length > 0 && (tt.length < 10)) {
                res.append(UnitextPlaintext._new58(tt, (tag.name === "SUB" ? UnitextPlaintextType.SUB : UnitextPlaintextType.SUP)), null, -1, false);
                return;
            }
        }
        if (res === null) {
            for (let ii = 0; ii < nod.children.length; ii++) {
                this.getUniText(nod.children[ii], res, blk, lev + 1);
            }
            return;
        }
        if (tagName === "A") {
            let val = nod.getAttribute("HREF");
            if (val !== null) {
                let fn = null;
                let wrapfn60 = new RefOutArgWrapper();
                let inoutres61 = this.m_Foots.tryGetValue(val.substring(1), wrapfn60);
                fn = wrapfn60.value;
                if (val.startsWith("#") && inoutres61) {
                    res.append(fn, null, -1, false);
                    return;
                }
                if (val.startsWith("#") && this.m_Anno.containsKey(val.substring(1))) {
                    res.append(this.m_Anno.get(val.substring(1)), null, -1, false);
                    return;
                }
                if (nod.children.length > 0) {
                    let noTag = false;
                    if (nod.children.length > 20) 
                        noTag = true;
                    else 
                        for (const ch of nod.children) {
                            if (ch.hasTag("A") || ch.hasBlockTag()) {
                                noTag = true;
                                break;
                            }
                        }
                    if (noTag && (nod.parent instanceof HtmlNode)) {
                        let i = nod.parent.children.indexOf(nod);
                        if (i >= 0) 
                            nod.parent.children.splice(i + 1, 0, ...nod.children);
                        nod.children.splice(0, nod.children.length);
                    }
                }
                let gg = new UnitextGen();
                if (nod.text !== null) 
                    gg.appendText(nod.text, false);
                for (const ch of nod.children) {
                    this.getUniText(ch, gg, null, lev + 1);
                }
                let it = gg.finish(true, null);
                if (it !== null) {
                    let hr = UnitextHyperlink._new59(val);
                    hr.content = it;
                    res.append(hr, null, -1, false);
                    return;
                }
                val = nod.getAttribute("CLASS");
                if (Utils.compareStrings((val != null ? val : ""), "MSOCOMANCHOR", true) === 0) 
                    return;
            }
        }
        if (tagName === "V:TEXTBOX") {
        }
        if (tagName === "V:IMAGEDATA" || tagName === "IMG") {
            let shapes = nod.getAttribute("V:SHAPES");
            if (shapes !== null) {
                let ids = Utils.splitString(shapes, ' ', false);
            }
            let img = new UnitextImage();
            if ((((img.id = nod.getAttribute("SRC")))) !== null) {
                try {
                    if (this.m_DirName !== null) {
                        if (img.id !== null && !img.id.startsWith("http")) {
                            let fname = path.join(this.m_DirName, ((img.id != null ? img.id : "")));
                            if (!fs.existsSync(fname) && fs.statSync(fname).isFile()) 
                                fname = Utils.replaceString(fname, '/', '\\');
                            if (fs.existsSync(fname) && fs.statSync(fname).isFile()) 
                                img.content = UnitextHelper.loadDataFromFile(fname, 0);
                        }
                    }
                    else if (this.m_Images !== null) {
                        for (const kp of this.m_Images.entries) {
                            if (kp.key.endsWith(img.id)) {
                                img.content = kp.value;
                                break;
                            }
                        }
                    }
                    res.append(img, null, -1, false);
                    for (let hh = nod; hh !== null; hh = Utils.as(hh.parent, HtmlNode)) {
                        let val = null;
                        if ((((val = hh.getStyleValue("WIDTH")))) !== null) 
                            img.width = UnitextGen.convertToPt(val, "px");
                        if ((((val = hh.getStyleValue("HEIGHT")))) !== null) 
                            img.height = UnitextGen.convertToPt(val, "px");
                        if (img.width !== null || img.height !== null) 
                            break;
                        if ((((val = hh.getAttribute("WIDTH")))) !== null) 
                            img.width = UnitextGen.convertToPt(val, "px");
                        if ((((val = hh.getAttribute("HEIGHT")))) !== null) 
                            img.height = UnitextGen.convertToPt(val, "px");
                    }
                    if (img.width === null || img.height === null) 
                        img.width = (img.height = null);
                } catch (ex62) {
                }
                return;
            }
        }
        let isBlock = false;
        if (tag !== null && ((tag.isBlock || tag.isTable))) 
            isBlock = true;
        let isH = false;
        if (isBlock) {
            res.appendNewline(false, false);
            if (((tagName != null ? tagName : "")).length === 2) {
                if (((tagName[0] === 'H' || tagName[0] === 'h')) && Utils.isDigit(tagName[1])) {
                    isH = true;
                    res.appendNewline(false, false);
                    if (tagName[0] === '1') 
                        res.appendNewline(false, false);
                }
            }
        }
        if (!Utils.isNullOrEmpty(nod.text)) {
            let cou = 0;
            let wingdings = false;
            let webdings = false;
            let symbols = false;
            for (let pp = nod; pp !== null && (cou < 2); pp = Utils.as(pp.parent, HtmlNode),cou++) {
                let ff = Utils.notNull(pp.getStyleValue("font-family"), pp.getStyleValue("font"));
                if (ff !== null) {
                    if (ff.toUpperCase().includes("WINGDINGS")) 
                        wingdings = true;
                    else if (ff.toUpperCase().includes("WEBDINGS")) 
                        webdings = true;
                    else if (ff.toUpperCase().includes("SYMBOL")) 
                        symbols = true;
                    break;
                }
            }
            if (wingdings) 
                res.appendText(WingdingsHelper.getUnicodeString(nod.text), false);
            else if (webdings) 
                res.appendText(WebdingsHelper.getUnicodeString(nod.text), false);
            else if (symbols) 
                res.appendText(SymbolHelper.getUnicodeString(nod.text), false);
            else 
                res.appendText(nod.text, false);
        }
        else if (nod.children.length === 1) {
            let cou = 0;
            let nn = nod;
            for (; nn !== null; ) {
                if (nn.children.length !== 1) 
                    break;
                if (nn.children[0].text !== null) 
                    break;
                cou++;
                nn = nn.children[0];
            }
            if (cou > 100 && nn !== null) 
                nod = nn;
            else 
                nod = nod.children[0];
            this.getUniText(nod, res, null, lev + 1);
        }
        else {
            let first = true;
            let lists = null;
            let listId = null;
            for (let ii = 0; ii < nod.children.length; ii++) {
                let ch = nod.children[ii];
                let li = this.tryParseList(ch, lev + 1);
                if (li !== null && li.item.content === null && nod.tagName === "TD") 
                    li = null;
                if (li === null) {
                    if (lists !== null) {
                        if (ch.children.length === 0 && ((ch.text != null ? ch.text : "")).trim().length === 0) 
                            continue;
                        lists = null;
                        listId = null;
                    }
                }
                else if (li.listId !== listId && listId !== null) {
                    listId = null;
                    lists = null;
                }
                if (li !== null) {
                    if (lists === null) {
                        let list = new UnitextList();
                        if (res.lastChar !== '\r') 
                            res.appendNewline(false, false);
                        res.append(list, null, -1, false);
                        res.appendNewline(false, false);
                        lists = new Array();
                        lists.push(list);
                        listId = li.listId;
                    }
                    if (li.level === 3) {
                    }
                    if (li.level === lists.length) {
                        lists[0].items.push(li.item);
                        continue;
                    }
                    if (li.level < lists.length) {
                        while (li.level < lists.length) {
                            lists.splice(0, 1);
                        }
                        lists[0].items.push(li.item);
                        continue;
                    }
                    if (li.level === (lists.length + 1) && lists[0].items.length > 0) {
                        let last = lists[0].items[lists[0].items.length - 1];
                        if (last.sublist === null) 
                            last.sublist = UnitextList._new63(li.level - 1);
                        lists.splice(0, 0, last.sublist);
                        last.sublist.items.push(li.item);
                        continue;
                    }
                }
                if (first) 
                    first = false;
                else if (!ch.whitespacePreserve) {
                    if (ch.whitespaceBefore) 
                        res.appendText(" ", false);
                }
                this.getUniText(ch, res, null, lev + 1);
            }
        }
        if (isH) {
            res.appendNewline(false, false);
            if (tagName[0] === '1') 
                res.appendNewline(false, false);
        }
    }
    
    tryParseList(nod, lev) {
        if (nod.tagName !== "P") 
            return null;
        let val = nod.getAttribute("STYLE");
        if (val === null) 
            return null;
        let i = val.indexOf("mso-list:");
        if (i < 0) 
            return null;
        val = val.substring(i + 9).trim();
        let fi = Utils.splitString(val, ' ', false);
        if (fi.length < 3) 
            return null;
        if (!Utils.startsWithString(fi[2], "LFO", true)) 
            return null;
        let res = UnitextHtmlGen.MsoListItem._new64(fi[2]);
        let wrapi66 = new RefOutArgWrapper();
        let inoutres67 = Utils.tryParseInt(fi[1].substring(5), wrapi66);
        i = wrapi66.value;
        if (!Utils.startsWithString(fi[1], "level", true) || !inoutres67) 
            return null;
        res.level = i;
        if (i < 1) 
            return null;
        if (nod.children.length === 1 && nod.children[0].tagName === "A") 
            nod = nod.children[0];
        for (i = 0; i < nod.children.length; i++) {
            let ch = nod.children[i];
            if (ch.tagName !== "SPAN") 
                continue;
            if ((((val = ch.getAttribute("STYLE")))) !== null && val.includes("Ignore")) {
            }
            else if (ch.findSubnode("SPAN", "STYLE", "mso-list:Ignore") !== null) {
            }
            else if (i === 0) {
            }
            else 
                continue;
            let tmp = new StringBuilder();
            ch._getFullText(tmp, new GetPlaintextParam(), null);
            res.item = new UnitextListitem();
            if (tmp.length > 0) 
                res.item.prefix = UnitextPlaintext._new57(tmp.toString().trim());
            let gg = new UnitextGen();
            nod.children[i] = new HtmlNode();
            nod.tagName = "PPP";
            this.getUniText(nod, gg, null, lev + 1);
            nod.children[i] = ch;
            nod.tagName = "P";
            res.item.content = gg.finish(true, null);
            return res;
        }
        return null;
    }
}


UnitextHtmlGen.MsoListItem = class  {
    
    constructor() {
        this.level = 0;
        this.listId = null;
        this.item = null;
    }
    
    static _new64(_arg1) {
        let res = new UnitextHtmlGen.MsoListItem();
        res.listId = _arg1;
        return res;
    }
}


module.exports = UnitextHtmlGen