/*
 * 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 UnitextStyle = require("./../../UnitextStyle");
const BorderInfo = require("./../misc/BorderInfo");
const MiscHelper = require("./../../../util/MiscHelper");
const SizeunitConverter = require("./../../../util/SizeunitConverter");
const DocTextStyle = require("./DocTextStyle");

class DocTextStyles {
    
    constructor() {
        this.m_TextStyles = new Hashtable();
        this.defStyle = null;
        this.defStyles = new Hashtable();
        this.uStyles = new Array();
        this.m_UStyles = new Hashtable();
        this.ignore = false;
        this.m_MajorFont = null;
        this.m_MinorFont = null;
    }
    
    registerStyle(st) {
        if (this.ignore) 
            return st;
        let key = st.toString();
        if (Utils.isNullOrEmpty(key)) 
            return null;
        let res = null;
        let wrapres471 = new RefOutArgWrapper();
        let inoutres472 = this.m_UStyles.tryGetValue(key, wrapres471);
        res = wrapres471.value;
        if (inoutres472) 
            return res;
        this.m_UStyles.put(key, st);
        st.id = this.uStyles.length;
        this.uStyles.push(st);
        return st;
    }
    
    getStyle(x, nam) {
        let id = DocTextStyles._readAttrVal(x, nam, null);
        if (id === null) 
            return null;
        let res = null;
        let wrapres473 = new RefOutArgWrapper();
        let inoutres474 = this.m_TextStyles.tryGetValue(id, wrapres473);
        res = wrapres473.value;
        if (!inoutres474) 
            return null;
        return res;
    }
    
    getStyleById(id) {
        let res = null;
        let wrapres475 = new RefOutArgWrapper();
        let inoutres476 = this.m_TextStyles.tryGetValue(id, wrapres475);
        res = wrapres475.value;
        if (!inoutres476) 
            return null;
        return res;
    }
    
    static _readAttrVal(x, nam, nam2 = null) {
        if (x.attributes !== null) {
            for (const a of x.attributes) {
                if (a.local_name === nam) 
                    return a.value;
                else if (nam2 !== null && a.local_name === nam2) 
                    return a.value;
            }
        }
        return null;
    }
    
    static _getSizeVal(val, outCm = false) {
        if (val === null) 
            return null;
        for (const ch of val) {
            if (Utils.isLetter(ch)) 
                return val;
        }
        let d = 0;
        let wrapd477 = new RefOutArgWrapper();
        let inoutres478 = MiscHelper.tryParseDouble(val, wrapd477);
        d = wrapd477.value;
        if (!inoutres478) 
            return val;
        if (outCm) {
            d = Utils.mathRound(d / (((20) * 28.35)), 2);
            return (MiscHelper.outDouble(d) + "cm");
        }
        d = Utils.mathRound(d / (20), 2);
        return (MiscHelper.outDouble(d) + "pt");
    }
    
    static _corrColor(val) {
        if (val === null) 
            return null;
        if (val.length !== 6) 
            return val;
        for (const ch of val) {
            if (Utils.isDigit(ch)) {
            }
            else if (ch >= 'A' && ch <= 'F') {
            }
            else if (ch >= 'a' && ch <= 'f') {
            }
            else 
                return val;
        }
        return val = "#" + val.toUpperCase();
    }
    
    readUnitextStyle(node, st, ignoreFontName = false) {
        for (const x of node.child_nodes) {
            if (x.local_name === "pStyle" || x.local_name === "rStyle") {
                let id = DocTextStyles._readAttrVal(x, "val", null);
                if (this.m_TextStyles.containsKey(id)) 
                    this.m_TextStyles.get(id).uStyle.copyTo(st);
            }
            else if (x.local_name === "rFonts" && !ignoreFontName) {
                let nam = DocTextStyles._readAttrVal(x, "cs", "ansii");
                if (nam === null) 
                    nam = DocTextStyles._readAttrVal(x, "ascii", "hAnsii");
                if (nam === null) 
                    nam = st.getAttr("font-name");
                let isBidi = false;
                if (nam === null) {
                    for (const a of x.attributes) {
                        if (Utils.endsWithString(a.local_name, "cstheme", true) && Utils.endsWithString(a.value, "bidi", true)) 
                            isBidi = true;
                    }
                    for (const a of x.attributes) {
                        if (Utils.endsWithString(a.local_name, "theme", true) && !Utils.endsWithString(a.local_name, "asiatheme", true)) {
                            if (isBidi) 
                                break;
                            if (Utils.startsWithString(a.value, "major", true)) 
                                nam = this.m_MajorFont;
                            else if (Utils.startsWithString(a.value, "minor", true)) 
                                nam = this.m_MinorFont;
                        }
                    }
                }
                if (nam === null) {
                    for (const a of x.attributes) {
                        if (!Utils.endsWithString(a.local_name, "theme", true) && !Utils.endsWithString(a.local_name, "asia", true)) {
                            nam = a.value;
                            break;
                        }
                    }
                }
                if (!Utils.isNullOrEmpty(nam)) 
                    st.addAttr("font-name", nam, false);
            }
        }
        DocTextStyles.readUnitextStyleExt(node, st, true, false);
    }
    
    static readUnitextStyleExt(node, st, ignoreFontName = false, numRegime = false) {
        for (const x of node.child_nodes) {
            if (x.local_name === "b" && !numRegime) {
                let val = DocTextStyles._readAttrVal(x, "val", null);
                if (val === "0") 
                    val = "normal";
                else 
                    val = "bold";
                st.addAttr("font-weight", val, false);
            }
            else if (x.local_name === "i" && !numRegime) {
                let val = DocTextStyles._readAttrVal(x, "val", null);
                if (val === "0") 
                    st.addAttr("font-style", "none", false);
                else 
                    st.addAttr("font-style", "italic", false);
            }
            else if (x.local_name === "u" && !numRegime) {
                let val = DocTextStyles._readAttrVal(x, "val", null);
                if (val === "none") 
                    st.addAttr("text-decoration", "none", false);
                else 
                    st.addAttr("text-decoration", "underline", false);
            }
            else if (x.local_name === "strike" && !numRegime) {
                let val = DocTextStyles._readAttrVal(x, "val", null);
                if (val !== "0") 
                    st.addAttr("text-decoration", "line-through", false);
            }
            else if (x.local_name === "caps" && !numRegime) 
                st.addAttr("upper-case", "true", false);
            else if (x.local_name === "rFonts" && !ignoreFontName) {
                let nam = DocTextStyles._readAttrVal(x, "cs", "ansii");
                if (nam === null) 
                    nam = DocTextStyles._readAttrVal(x, "ascii", "hAnsii");
                if (nam === null) 
                    nam = st.getAttr("font-name");
                if (!Utils.isNullOrEmpty(nam)) 
                    st.addAttr("font-name", nam, false);
            }
            else if (x.local_name === "sz" && !numRegime) {
                let d = 0;
                let wrapd479 = new RefOutArgWrapper();
                let inoutres480 = MiscHelper.tryParseDouble(DocTextStyles._readAttrVal(x, "val", null), wrapd479);
                d = wrapd479.value;
                if (inoutres480) 
                    st.addAttr("font-size", (MiscHelper.outDouble(d / (2)) + "pt"), false);
            }
            else if (x.local_name === "highlight" || x.local_name === "color") {
                let val = DocTextStyles._corrColor(DocTextStyles._readAttrVal(x, "val", null));
                if (val === null || val === "auto") 
                    continue;
                if (x.local_name === "color") 
                    st.addAttr("color", val, false);
                else 
                    st.addAttr("background-color", val, false);
            }
            else if (x.local_name === "shd") {
                let val = DocTextStyles._readAttrVal(x, "color", null);
                if (val === "auto" || DocTextStyles._readAttrVal(x, "val", null) === "clear") 
                    val = DocTextStyles._corrColor(DocTextStyles._readAttrVal(x, "fill", null));
                else 
                    val = DocTextStyles._corrColor(val);
                if (val !== null && val !== "auto") 
                    st.addAttr("background-color", val, false);
            }
            else if (x.local_name === "rPr") {
                if (node.local_name === "pPr") {
                }
                else 
                    DocTextStyles.readUnitextStyleExt(x, st, ignoreFontName, numRegime);
            }
            else if (x.local_name === "jc" && !numRegime) {
                let val = DocTextStyles._readAttrVal(x, "val", null);
                if (val === "start") 
                    val = "left";
                else if (val === "end") 
                    val = "right";
                else if (val === "both") 
                    val = "justify";
                st.addAttr("text-align", val, false);
            }
            else if (x.local_name === "vAlign" && !numRegime) {
                let val = DocTextStyles._readAttrVal(x, "val", null);
                st.addAttr("vertical-align", val, false);
            }
            else if (x.local_name === "spacing" && !numRegime) {
                let tempVal = DocTextStyles._readAttrVal(x, "val", null);
                if (tempVal !== null) 
                    st.addAttr("letter-spacing", DocTextStyles._getSizeVal(tempVal, false), false);
                let d = 0;
                let rule = DocTextStyles._readAttrVal(x, "lineRule", null);
                for (const a of x.attributes) {
                    if (a.local_name === "before" || a.local_name === "top") 
                        st.addAttr("margin-top", DocTextStyles._getSizeVal(a.value, false), false);
                    else if (a.local_name === "after" || a.local_name === "bottom") 
                        st.addAttr("margin-bottom", DocTextStyles._getSizeVal(a.value, false), false);
                    else if (a.local_name === "line") {
                        let wrapd481 = new RefOutArgWrapper();
                        let inoutres482 = MiscHelper.tryParseDouble(a.value, wrapd481);
                        d = wrapd481.value;
                        if (inoutres482) {
                            let val = null;
                            if (rule === "auto") {
                                d = Utils.mathRound(d / (240), 2);
                                val = (MiscHelper.outDouble(d));
                            }
                            else if (rule === "exact") {
                                d = Utils.mathRound(d / (20), 2);
                                val = (MiscHelper.outDouble(d) + "pt");
                                let pt = SizeunitConverter.convert(st.getAttr("font-size"), "pt");
                                if (pt !== null && pt > 0) 
                                    val = MiscHelper.outDouble(Utils.mathRound(d / pt, 2));
                            }
                            else {
                            }
                            if (val !== null) 
                                st.addAttr("line-height", val, false);
                        }
                    }
                }
            }
            else if (x.local_name === "tcW") {
                let val = DocTextStyles._readAttrVal(x, "w", null);
                if (val !== null) 
                    st.addAttr("width", DocTextStyles._getSizeVal(val, false), false);
            }
            else if (x.local_name === "ind") {
                for (const a of x.attributes) {
                    if (a.local_name === "left" || a.local_name === "start") 
                        st.addAttr("margin-left", DocTextStyles._getSizeVal(a.value, true), false);
                    else if (a.local_name === "right" || a.local_name === "end") 
                        st.addAttr("margin-right", DocTextStyles._getSizeVal(a.value, true), false);
                    else if (a.local_name === "firstLine") 
                        st.addAttr("text-indent", DocTextStyles._getSizeVal(a.value, true), false);
                    else if (a.local_name === "hanging") 
                        st.addAttr("text-indent", "-" + DocTextStyles._getSizeVal(a.value, true), false);
                }
            }
        }
    }
    
    readTheme(node) {
        for (const x1 of node.child_nodes) {
            for (const x2 of x1.child_nodes) {
                if (x2.local_name === "fontScheme") {
                    for (const x3 of x2.child_nodes) {
                        if (x3.local_name === "majorFont" || x3.local_name === "minorFont") {
                            for (const x4 of x3.child_nodes) {
                                if (x4.local_name === "latin") {
                                    if (x3.local_name === "majorFont") 
                                        this.m_MajorFont = DocTextStyles._readAttrVal(x4, "typeface", null);
                                    else 
                                        this.m_MinorFont = DocTextStyles._readAttrVal(x4, "typeface", null);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    readAllStyles(node, nums) {
        for (const xnum of node.child_nodes) {
            if (xnum.local_name === "style") {
                let isNormal = false;
                for (const x of xnum.child_nodes) {
                    if (x.local_name === "name") {
                        for (const xAttr of x.attributes) {
                            if (xAttr.value === "Normal") 
                                isNormal = true;
                            break;
                        }
                    }
                }
                if (!isNormal) 
                    continue;
                for (const x of xnum.child_nodes) {
                    if (x.local_name === "rPr") {
                        this.defStyle = new UnitextStyle();
                        this.readUnitextStyle(x, this.defStyle, false);
                    }
                }
                if (isNormal) 
                    break;
            }
        }
        if (this.defStyle !== null) {
            if (!this.defStyle.attrs.containsKey("font-name")) {
                for (const xnum of node.child_nodes) {
                    if (xnum.local_name === "docDefaults") {
                        for (const x of xnum.child_nodes) {
                            if (x.local_name === "rPrDefault") {
                                for (const xx of x.child_nodes) {
                                    if (xx.local_name === "rPr") 
                                        this.readUnitextStyle(xx, this.defStyle, false);
                                }
                            }
                        }
                    }
                }
            }
        }
        if (this.defStyle === null) {
            for (const xnum of node.child_nodes) {
                if (xnum.local_name === "docDefaults") {
                    for (const x of xnum.child_nodes) {
                        if (x.local_name === "rPrDefault") {
                            for (const xx of x.child_nodes) {
                                if (xx.local_name === "rPr") {
                                    this.defStyle = new UnitextStyle();
                                    this.readUnitextStyle(xx, this.defStyle, false);
                                }
                            }
                        }
                    }
                }
            }
        }
        for (const xnum of node.child_nodes) {
            if (xnum.local_name === "style" && xnum.attributes !== null && xnum.attributes.length >= 1) {
                let id = DocTextStyles._readAttrVal(xnum, "styleId", null);
                if (id === null || this.m_TextStyles.containsKey(id)) 
                    continue;
                let sty = new DocTextStyle();
                sty.xml = xnum;
                let typ = DocTextStyles._readAttrVal(xnum, "type", null);
                if (this.defStyle !== null) 
                    this.defStyle.copyTo(sty.uStyle);
                if (typ !== null && this.defStyles.containsKey(typ)) 
                    this.defStyles.get(typ).copyTo(sty.uStyle);
                this.m_TextStyles.put(id, sty);
                for (const x of xnum.child_nodes) {
                    if (x.local_name === "name") {
                        if (x.attributes !== null && x.attributes.length > 0) 
                            sty.name = x.attributes[0].value;
                        if (sty.name !== null && sty.name === "Body Text Indent") {
                        }
                    }
                    else if (x.local_name === "aliases") {
                        if (x.attributes !== null && x.attributes.length > 0) 
                            sty.aliases = x.attributes[0].value;
                    }
                    else if (x.local_name === "basedOn") 
                        sty.basedOn = DocTextStyles._readAttrVal(x, "val", null);
                }
            }
        }
        for (const kp of this.m_TextStyles.entries) {
            let sty = kp.value;
            if (sty.loaded) 
                continue;
            if (kp.key === "XX") {
            }
            if (sty.basedOn !== null && this.m_TextStyles.containsKey(sty.basedOn)) {
                let sty0 = this.m_TextStyles.get(sty.basedOn);
                if (!sty0.loaded) {
                    if (sty0.basedOn !== null && this.m_TextStyles.containsKey(sty0.basedOn)) {
                        let sty00 = this.m_TextStyles.get(sty0.basedOn);
                        if (!sty00.loaded) 
                            this._readSingleStyle(sty00);
                        sty0.numId = sty00.numId;
                        sty0.numLvl = sty00.numLvl;
                        sty00.uStyle.copyTo(sty0.uStyle);
                    }
                    this._readSingleStyle(sty0);
                }
                sty.numId = sty0.numId;
                sty.numLvl = sty0.numLvl;
                sty0.uStyle.copyTo(sty.uStyle);
            }
            this._readSingleStyle(sty);
            if (sty.numId !== null && nums !== null) {
                let num = nums.getStyle(sty.numId);
                if (num !== null) {
                    let lvl = num.getLevel(sty.numLvl);
                    if (lvl !== null && lvl.style !== null) {
                        for (const a of lvl.style.attrs.entries) {
                            if (!sty.uStyle.attrs.containsKey(a.key)) 
                                sty.uStyle.attrs.put(a.key, a.value);
                        }
                    }
                }
            }
        }
    }
    
    _readSingleStyle(sty) {
        let typ = DocTextStyles._readAttrVal(sty.xml, "type", null);
        for (const x of sty.xml.child_nodes) {
            if (x.local_name === "rPr") {
                this.readUnitextStyle(x, sty.uStyle, sty.isHeading);
                if (DocTextStyles._readAttrVal(sty.xml, "default", null) === "1") {
                    if (!this.defStyles.containsKey(typ)) 
                        this.defStyles.put(typ, sty.uStyle);
                }
            }
            else if (x.local_name === "pPr") {
                this.readUnitextStyle(x, sty.uStyle, false);
                for (const xx of x.child_nodes) {
                    if (xx.local_name === "numPr") {
                        for (const xxx of xx.child_nodes) {
                            if (xxx.local_name === "numId" && xxx.attributes !== null) {
                                for (const a of xxx.attributes) {
                                    if (a.local_name === "val") 
                                        sty.numId = a.value;
                                }
                            }
                            else if (xxx.local_name === "ilvl" && xxx.attributes !== null) {
                                for (const a of xxx.attributes) {
                                    if (a.local_name === "val") {
                                        let ll = 0;
                                        let wrapll483 = new RefOutArgWrapper();
                                        let inoutres484 = Utils.tryParseInt(a.value, wrapll483);
                                        ll = wrapll483.value;
                                        if (inoutres484) 
                                            sty.numLvl = ll;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (sty.isHeading) 
            sty.uStyle.addAttr("heading-level", sty.calcHeadingLevel().toString(), false);
        sty.loaded = true;
    }
    
    readAllExcelStyles(node) {
        let brdr = new Array();
        let specFrms = new Hashtable();
        for (const xx of node.child_nodes) {
            if (xx.local_name === "borders") {
                for (const xxx of xx.child_nodes) {
                    if (xxx.local_name === "border") {
                        let brd = new BorderInfo();
                        brdr.push(brd);
                        for (const y of xxx.child_nodes) {
                            if (y.attributes !== null && ((y.attributes.length > 0 || y.child_nodes.length > 0))) {
                                if (y.local_name === "left") 
                                    brd.left = true;
                                else if (y.local_name === "right") 
                                    brd.right = true;
                                else if (y.local_name === "top") 
                                    brd.top = true;
                                else if (y.local_name === "bottom") 
                                    brd.bottom = true;
                            }
                        }
                    }
                }
            }
            else if (xx.local_name === "numFmts") {
                for (const xxx of xx.child_nodes) {
                    if (xxx.local_name === "numFmt") {
                        let cod = null;
                        let frm = null;
                        for (const a of xxx.attributes) {
                            if (a.local_name === "numFmtId") 
                                cod = a.value;
                            else if (a.local_name === "formatCode") 
                                frm = a.value;
                        }
                        if (cod !== null && frm !== null && !specFrms.containsKey(cod)) 
                            specFrms.put(cod, frm);
                    }
                }
            }
        }
        for (const x1 of node.child_nodes) {
            if (x1.local_name === "cellXfs") {
                let id = 0;
                for (const xx of x1.child_nodes) {
                    if (xx.local_name === "xf") {
                        let st = new DocTextStyle();
                        st.name = id.toString();
                        id++;
                        this.m_TextStyles.put(st.name, st);
                        for (const a of xx.attributes) {
                            if (a.local_name === "numFmtId") {
                                st.xlsFormat = a.value;
                                if (specFrms.containsKey(a.value)) 
                                    st.xlsFormat = specFrms.get(a.value);
                            }
                            else if (a.local_name === "borderId") {
                                let n = 0;
                                let wrapn485 = new RefOutArgWrapper();
                                let inoutres486 = Utils.tryParseInt(a.value, wrapn485);
                                n = wrapn485.value;
                                if (inoutres486) {
                                    if (n >= 0 && (n < brdr.length)) 
                                        st.xlsBorder = brdr[n];
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}


module.exports = DocTextStyles