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

const UnitextPlaintextType = require("./../../UnitextPlaintextType");
const UnilayPage = require("./../../UnilayPage");
const MyXmlReader = require("./../misc/MyXmlReader");
const UnitextPlaintext = require("./../../UnitextPlaintext");
const UnitextGen = require("./UnitextGen");
const MSOfficeHelper = require("./../word/MSOfficeHelper");
const GetPlaintextParam = require("./../../GetPlaintextParam");
const UnitextDocblock = require("./../../UnitextDocblock");
const UnitextListitem = require("./../../UnitextListitem");
const TiffHelper = require("./../misc/TiffHelper");
const UnitextFootnote = require("./../../UnitextFootnote");
const StyleHelper = require("./StyleHelper");
const FileFormat = require("./../../FileFormat");
const UnitextItem = require("./../../UnitextItem");
const UnitextMiscType = require("./../../UnitextMiscType");
const UnitextMisc = require("./../../UnitextMisc");
const FileFormatClass = require("./../../FileFormatClass");
const UnitextContainer = require("./../../UnitextContainer");
const UnitextComment = require("./../../UnitextComment");
const FileFormatsHelper = require("./../../../util/FileFormatsHelper");
const UnitextImage = require("./../../UnitextImage");
const UnitextPagebreak = require("./../../UnitextPagebreak");
const UnitextService = require("./../../UnitextService");

class UnitextHelper {
    
    static create(fileName, fileContent, pars) {
        const UnitextNewline = require("./../../UnitextNewline");
        const ArchiveHelper = require("./../../../util/ArchiveHelper");
        const UnitextDocument = require("./../../UnitextDocument");
        const UnitextList = require("./../../UnitextList");
        const UnitextHyperlink = require("./../../UnitextHyperlink");
        const UnitextTable = require("./../../UnitextTable");
        if (fileContent === null) {
            if (fileName === null) 
                return UnitextDocument._new379(FileFormat.UNKNOWN, ("Not filename, not content..."));
            fileName = path.resolve(fileName);
            if (!fs.existsSync(fileName) && fs.statSync(fileName).isFile()) 
                return UnitextDocument._new379(FileFormat.UNKNOWN, ("File '" + fileName + "' not exists"));
        }
        let frm = FileFormatsHelper.analizeFileFormat(fileName, fileContent);
        let doc = null;
        try {
            if (UnitextService.EXTENSION !== null) 
                doc = UnitextService.EXTENSION.createDocument(frm, fileName, fileContent, pars);
            if (doc === null) 
                doc = UnitextHelper._create(frm, fileName, fileContent, pars);
            if (doc === null) 
                doc = UnitextDocument._new379(frm, (frm === FileFormat.UNKNOWN ? "Format unknown" : "Can't create document"));
        } catch (ex) {
            doc = UnitextDocument._new379(frm, ex.toString());
        }
        if (doc.sourceFileName === null) 
            doc.sourceFileName = fileName;
        let all = new Array();
        doc.getAllItems(all, 0);
        let inHyps = new Array();
        let ancs = new Hashtable();
        for (const it of all) {
            let mi = Utils.as(it, UnitextMisc);
            if (mi !== null && mi.typ === UnitextMiscType.ANCHOR) {
                if (!ancs.containsKey(mi.id)) 
                    ancs.put(mi.id, mi);
                mi.tag = null;
            }
            let hyp = Utils.as(it, UnitextHyperlink);
            if (hyp !== null) {
                if (hyp.toString().includes("9.4")) {
                }
            }
            if (hyp !== null && hyp.href !== null && hyp.isInternal) {
                inHyps.push(hyp);
                if (hyp.content === null) {
                    let cnt = Utils.as(hyp.parent, UnitextContainer);
                    if (cnt !== null) {
                        let i = cnt.getChildIndexOf(hyp);
                        if (i >= 0 && ((i + 1) < cnt.children.length)) {
                            let i0 = i;
                            i++;
                            let vv = cnt.children[i];
                            while ((vv instanceof UnitextNewline) && ((i + 1) < cnt.children.length)) {
                                i++;
                                vv = cnt.children[i];
                            }
                            if (!(vv instanceof UnitextNewline)) {
                                hyp.content = vv;
                                vv.parent = hyp;
                                cnt.children[i] = hyp;
                                cnt.children.splice(i0, 1);
                            }
                        }
                    }
                }
            }
            let img = Utils.as(it, UnitextImage);
            if (img !== null) {
                if (img.content === null && img.id !== null) {
                    if (img.id.startsWith("data:image")) {
                        let ii = img.id.indexOf("base64,");
                        if (ii > 0) {
                            try {
                                img.content = Utils.decodeBase64(img.id.substring(ii + 7));
                                img.id = null;
                            } catch (ex) {
                            }
                        }
                    }
                    else if (img.id.startsWith("http") || img.id.startsWith("www")) {
                        img.htmlSrcUri = img.id;
                        continue;
                    }
                }
                if (img.content !== null && img.content.length > 10) {
                    if (img.content[0] === (0x1F) && img.content[1] === (0x8B)) {
                        try {
                            img.content = ArchiveHelper.decompressGZip(img.content);
                        } catch (ex383) {
                        }
                    }
                }
                if (img.content === null && img.id !== null && (img.id.length < 30)) 
                    continue;
                if (pars !== null && pars.maxImageSize > 0 && img.content !== null) {
                    if (img.content.length > pars.maxImageSize) 
                        img.content = null;
                }
            }
        }
        let refid = 1;
        for (const h of inHyps) {
            let anc = null;
            let wrapanc384 = new RefOutArgWrapper();
            let inoutres385 = ancs.tryGetValue(h.href, wrapanc384);
            anc = wrapanc384.value;
            if (!inoutres385) 
                continue;
            let cnt = Utils.as(anc.parent, UnitextContainer);
            let anc0 = anc;
            if (cnt !== null) {
                let i = cnt.getChildIndexOf(anc);
                let ait = null;
                if (i >= 0) {
                    for (let j = i - 1; j >= 0; j--) {
                        let it = cnt.children[j];
                        if (((it instanceof UnitextNewline) || (it instanceof UnitextPagebreak) || (it instanceof UnitextTable)) || (it instanceof UnitextList)) 
                            break;
                        if (it instanceof UnitextComment) 
                            continue;
                        let um = Utils.as(it, UnitextMisc);
                        if (um !== null) {
                            if (um.typ === UnitextMiscType.HORIZONTALLINE) 
                                break;
                            continue;
                        }
                        ait = it;
                    }
                    if (ait === null) {
                        for (let j = i + 1; j < cnt.children.length; j++) {
                            let it = cnt.children[j];
                            if (((it instanceof UnitextNewline) || (it instanceof UnitextMisc) || (it instanceof UnitextPagebreak)) || (it instanceof UnitextComment)) 
                                continue;
                            ait = it;
                            break;
                        }
                    }
                    if (ait !== null) {
                        if (ait.id === null) {
                            if (refid === 101) {
                            }
                            ait.id = (ait.innerTag + "_ref" + refid);
                            refid++;
                        }
                        h.href = ait.id;
                        anc0 = null;
                    }
                }
                if (i > 0 && ait === null) {
                    for (let j = i - 1; j >= 0; j--) {
                        if ((cnt.children[j] instanceof UnitextMisc) && cnt.children[j].typ === UnitextMiscType.ANCHOR) 
                            anc0 = Utils.as(cnt.children[j], UnitextMisc);
                        else 
                            break;
                    }
                }
            }
            if (anc0 !== null) {
                if (anc0 !== anc) 
                    h.href = anc0.id;
                anc0.tag = h;
            }
        }
        for (const a of ancs.values) {
            if (a.tag === null) {
                let cnt = Utils.as(a.parent, UnitextContainer);
                if (cnt === null) 
                    continue;
                let i = cnt.getChildIndexOf(a);
                if (i >= 0) 
                    cnt.children.splice(i, 1);
            }
        }
        return doc;
    }
    
    static loadDataFromFile(fileName, attampts = 0) {
        let fStr = null;
        let buf = null;
        try {
            let ex = null;
            for (let i = 0; i <= attampts; i++) {
                try {
                    fStr = new FileStream(fileName, "r", false);
                    break;
                } catch (e) {
                    ex = e;
                }
                if (i === 0 && !fs.existsSync(fileName) && fs.statSync(fileName).isFile()) 
                    break;
            }
            if (fStr === null) 
                throw ex;
            if (fStr.length === (0)) 
                return null;
            buf = new Uint8Array(fStr.length);
            fStr.read(buf, 0, fStr.length);
        } finally {
            if (fStr !== null) 
                fStr.close();
        }
        return buf;
    }
    
    static _create(frm, fileName, fileContent, pars) {
        const EpubHelper = require("./../misc/EpubHelper");
        const Fb2Helper = require("./../misc/Fb2Helper");
        const MhtHelper = require("./../html/MhtHelper");
        const UnitextDocument = require("./../../UnitextDocument");
        const CsvHelper = require("./../misc/CsvHelper");
        const TextHelper = require("./../../../util/TextHelper");
        const HtmlHelper = require("./../html/HtmlHelper");
        const RtfHelper = require("./../rtf/RtfHelper");
        const ExcelHelper = require("./../misc/ExcelHelper");
        const ArchiveHelper = require("./../../../util/ArchiveHelper");
        const PdfHelper = require("./../pdf/PdfHelper");
        const DocxToText = require("./../word/DocxToText");
        let frmcl = FileFormatsHelper.getFormatClass(frm);
        if (frmcl === FileFormatClass.ARCHIVE) {
            let res = UnitextDocument._new69(fileName, frm);
            if (pars.ignoreInnerDocuments) 
                return res;
            let files = null;
            try {
                files = ArchiveHelper.getFileNamesFromArchive(fileName, fileContent);
            } catch (ex) {
                res.errorMessage = ex.message;
                return res;
            }
            if (files === null) {
                res.errorMessage = ("Archive format " + frm.toString() + " not supported");
                return res;
            }
            if (files.length === 0) 
                return res;
            for (const f of files.entries) {
                let ext = path.extname(f.key);
                if (ext === ".exe" || ext === ".dll") 
                    continue;
                try {
                    let cnt = ArchiveHelper.getFileFromArchive(fileName, fileContent, f.key);
                    if (cnt === null || cnt.length === 0) 
                        continue;
                    let d = UnitextService.createDocument(f.key, cnt, pars);
                    res.innerDocuments.push(d);
                } catch (ex) {
                    let d = UnitextDocument._new69(f.key, FileFormatsHelper.analizeFormat(ext, null));
                    d.errorMessage = ex.message;
                    res.innerDocuments.push(d);
                }
            }
            return res;
        }
        if (fileContent === null) {
            let fi = new FileInfo(fileName);
            if (fi.length < (10000000)) 
                fileContent = UnitextHelper.loadDataFromFile(fileName, 0);
        }
        if (frm === FileFormat.RTF) {
            if (fileContent !== null) {
                let mem = new MemoryStream(fileContent); 
                try {
                    return RtfHelper.createUniDoc(mem, pars);
                }
                finally {
                    mem.close();
                }
            }
            else {
                let f = new FileStream(fileName, "r", false); 
                try {
                    return RtfHelper.createUniDoc(f, pars);
                }
                finally {
                    f.close();
                }
            }
        }
        if ((frm === FileFormat.DOCX || frm === FileFormat.XLSX || frm === FileFormat.PPTX) || frm === FileFormat.ODT || frm === FileFormat.DOCXML) {
            let d2t = new DocxToText(fileName, fileContent, frm === FileFormat.DOCXML, (pars !== null ? pars.setFormulaAsImage : false)); 
            try {
                d2t.maxTableRows = pars.maxTableRows;
                let doc = d2t.createUniDoc(pars.onlyForPureText, frm, pars);
                if (doc !== null) {
                    doc.optimize(false, pars);
                    StyleHelper.processDoc(doc);
                }
                return doc;
            }
            finally {
                d2t.close();
            }
        }
        if (frm === FileFormat.XLSXML) {
            let xm = null;
            if (fileContent !== null) {
                xm = MyXmlReader.create(fileContent);
                return ExcelHelper.createDocForXml(xm, pars.maxTableRows);
            }
            else {
                xm = MyXmlReader.create(UnitextHelper.loadDataFromFile(fileName, 0));
                return ExcelHelper.createDocForXml(xm, pars.maxTableRows);
            }
        }
        if (frm === FileFormat.DOC) {
            let doc = null;
            if (fileContent !== null) 
                doc = MSOfficeHelper._uniFromWord97Arr(fileContent);
            else 
                doc = MSOfficeHelper._uniFromWord97File(fileName);
            if (doc === null) 
                return null;
            if (doc.attrs.containsKey("word") && doc.attrs.get("word") === "6") {
                if (pars.ignoreWord6) {
                    doc = UnitextDocument._new47(FileFormat.DOC);
                    doc.errorMessage = "Word6 not supported";
                    return doc;
                }
            }
            doc.optimize(false, pars);
            return doc;
        }
        if (frm === FileFormat.PDF) 
            return PdfHelper.createUni(fileName, fileContent, pars);
        if (frm === FileFormat.HTML) {
            let nod = HtmlHelper.createNode(fileName, fileContent, null);
            if (nod === null) 
                return null;
            let dirName = null;
            if (!pars.onlyForPureText && fileName !== null && fs.existsSync(fileName) && fs.statSync(fileName).isFile()) {
                let dir = path.dirname(path.resolve(fileName));
                if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) 
                    dirName = dir;
            }
            let doc = HtmlHelper.create(nod, dirName, null, pars);
            return doc;
        }
        if (frm === FileFormat.XML) {
            let doc = UnitextDocument._new47(FileFormat.XML);
            let txt = HtmlHelper.getXmlText(fileName, fileContent);
            if (txt !== null) 
                doc.content = UnitextPlaintext._new390(UnitextPlaintextType.XML, txt);
            else 
                doc.errorMessage = "Размер XML слишком большой";
            return doc;
        }
        if (frm === FileFormat.MHT || frm === FileFormat.EML) {
            let fs = null;
            if (fileContent === null) 
                fileContent = UnitextHelper.loadDataFromFile(fileName, 0);
            try {
                let doc = MhtHelper._createDoc(fileContent, pars, frm === FileFormat.MHT);
                if (doc !== null) {
                    doc.optimize(false, pars);
                    doc.sourceFileName = fileName;
                    doc.sourceFormat = frm;
                }
                else 
                    doc = UnitextDocument._new379(frm, "Не удалось сформировать письмо");
                return doc;
            } finally {
                if (fs !== null) 
                    fs.close();
            }
        }
        if (frm === FileFormat.FB2) 
            return Fb2Helper.createDoc(fileName, fileContent, pars);
        if (frm === FileFormat.FB3) 
            return Fb2Helper.createDocZip(fileName, fileContent, pars);
        if (frm === FileFormat.EPUB) 
            return EpubHelper.createDoc(fileName, fileContent, pars);
        if (frm === FileFormat.TXT || frm === FileFormat.CSV) {
            let txt = null;
            if (fileContent !== null) 
                txt = TextHelper.readStringFromBytes(fileContent, false, false);
            else 
                txt = TextHelper.readStringFromFile(fileName, false, false);
            if (Utils.isNullOrEmpty(txt)) 
                return null;
            let len = txt.length;
            if (frm === FileFormat.CSV) {
                let csv = CsvHelper.create(txt);
                if (csv !== null) 
                    return csv;
            }
            let gen = new UnitextGen();
            gen.appendText(txt, true);
            let doc = UnitextDocument._new47(FileFormat.TXT);
            doc.content = gen.finish(true, null);
            if (doc.content === null) 
                return null;
            return doc;
        }
        if (frm === FileFormat.TIF) {
            if (fileContent === null) 
                fileContent = UnitextHelper.loadDataFromFile(fileName, 0);
            let doc = TiffHelper.createDoc(fileContent);
            doc.refreshContentByPages();
            return doc;
        }
        if (frmcl === FileFormatClass.IMAGE) {
            let doc = UnitextDocument._new393(frm, fileName);
            let page = new UnilayPage();
            page.imageContent = (fileContent != null ? fileContent : UnitextHelper.loadDataFromFile(fileName, 0));
            doc.pages.push(page);
            doc.refreshContentByPages();
            return doc;
        }
        let err = UnitextDocument._new379(frm, "Unsupported format");
        if (frm !== FileFormat.UNKNOWN) 
            err.errorMessage = (err.errorMessage + " " + frm.toString());
        return err;
    }
    
    static createItem(xml, par) {
        const UnitextHyperlink = require("./../../UnitextHyperlink");
        const UnitextNewline = require("./../../UnitextNewline");
        const UnitextList = require("./../../UnitextList");
        const UnitextTablecell = require("./../../UnitextTablecell");
        const UnitextTable = require("./../../UnitextTable");
        let res = null;
        switch (xml.local_name) { 
        case "container": {
            res = new UnitextContainer();
            break;
        }
        case "text": {
            res = new UnitextPlaintext();
            break;
        }
        case "newline": {
            res = new UnitextNewline();
            break;
        }
        case "pagebreak": {
            res = new UnitextPagebreak();
            break;
        }
        case "table": {
            res = new UnitextTable();
            break;
        }
        case "cell": {
            res = new UnitextTablecell();
            break;
        }
        case "hyperlink": {
            res = new UnitextHyperlink();
            break;
        }
        case "footnote": {
            res = new UnitextFootnote();
            break;
        }
        case "list": {
            res = new UnitextList();
            break;
        }
        case "listitem": {
            res = new UnitextListitem();
            break;
        }
        case "image": {
            res = new UnitextImage();
            break;
        }
        case "comment": {
            res = new UnitextComment();
            break;
        }
        case "docblock": {
            res = new UnitextDocblock();
            break;
        }
        case "misc": {
            res = new UnitextMisc();
            break;
        }
        }
        if (res !== null) {
            res.parent = par;
            res.fromXml(xml);
        }
        return res;
    }
    
    static createDocFromText(text) {
        const UnitextNewline = require("./../../UnitextNewline");
        const UnitextDocument = require("./../../UnitextDocument");
        let doc = UnitextDocument._new395((text != null ? text : ""));
        if (Utils.isNullOrEmpty(text)) 
            return doc;
        let cur = null;
        let cnt = UnitextContainer._new396(text.length - 1);
        doc.content = cnt;
        cnt.parent = doc;
        doc.endChar = text.length - 1;
        for (let i = 0; i < text.length; i++) {
            let ch = text[i];
            if (ch === '\r' || ch === '\n') {
                if (!(cur instanceof UnitextNewline)) {
                    cur = UnitextNewline._new397(cnt);
                    cnt.children.push(cur);
                    cur.beginChar = i;
                }
                cur.endChar = i;
                if (ch === '\r') 
                    cur.count++;
                else if (ch === '\n') {
                    if (i === 0 || text[i - 1] !== '\r') 
                        cur.count++;
                }
            }
            else if ((ch.charCodeAt(0)) === 0xC) {
                cur = UnitextPagebreak._new398(cnt);
                cnt.children.push(cur);
                cur.beginChar = i;
                cur.endChar = i;
            }
            else {
                if (!(cur instanceof UnitextPlaintext)) {
                    cur = UnitextPlaintext._new399(cnt);
                    cnt.children.push(cur);
                    cur.beginChar = i;
                }
                cur.endChar = i;
            }
        }
        for (const ch of cnt.children) {
            if ((ch instanceof UnitextPlaintext) && ch.beginChar <= ch.endChar) 
                ch.text = text.substring(ch.beginChar, ch.beginChar + (ch.endChar - ch.beginChar) + 1);
        }
        doc.generateIds();
        return doc;
    }
    
    static getPlaintext(it, pars = null) {
        if (it === null) 
            return null;
        if (pars === null) 
            pars = UnitextHelper.m_StdParams;
        let res = new StringBuilder();
        it.getPlaintext(res, pars);
        if (res.length === 0) 
            return null;
        return res.toString();
    }
    
    static static_constructor() {
        UnitextHelper.m_StdParams = GetPlaintextParam._new356(false);
        UnitextHelper.m_Romans = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX", "XXI", "XXII", "XXIII", "XXIV", "XXV", "XXVI", "XXVII", "XXVIII", "XXIX", "XXX"];
    }
}


UnitextHelper.static_constructor();

module.exports = UnitextHelper