/*
 * 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 StringBuilder = require("./../../../unisharp/StringBuilder");

const FileFormat = require("./../../FileFormat");
const UnitextGen = require("./../uni/UnitextGen");
const MiscHelper = require("./../../../util/MiscHelper");
const UnitextService = require("./../../UnitextService");
const UnitextDocument = require("./../../UnitextDocument");
const EncodingWrapper = require("./../../../util/EncodingWrapper");
const EmlPart = require("./EmlPart");
const EncodingStandard = require("./../../../util/EncodingStandard");
const HtmlParser = require("./HtmlParser");
const HtmlHelper = require("./HtmlHelper");

/**
 * Поддержка формата MHT и EML
 */
class MhtHelper {
    
    static _createDoc(content, pars, isMht) {
        let txt = MiscHelper.decodeStringUtf8(content, 0, -1);
        return MhtHelper._createDocTxt(txt, pars, isMht, content);
    }
    
    static _createDocTxt(txt, pars, isMht, content) {
        let pos = 0;
        let wrappos46 = new RefOutArgWrapper(pos);
        let p = EmlPart.tryParse(txt, wrappos46);
        pos = wrappos46.value;
        if (p === null) 
            return null;
        let p0 = p;
        let nod = null;
        let parts = new Array();
        parts.push(p);
        let images = new Hashtable();
        let imageTypes = new Hashtable();
        while (pos < txt.length) {
            if (txt[pos] !== '-') {
                pos++;
                continue;
            }
            let wrappos45 = new RefOutArgWrapper(pos);
            p = EmlPart.tryParse(txt, wrappos45);
            pos = wrappos45.value;
            if (p === null) 
                break;
            if (p.contentCharset !== null && content !== null) {
                try {
                    let ee = new EncodingWrapper(EncodingStandard.UNDEFINED, p.contentCharset);
                    if (ee !== null) {
                        txt = ee.getString(content, 0, -1);
                        return MhtHelper._createDocTxt(txt, pars, isMht, null);
                    }
                } catch (ex) {
                }
            }
            if (p.data !== null && p.contentType !== null && p.contentType.startsWith("image")) {
                if (pars.onlyForPureText) 
                    continue;
                if (p.filename === null) {
                    let ii = images.length;
                    if (p.contentLocation !== null && !images.containsKey(p.contentLocation)) {
                        images.put(p.contentLocation, p.data);
                        if (p.contentType !== null) 
                            imageTypes.put(p.contentLocation, p.contentType);
                    }
                    if (p.contentId !== null && !images.containsKey("cid:" + p.contentId)) {
                        images.put("cid:" + p.contentId, p.data);
                        if (p.contentType !== null) 
                            imageTypes.put("cid:" + p.contentId, p.contentType);
                    }
                    if (images.length > ii) 
                        continue;
                }
            }
            parts.push(p);
            if (p.contentType === "text/html") {
                if (pars.ignoreInnerDocuments) 
                    break;
            }
        }
        let doc = null;
        for (let i = 0; i < parts.length; i++) {
            if (parts[i].contentType === "text/html") {
                p = parts[i];
                if (p.stringData !== null) {
                    let tmp = new StringBuilder(p.stringData);
                    nod = HtmlParser.parse(tmp, false);
                }
                else if (p.data !== null) 
                    nod = HtmlHelper.createNode(null, p.data, p.contentCharset);
                if (nod === null) 
                    continue;
                doc = HtmlHelper.create(nod, null, images, pars);
                if (doc === null) 
                    continue;
                parts.splice(i, 1);
                if (i > 0 && parts[i - 1].contentType === "text/plain") 
                    parts.splice(i - 1, 1);
                break;
            }
        }
        if (doc === null) {
            for (let i = 0; i < parts.length; i++) {
                if (parts[i].contentType === "text/plain") {
                    if (parts[i].stringData !== null) {
                        doc = UnitextService.createDocumentFromText(parts[i].stringData);
                        parts.splice(i, 1);
                        break;
                    }
                }
            }
        }
        if (doc === null) 
            doc = new UnitextDocument();
        doc.sourceFormat = (isMht ? FileFormat.MHT : FileFormat.EML);
        for (const a of p0.attrs.entries) {
            if (!doc.attrs.containsKey(a.key)) 
                doc.attrs.put(a.key, a.value);
        }
        if (!isMht) {
            let kk = 0;
            let gen = new UnitextGen();
            for (const s of ["From", "To", "CC", "Date", "Subject"]) {
                if (doc.attrs.containsKey(s)) {
                    gen.appendText((s + ": " + doc.attrs.get(s)), false);
                    gen.appendNewline(false, false);
                    kk++;
                }
            }
            if (kk > 0) {
                gen.appendNewline(false, false);
                if (doc.content !== null) 
                    gen.append(doc.content, null, -1, false);
                doc.content = gen.finish(true, null);
                doc.optimize(false, null);
                doc.refreshParents();
            }
        }
        if (pars.ignoreInnerDocuments) 
            return doc;
        for (const pp of parts) {
            if (pp.data !== null) {
                if (pp.filename !== null) {
                    try {
                        let aa = UnitextService.createDocument(pp.filename, pp.data, pars);
                        if (aa !== null) 
                            doc.innerDocuments.push(aa);
                    } catch (ex) {
                    }
                }
            }
        }
        return doc;
    }
    
    static _encodeString(val) {
        let res = new StringBuilder();
        let col = 0;
        for (let i = 0; i < val.length; i++) {
            let ch = val[i];
            if (ch === '\r' || ch === '\n') 
                col = 0;
            else 
                col++;
            if (col > 80) {
                res.append("=\r\n");
                col = 0;
            }
            if (ch === '=') 
                res.append("=3D");
            else 
                res.append(ch);
        }
        return res.toString();
    }
    
    static _decodeString(val) {
        if (Utils.isNullOrEmpty(val) || (val.length < 3)) 
            return val;
        if (val.length < 10) 
            return val;
        if (!val.includes("=?")) 
            return val;
        let res = new StringBuilder();
        for (let i = 0; i < val.length; i++) {
            if (val[i] === '=' && ((i + 1) < val.length) && val[i + 1] === '?') {
                let j = 0;
                i += 2;
                for (j = i; j < val.length; j++) {
                    if (val[j] === '?') 
                        break;
                }
                if (j >= val.length) 
                    return val;
                let charset = val.substring(i, i + j - i).trim();
                let enc = null;
                try {
                    enc = new EncodingWrapper(EncodingStandard.UNDEFINED, charset);
                } catch (ex) {
                    return val;
                }
                i = j + 1;
                let typ = '?';
                for (++j; j < val.length; j++) {
                    if (val[j] === '?') 
                        break;
                    else if (val[j] === 'Q' || val[j] === 'q') 
                        typ = 'Q';
                    else if (val[j] === 'B' || val[j] === 'b') 
                        typ = 'B';
                }
                if (typ !== 'Q' && typ !== 'B') 
                    return val;
                i = j + 1;
                for (++j; j < val.length; j++) {
                    if (val[j] === '?' && ((j + 1) < val.length) && val[j + 1] === '=') 
                        break;
                }
                let data = val.substring(i, i + j - i).trim();
                let bdata = null;
                if (typ === 'B') 
                    bdata = Utils.decodeBase64(data);
                else {
                    let bbb = new Array();
                    for (let k = 0; k < data.length; k++) {
                        if (data[k] !== '=' || (k + 1) >= data.length) 
                            bbb.push(data.charCodeAt(k));
                        else if ((k + 2) < data.length) {
                            let v1 = EmlPart._toInt(data[k + 1]);
                            let v2 = EmlPart._toInt(data[k + 2]);
                            if (v1 >= 0 && v2 >= 0) {
                                bbb.push(((v1 << 4) | v2));
                                k += 2;
                            }
                            else 
                                bbb.push(data.charCodeAt(k));
                        }
                    }
                    bdata = bbb;
                }
                if (bdata === null) 
                    return val;
                let ooo = enc.getString(bdata, 0, -1);
                res.append(ooo);
                i = j + 1;
            }
            else 
                res.append(val[i]);
        }
        return res.toString();
    }
    
    static _corrString(val) {
        if (Utils.isNullOrEmpty(val) || (val.length < 3)) 
            return val;
        let i = val.indexOf(';');
        if (i > 0) 
            val = val.substring(0, 0 + i).trim();
        if (val[0] === '"' && val[val.length - 1] === '"') 
            val = val.substring(1, 1 + val.length - 2);
        return val;
    }
}


module.exports = MhtHelper