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

const RftItemTyp = require("./RftItemTyp");

/**
 * Простейший элемент структуры файла RTF
 */
class RtfItem {
    
    constructor() {
        this.typ = RftItemTyp.UNDEFINED;
        this.text = null;
        this.codes = null;
        this.level = 0;
    }
    
    toString() {
        if (this.typ === RftItemTyp.BRACKETOPEN) 
            return (String(this.level) + ": {");
        if (this.typ === RftItemTyp.BRACKETCLOSE) 
            return (String(this.level) + ": }");
        if (this.typ === RftItemTyp.COMMAND) 
            return (String(this.level) + ": \\" + ((this.text != null ? this.text : "")));
        if (this.typ === RftItemTyp.IMAGE) 
            return (String(this.level) + ": Image " + ((this.text != null ? this.text : "")) + ": Len=" + this.codes.length);
        if (this.typ === RftItemTyp.TEXT) {
            if (this.text !== null) 
                return (String(this.level) + ": [" + this.text.length + "] '" + (this.text.length > 200 ? this.text.substring(0, 0 + 200) : this.text) + "'");
            if (this.codes !== null) {
                let tmp = new StringBuilder();
                tmp.append(this.level).append(": [").append(this.codes.length).append("]");
                for (const c of this.codes) {
                    tmp.append("'").append(Utils.correctToString((c).toString(16).toUpperCase(), 2, true)).append("' ");
                    if (tmp.length > 200) {
                        tmp.append("...");
                        break;
                    }
                }
                return tmp.toString();
            }
        }
        return "?";
    }
    
    static parseList(stream) {
        const RtfItemImage = require("./RtfItemImage");
        let res = new Array();
        let txtBuf = new StringBuilder();
        let codBuf = new Array();
        let command = new RtfItem.RftCommand();
        while (stream.position < stream.length) {
            let i = stream.readByte();
            if (i < 0) 
                break;
            let ch = String.fromCharCode(i);
            let newItem = null;
            let newCode = 0;
            let newChar = String.fromCharCode(0);
            if (ch === '{') 
                newItem = RtfItem._new299(RftItemTyp.BRACKETOPEN);
            else if (ch === '}') 
                newItem = RtfItem._new299(RftItemTyp.BRACKETCLOSE);
            else if (ch === '\\') {
                if (!command.parse(stream)) 
                    continue;
                if (command.charCode !== (0)) 
                    newCode = command.charCode;
                else if ((command.pureChar.charCodeAt(0)) !== 0) 
                    newChar = command.pureChar;
                else if (command.pictContent !== null) 
                    newItem = RtfItemImage._new301(RftItemTyp.IMAGE, command.picWidth, command.picHeight, command.command, command.pictContent);
                else if (command.command !== null) 
                    newItem = RtfItem._new302(RftItemTyp.COMMAND, command.command);
            }
            else {
                if ((ch.charCodeAt(0)) === 0xD || (ch.charCodeAt(0)) === 0xA) 
                    continue;
                if ((ch.charCodeAt(0)) < 0x80) 
                    newChar = ch;
                else 
                    newCode = ch.charCodeAt(0);
            }
            if (newItem !== null || newCode !== (0)) {
                if (txtBuf.length > 0) {
                    res.push(RtfItem._new302(RftItemTyp.TEXT, txtBuf.toString()));
                    txtBuf.length = 0;
                }
            }
            if (newItem !== null || (newChar.charCodeAt(0)) !== 0) {
                if (codBuf.length > 0) {
                    res.push(RtfItem._new304(RftItemTyp.TEXT, codBuf));
                    codBuf.splice(0, codBuf.length);
                }
            }
            if (newItem !== null) 
                res.push(newItem);
            if (newCode !== (0)) 
                codBuf.push(newCode);
            if ((newChar.charCodeAt(0)) !== 0) 
                txtBuf.append(newChar);
        }
        if (txtBuf.length > 0) {
            res.push(RtfItem._new302(RftItemTyp.TEXT, txtBuf.toString()));
            txtBuf.length = 0;
        }
        if (codBuf.length > 0) {
            res.push(RtfItem._new304(RftItemTyp.TEXT, codBuf));
            codBuf.splice(0, codBuf.length);
        }
        let lev = 0;
        for (const it of res) {
            it.level = lev;
            if (it.typ === RftItemTyp.BRACKETOPEN) 
                lev++;
            else if (it.typ === RftItemTyp.BRACKETCLOSE) {
                lev--;
                it.level = lev;
            }
        }
        return res;
    }
    
    static _new299(_arg1) {
        let res = new RtfItem();
        res.typ = _arg1;
        return res;
    }
    
    static _new302(_arg1, _arg2) {
        let res = new RtfItem();
        res.typ = _arg1;
        res.text = _arg2;
        return res;
    }
    
    static _new304(_arg1, _arg2) {
        let res = new RtfItem();
        res.typ = _arg1;
        res.codes = _arg2;
        return res;
    }
}


RtfItem.RftCommand = class  {
    
    constructor() {
        this.command = null;
        this.charCode = 0;
        this.pureChar = '\0';
        this.pictContent = null;
        this.picWidth = 0;
        this.picHeight = 0;
        this.m_TempCmd = null;
    }
    
    parse(stream) {
        this.command = null;
        this.charCode = 0;
        this.pureChar = String.fromCharCode(0);
        this.pictContent = null;
        let i = stream.readByte();
        if (i < 0) 
            return false;
        let ch = String.fromCharCode(i);
        if (ch === '\'') {
            let buf = new Uint8Array(2);
            if (stream.read(buf, 0, 2) !== 2) 
                return false;
            for (i = 0; i < 2; i++) {
                ch = String.fromCharCode(buf[i]);
                if (ch >= '0' && ch <= '9') 
                    buf[i] = ((ch.charCodeAt(0)) - ('0'.charCodeAt(0)));
                else if (ch >= 'a' && ch <= 'f') 
                    buf[i] = (((ch.charCodeAt(0)) - ('a'.charCodeAt(0))) + 10);
                else if (ch >= 'A' && ch <= 'F') 
                    buf[i] = (((ch.charCodeAt(0)) - ('A'.charCodeAt(0))) + 10);
                else 
                    return false;
            }
            this.charCode = (((buf[0]) << 4) | (buf[1]));
            return true;
        }
        if (ch === 'u') {
            let cod = 0;
            i = stream.readByte();
            if (i < 0) 
                return false;
            let ch1 = String.fromCharCode(i);
            if (Utils.isDigit(ch1)) {
                cod = ((ch1.charCodeAt(0)) - ('0'.charCodeAt(0)));
                while (true) {
                    i = stream.readByte();
                    if (i < 0) 
                        break;
                    ch1 = String.fromCharCode(i);
                    if (Utils.isDigit(ch1)) 
                        cod = (cod * 10) + (((ch1.charCodeAt(0)) - ('0'.charCodeAt(0))));
                    else {
                        if (ch1 === '\\') 
                            stream.position = stream.position - (1);
                        break;
                    }
                }
                this.pureChar = String.fromCharCode(cod);
                if (this.m_TempCmd === null) 
                    this.m_TempCmd = new RtfItem.RftCommand();
                if (ch1 === '\\') {
                    let pos = stream.position;
                    stream.position = stream.position + (1);
                    this.m_TempCmd.parse(stream);
                    if (this.m_TempCmd.charCode !== (0)) {
                    }
                    else 
                        stream.position = pos;
                }
                return true;
            }
            else 
                stream.position = stream.position - (1);
        }
        if ("{}\\".indexOf(ch) >= 0) {
            this.pureChar = ch;
            return true;
        }
        if ((ch.charCodeAt(0)) === 0xD || (ch.charCodeAt(0)) === 0xA) {
            this.pureChar = '\n';
            return true;
        }
        let cmd = new StringBuilder();
        cmd.append(ch);
        if (ch !== '*') {
            while (true) {
                if (cmd.length === 1) {
                    if (ch === '~' || ch === '_') 
                        break;
                }
                i = stream.readByte();
                if (i < 0) 
                    break;
                ch = String.fromCharCode(i);
                if ((ch === '\\' || ch === '}' || ch === '{') || i >= 0x80) {
                    stream.position = stream.position - (1);
                    break;
                }
                if (Utils.isWhitespace(ch)) 
                    break;
                cmd.append(ch);
            }
        }
        this.command = cmd.toString();
        if (this.command === "tab") 
            this.pureChar = '\t';
        else if (this.command === "emdash") 
            this.pureChar = String.fromCharCode(0x2014);
        else if (this.command === "endash") 
            this.pureChar = String.fromCharCode(0x2013);
        else if (this.command === "emspace" || this.command === "enspace" || this.command === "~") 
            this.pureChar = ' ';
        else if (this.command === "bullet") 
            this.pureChar = String.fromCharCode(0x2022);
        else if (this.command === "lquote") 
            this.pureChar = String.fromCharCode(0x2018);
        else if (this.command === "rquote") 
            this.pureChar = String.fromCharCode(0x2019);
        else if (this.command === "ldblquote") 
            this.pureChar = String.fromCharCode(0x201C);
        else if (this.command === "rdblquote") 
            this.pureChar = String.fromCharCode(0x201D);
        else if (this.command === "lquote") 
            this.pureChar = String.fromCharCode(0x2018);
        else if (this.command === "_") 
            this.pureChar = '-';
        else if (this.command.length > 2 && this.command[0] === 'u' && Utils.isDigit(this.command[1])) {
            let wrapi289 = new RefOutArgWrapper();
            let inoutres290 = Utils.tryParseInt(this.command.substring(1), wrapi289);
            i = wrapi289.value;
            if (inoutres290) {
                this.pureChar = String.fromCharCode(i);
                return true;
            }
        }
        if ((this.command.startsWith("colortbl") || this.command.startsWith("info") || this.command.startsWith("object")) || this.command.startsWith("pict") || this.command.startsWith("themedata")) {
            let lev = 0;
            let isPict = this.command.startsWith("pict") || this.command.startsWith("object");
            let pictComm = new RtfItem.RftCommand();
            let hexVal = new StringBuilder();
            let picW = 0;
            let picGoalW = 0;
            let picH = 0;
            let picGoalH = 0;
            let scalx = 100;
            let scaly = 100;
            while (true) {
                i = stream.readByte();
                if (i < 0) 
                    break;
                ch = String.fromCharCode(i);
                if (ch === '}') {
                    if (lev === 0) {
                        stream.position = stream.position - (1);
                        break;
                    }
                    else 
                        lev--;
                }
                else if (ch === '{') 
                    lev++;
                else if (ch === '\\') {
                    if (pictComm.parse(stream)) {
                        if (pictComm.command !== null) {
                            if (pictComm.command.startsWith("picwgoal")) {
                                let wrappicGoalW291 = new RefOutArgWrapper();
                                Utils.tryParseInt(pictComm.command.substring(8), wrappicGoalW291);
                                picGoalW = wrappicGoalW291.value;
                            }
                            else if (pictComm.command.startsWith("pichgoal")) {
                                let wrappicGoalH292 = new RefOutArgWrapper();
                                Utils.tryParseInt(pictComm.command.substring(8), wrappicGoalH292);
                                picGoalH = wrappicGoalH292.value;
                            }
                            else if (pictComm.command.startsWith("picw") || pictComm.command.startsWith("objw")) {
                                let wrappicW293 = new RefOutArgWrapper();
                                Utils.tryParseInt(pictComm.command.substring(4), wrappicW293);
                                picW = wrappicW293.value;
                            }
                            else if (pictComm.command.startsWith("pich") || pictComm.command.startsWith("objh")) {
                                let wrappicH294 = new RefOutArgWrapper();
                                Utils.tryParseInt(pictComm.command.substring(4), wrappicH294);
                                picH = wrappicH294.value;
                            }
                            else if (pictComm.command.startsWith("picscalex")) {
                                let wrapscalx295 = new RefOutArgWrapper();
                                Utils.tryParseInt(pictComm.command.substring(9), wrapscalx295);
                                scalx = wrapscalx295.value;
                            }
                            else if (pictComm.command.startsWith("picscaley")) {
                                let wrapscaly296 = new RefOutArgWrapper();
                                Utils.tryParseInt(pictComm.command.substring(9), wrapscaly296);
                                scaly = wrapscaly296.value;
                            }
                            else if (pictComm.command.startsWith("bin")) {
                                let blen = 0;
                                let wrapblen297 = new RefOutArgWrapper();
                                let inoutres298 = Utils.tryParseInt(pictComm.command.substring(3), wrapblen297);
                                blen = wrapblen297.value;
                                if (inoutres298) {
                                    if ((stream.position + (blen)) <= stream.length) {
                                        if (isPict) {
                                            this.pictContent = new Uint8Array(blen);
                                            stream.read(this.pictContent, 0, blen);
                                        }
                                        else 
                                            stream.position = stream.position + (blen);
                                    }
                                }
                            }
                            if (isPict && pictComm.pictContent !== null) 
                                this.pictContent = pictComm.pictContent;
                        }
                    }
                }
                else if (lev === 0 && isPict && Utils.isLetterOrDigit(ch)) 
                    hexVal.append(ch);
            }
            if (isPict && hexVal.length > 10 && this.pictContent === null) {
                this.pictContent = new Uint8Array(Utils.intDiv(hexVal.length, 2));
                let str = hexVal.toString();
                for (let ii = 0, p = 0; ii < (hexVal.length - 1); ii += 2,p++) {
                    let bb = 0;
                    for (let jj = 0; jj < 2; jj++) {
                        let chh = str[ii + jj];
                        let v = 0;
                        if (chh >= '0' && chh <= '9') 
                            v = (chh.charCodeAt(0)) - ('0'.charCodeAt(0));
                        else if (chh >= 'a' && chh <= 'f') 
                            v = 10 + (((chh.charCodeAt(0)) - ('a'.charCodeAt(0))));
                        else if (chh >= 'A' && chh <= 'F') 
                            v = 10 + (((chh.charCodeAt(0)) - ('A'.charCodeAt(0))));
                        else 
                            break;
                        bb = (((bb) << 4) | v);
                    }
                    this.pictContent[p] = bb;
                }
            }
            if (isPict && ((picW > 0 || picGoalW > 0)) && ((picH > 0 || picGoalH > 0))) {
                if (picGoalW <= 0 || picGoalH <= 0) {
                    this.picWidth = Math.floor((0.75 * (this.picWidth)));
                    this.picHeight = Math.floor((0.75 * (this.picHeight)));
                }
                else {
                    this.picWidth = Utils.intDiv(picGoalW, 20);
                    this.picHeight = Utils.intDiv(picGoalH, 20);
                }
                if (scalx > 0) 
                    this.picWidth = Utils.intDiv(this.picWidth * scalx, 100);
                if (scaly > 0) 
                    this.picHeight = Utils.intDiv(this.picHeight * scaly, 100);
            }
            return true;
        }
        return true;
    }
}


module.exports = RtfItem