/*
 * 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 Utils = require("./../../../unisharp/Utils");
const Hashtable = require("./../../../unisharp/Hashtable");
const Stream = require("./../../../unisharp/Stream");
const FileStream = require("./../../../unisharp/FileStream");
const MemoryStream = require("./../../../unisharp/MemoryStream");
const XmlDocument = require("./../../../unisharp/XmlDocument");

const UnitextItem = require("./../../UnitextItem");
const UnitextDocblock = require("./../../UnitextDocblock");
const UnitextImage = require("./../../UnitextImage");
const UnitextContainerType = require("./../../UnitextContainerType");
const UnitextContainer = require("./../../UnitextContainer");
const UnitextNewline = require("./../../UnitextNewline");
const UnitextFootnote = require("./../../UnitextFootnote");
const MyZipFile = require("./MyZipFile");
const UnitextDocument = require("./../../UnitextDocument");
const FileFormat = require("./../../FileFormat");
const UnitextGen = require("./../uni/UnitextGen");
const UnitextPagesectionItem = require("./../../UnitextPagesectionItem");
const UnitextPagesection = require("./../../UnitextPagesection");

class Fb2Helper {
    
    static createDocZip(fileName, content, pars) {
        let zip = new MyZipFile(fileName, content);
        let doc = UnitextDocument._new69(fileName, FileFormat.EPUB);
        doc.content = new UnitextContainer();
        let footNotes = new Hashtable();
        let coverImage = null;
        try {
            for (const entry of zip.entries) {
                if (Utils.endsWithString(entry.name, "body.xml", true)) {
                    let dat = entry.getData();
                    if (dat === null) 
                        continue;
                    let xml = new XmlDocument();
                    let documentXml = new MemoryStream(dat); 
                    try {
                        xml.preserve_whitespace = true;
                        xml.loadStream(documentXml);
                        documentXml.close();
                    }
                    finally {
                        documentXml.close();
                    }
                    let img = Fb2Helper._loadBody(xml.document_element, doc, footNotes, pars);
                    if (img !== null) 
                        coverImage = img;
                }
            }
        } finally {
            if (zip !== null) 
                zip.close();
        }
        doc.optimize(false, null);
        return doc;
    }
    
    static createDoc(fileName, content, pars) {
        let xml = new XmlDocument();
        if (content === null && fs.existsSync(fileName) && fs.statSync(fileName).isFile()) {
            let fs = new FileStream(fileName, "r", false); 
            try {
                xml.loadStream(fs);
            }
            finally {
                fs.close();
            }
        }
        else if (content !== null) {
            let mem = new MemoryStream(content); 
            try {
                try {
                    xml.loadStream(mem);
                } catch (ex) {
                    if (xml.document_element === null) 
                        throw ex;
                }
            }
            finally {
                mem.close();
            }
        }
        else 
            return null;
        let footNotes = new Hashtable();
        for (const x of xml.document_element.child_nodes) {
            if (x.local_name === "body") {
                let name = null;
                if (x.attributes !== null) {
                    for (const a of x.attributes) {
                        if (a.local_name === "name") 
                            name = a.value;
                    }
                }
                if (name !== "notes") 
                    continue;
                for (const xx of x.child_nodes) {
                    if (xx.local_name === "section") {
                        let id = null;
                        if (xx.attributes !== null) {
                            for (const a of xx.attributes) {
                                if (a.local_name === "id") 
                                    id = a.value;
                            }
                        }
                        if (id === null || footNotes.containsKey(id)) 
                            continue;
                        let gen = new UnitextGen();
                        Fb2Helper._GetUniText(xx, gen, null, null, pars);
                        footNotes.put(id, gen.finish(true, null));
                    }
                }
            }
        }
        let doc = UnitextDocument._new69(fileName, FileFormat.FB2);
        let coverImage = null;
        for (const x of xml.document_element.child_nodes) {
            if (x.local_name === "body") {
                let img = Fb2Helper._loadBody(x, doc, footNotes, pars);
                if (img !== null) 
                    coverImage = img;
                break;
            }
            else if (x.local_name === "description") {
                for (const xx of x.child_nodes) {
                    if (xx.local_name === "title-info") {
                        for (const xxx of xx.child_nodes) {
                            if (xxx.local_name === "book-title") {
                                let gen = new UnitextGen();
                                Fb2Helper._GetUniText(xxx, gen, null, null, pars);
                                if (!pars.loadDocumentStructure) {
                                    let fi = gen.finish(true, null);
                                    if (fi !== null) {
                                        doc.sections.push(new UnitextPagesection());
                                        doc.sections[0].items.push(UnitextPagesectionItem._new48(fi));
                                    }
                                }
                                if (!doc.attrs.containsKey("title")) 
                                    doc.attrs.put("title", xxx.inner_text);
                            }
                            else if (xxx.local_name === "author") {
                                for (const xxxx of xxx.child_nodes) {
                                    if (xxxx.local_name === "first-name") {
                                        if (!doc.attrs.containsKey("author-firstname")) 
                                            doc.attrs.put("author-firstname", xxxx.inner_text);
                                    }
                                    else if (xxxx.local_name === "last-name") {
                                        if (!doc.attrs.containsKey("author-lastname")) 
                                            doc.attrs.put("author-lastname", xxxx.inner_text);
                                    }
                                }
                            }
                        }
                    }
                }
                coverImage = Fb2Helper.loadTitleInfo(doc.attrs, x, null);
            }
        }
        if (!pars.onlyForPureText) {
            for (const x of xml.document_element.child_nodes) {
                if (x.local_name === "binary") {
                    let id = null;
                    if (x.attributes !== null) {
                        for (const a of x.attributes) {
                            if (a.local_name === "id") 
                                id = a.value;
                        }
                    }
                    if (id === null) 
                        continue;
                    let img = Utils.as(doc.findById(id), UnitextImage);
                    if (img !== null) {
                        try {
                            img.content = Utils.decodeBase64(x.inner_text);
                        } catch (ex93) {
                        }
                    }
                }
            }
        }
        return doc;
    }
    
    static _loadBody(x, doc, footNotes, pars) {
        let coverImage = null;
        if (pars.loadDocumentStructure) {
            let dbl = new UnitextDocblock();
            dbl.typname = "Document";
            dbl.body = new UnitextContainer();
            let gg = new UnitextGen();
            Fb2Helper._GetUniText(x, gg, dbl, footNotes, pars);
            doc.content = dbl;
            for (const xx of x.child_nodes) {
                if (xx.local_name === "title") {
                    let g = new UnitextGen();
                    Fb2Helper._GetUniText(xx, g, null, footNotes, pars);
                    dbl.head = UnitextContainer._new94(UnitextContainerType.HEAD);
                    let nn = g.finish(true, null);
                    let ccc = Utils.as(nn, UnitextContainer);
                    if (ccc === null) {
                        ccc = new UnitextContainer();
                        ccc.children.push(nn);
                    }
                    ccc.typ = UnitextContainerType.NAME;
                    dbl.head.children.push(ccc);
                    dbl.head.children.push(new UnitextNewline());
                    break;
                }
            }
            if (coverImage !== null) {
                if (coverImage.startsWith("#")) 
                    coverImage = coverImage.substring(1);
                if (dbl.head === null) 
                    dbl.head = UnitextContainer._new94(UnitextContainerType.HEAD);
                dbl.head.children.splice(0, 0, UnitextImage._new96(coverImage));
                dbl.head.children.splice(1, 0, new UnitextNewline());
            }
        }
        else {
            let gen = new UnitextGen();
            Fb2Helper._GetUniText(x, gen, null, footNotes, pars);
            doc.content = gen.finish(true, null);
        }
        return coverImage;
    }
    
    static _GetUniText(xml, gen, dbl, footNotes, pars) {
        for (const x of xml.child_nodes) {
            if (x.local_name === "#text") {
                if (gen !== null) 
                    gen.appendText(x.inner_text, false);
            }
            else if (x.local_name === "p" || x.local_name === "v") {
                gen.appendNewline(true, false);
                Fb2Helper._GetUniText(x, gen, dbl, footNotes, pars);
                gen.appendNewline(false, false);
            }
            else if (x.local_name === "title") {
                if (footNotes === null || pars.loadDocumentStructure) 
                    continue;
                gen.appendNewline(false, false);
                Fb2Helper._GetUniText(x, gen, dbl, footNotes, pars);
                gen.appendNewline(false, false);
                gen.appendNewline(false, false);
            }
            else if (x.local_name === "section") {
                if (!pars.loadDocumentStructure) {
                    gen.appendNewline(false, false);
                    Fb2Helper._GetUniText(x, gen, null, footNotes, pars);
                    gen.appendPagebreak();
                }
                else {
                    let db = UnitextDocblock._new38("Section");
                    if (dbl.typname === "Section") 
                        db.typname = "Subsection";
                    else if (dbl.typname === "Subsection") 
                        db.typname = "Chapter";
                    db.body = new UnitextContainer();
                    dbl.body.children.push(db);
                    for (const xx of x.child_nodes) {
                        if (xx.local_name === "title") {
                            let g = new UnitextGen();
                            Fb2Helper._GetUniText(xx, g, null, footNotes, pars);
                            db.head = UnitextContainer._new94(UnitextContainerType.HEAD);
                            let nn = g.finish(true, null);
                            let ccc = Utils.as(nn, UnitextContainer);
                            if (ccc === null) {
                                ccc = new UnitextContainer();
                                ccc.children.push(nn);
                            }
                            ccc.typ = UnitextContainerType.NAME;
                            db.head.children.push(ccc);
                            db.head.children.push(new UnitextNewline());
                            break;
                        }
                    }
                    let gg = new UnitextGen();
                    Fb2Helper._GetUniText(x, gg, db, footNotes, pars);
                    let bb = gg.finish(false, null);
                    if (bb === null) 
                        continue;
                    if (db.body.children.length === 0) 
                        db.body = bb;
                    else 
                        db.body.children.splice(0, 0, bb);
                    let cnt = Utils.as(db.body, UnitextContainer);
                    if (cnt !== null && cnt.children.length > 0 && (cnt.children[0] instanceof UnitextNewline)) 
                        cnt.children.splice(0, 1);
                }
            }
            else if (x.local_name === "empty-line") 
                gen.appendNewline(false, false);
            else if (x.local_name === "image") {
                let id = null;
                if (x.attributes !== null) {
                    for (const a of x.attributes) {
                        if (a.local_name === "href" && !Utils.isNullOrEmpty(a.value) && a.value[0] === '#') {
                            id = a.value.substring(1);
                            break;
                        }
                    }
                }
                if (id !== null) 
                    gen.append(UnitextImage._new96(id), null, -1, false);
            }
            else if (x.local_name === "a") {
                let id = null;
                let typ = null;
                if (x.attributes !== null) {
                    for (const a of x.attributes) {
                        if (a.local_name === "href" && !Utils.isNullOrEmpty(a.value) && a.value[0] === '#') 
                            id = a.value.substring(1);
                        else if (a.local_name === "type") 
                            typ = a.value;
                    }
                }
                if ((id !== null && typ === "note" && footNotes !== null) && footNotes.containsKey(id)) {
                    let fn = UnitextFootnote._new100(x.inner_text);
                    fn.content = footNotes.get(id);
                    gen.append(fn, null, -1, false);
                    continue;
                }
                gen.appendText(x.inner_text, false);
            }
            else if (x.local_name === "subtitle") 
                gen.appendNewline(false, false);
            else if (x.local_name === "epigraph") {
                let g = new UnitextGen();
                Fb2Helper._GetUniText(x, g, null, null, pars);
                let fn = new UnitextFootnote();
                fn.content = g.finish(true, null);
                if (fn.content !== null) 
                    gen.append(fn, null, -1, false);
            }
            else 
                Fb2Helper._GetUniText(x, gen, dbl, footNotes, pars);
        }
    }
    
    static loadTitleInfo(attrs, xml, nam) {
        let ret = null;
        for (const ch of xml.child_nodes) {
            if (ch.local_name === "image" && xml.local_name === "coverpage") {
                for (const a of ch.attributes) {
                    if (a.local_name === "href") 
                        ret = a.value;
                }
                continue;
            }
            let key = (nam === null ? ch.local_name : (ch.local_name === "#text" ? nam : (nam + "/" + ch.local_name)));
            if (ch.child_nodes.length > 0) {
                let img = Fb2Helper.loadTitleInfo(attrs, ch, key);
                if (img !== null) 
                    ret = img;
                continue;
            }
            let val = ch.inner_text;
            if (Utils.isNullOrEmpty(val)) 
                continue;
            if (!attrs.containsKey(key)) 
                attrs.put(key, val);
            else 
                attrs.put(key, (attrs.get(key) + "; " + val));
        }
        return ret;
    }
}


module.exports = Fb2Helper