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

const MyXmlNodeType = require("./MyXmlNodeType");
const EncodingStandard = require("./../../../util/EncodingStandard");
const EncodingWrapper = require("./../../../util/EncodingWrapper");

class MyXmlReader {
    
    constructor() {
        this.m_Tmp = new StringBuilder();
        this.m_Tmp2 = null;
        this.m_Text = null;
        this.m_Pos = 0;
        this.nodeType = MyXmlNodeType.NONE;
        this.localName = null;
        this.value = null;
        this.attributes = new Hashtable();
        this.isEmptyElement = false;
    }
    
    static create(data) {
        let res = new MyXmlReader();
        let hlen = 0;
        let wraphlen101 = new RefOutArgWrapper();
        let enc = EncodingWrapper.checkEncoding(data, wraphlen101);
        hlen = wraphlen101.value;
        if (enc === null) 
            enc = new EncodingWrapper(EncodingStandard.ACSII);
        res.m_Text = enc.getString(data, hlen, data.length - hlen);
        res.m_Pos = 0;
        while (true) {
            if (!res._readHead()) 
                break;
        }
        return res;
    }
    
    _gotoNonsp() {
        for (; this.m_Pos < this.m_Text.length; this.m_Pos++) {
            if (!Utils.isWhitespace(this.m_Text[this.m_Pos])) 
                break;
        }
    }
    
    _readHead() {
        this._gotoNonsp();
        if (((this.m_Pos + 10) < this.m_Text.length) && this.m_Text[this.m_Pos] === '<' && this.m_Text[this.m_Pos + 1] === '?') {
            this.m_Pos += 2;
            for (; this.m_Pos < this.m_Text.length; this.m_Pos++) {
                if (this.m_Text[this.m_Pos] === '>' && this.m_Text[this.m_Pos - 1] === '?') {
                    this.m_Pos++;
                    return true;
                }
            }
        }
        return false;
    }
    
    _readName() {
        this._gotoNonsp();
        this.m_Tmp.length = 0;
        for (; this.m_Pos < this.m_Text.length; this.m_Pos++) {
            let ch = this.m_Text[this.m_Pos];
            if (Utils.isLetter(ch) || ch === '_') 
                this.m_Tmp.append(ch);
            else if (this.m_Tmp.length > 0 && ((Utils.isDigit(ch) || ch === '-' || ch === ':'))) 
                this.m_Tmp.append(ch);
            else 
                break;
        }
        if (this.m_Tmp.length > 0) 
            return this.m_Tmp.toString();
        return null;
    }
    
    _readChar() {
        if (this.m_Pos >= this.m_Text.length) 
            return MyXmlReader.m_Char0;
        let ch = this.m_Text[this.m_Pos];
        this.m_Pos++;
        if (ch !== '&') 
            return ch;
        if (this.m_Pos >= this.m_Text.length) 
            return ch;
        if (this.m_Tmp2 === null) 
            this.m_Tmp2 = new StringBuilder();
        this.m_Tmp2.length = 0;
        for (; this.m_Pos < this.m_Text.length; this.m_Pos++) {
            if (this.m_Text[this.m_Pos] === ';') {
                this.m_Pos++;
                break;
            }
            else 
                this.m_Tmp2.append(this.m_Text[this.m_Pos]);
        }
        let txt = this.m_Tmp2.toString().toUpperCase();
        if (txt === "LT") 
            return '<';
        if (txt === "GT") 
            return '>';
        if (txt === "AMP") 
            return '&';
        if (txt === "QUOT") 
            return '"';
        if (txt === "APOS") 
            return '\'';
        if (txt === "NBSP") 
            return String.fromCharCode(0xA0);
        if (txt.length === 0) 
            return MyXmlReader.m_Char0;
        if (txt[0] === 'X') {
            let cod = 0;
            for (let i = 1; i < txt.length; i++) {
                if (Utils.isDigit(txt[i])) 
                    cod = ((cod * 16) + (txt.charCodeAt(i))) - 0x30;
                else if ((txt.charCodeAt(i)) >= 0x41 && (txt.charCodeAt(i)) <= 0x46) 
                    cod = (((cod * 16) + (txt.charCodeAt(i))) - 0x41) + 10;
            }
            return String.fromCharCode(cod);
        }
        if (Utils.isDigit(txt[0])) {
            let cod = 0;
            for (let i = 1; i < txt.length; i++) {
                if (Utils.isDigit(txt[i])) 
                    cod = ((cod * 10) + (txt.charCodeAt(i))) - 0x30;
            }
            return String.fromCharCode(cod);
        }
        return txt[0];
    }
    
    _readValue(attrChar) {
        this.m_Tmp.length = 0;
        for (; this.m_Pos < this.m_Text.length; ) {
            let ch = this.m_Text[this.m_Pos];
            if (attrChar === ch) {
                this.m_Pos++;
                break;
            }
            if (attrChar === MyXmlReader.m_Char0) {
                if (ch === '<') 
                    break;
            }
            ch = this._readChar();
            if (ch !== MyXmlReader.m_Char0) 
                this.m_Tmp.append(ch);
            else 
                break;
        }
        return this.m_Tmp.toString();
    }
    
    _readAttr(nam, val) {
        val.value = null;
        let pos = this.m_Pos;
        nam.value = this._readName();
        if (nam.value === null) 
            return false;
        this._gotoNonsp();
        if (this.m_Pos >= this.m_Text.length || this.m_Text[this.m_Pos] !== '=') 
            return false;
        this.m_Pos++;
        this._gotoNonsp();
        if (this.m_Pos < this.m_Text.length) {
            let ch = this.m_Text[this.m_Pos];
            if (ch === '"' || ch === '\'') {
                this.m_Pos++;
                val.value = this._readValue(ch);
                if (val.value !== null) {
                    if ((this.m_Pos < this.m_Text.length) && this.m_Text[this.m_Pos] === ch) 
                        this.m_Pos++;
                    return true;
                }
            }
        }
        this.m_Pos = pos;
        return false;
    }
    
    read() {
        this.attributes.clear();
        this.isEmptyElement = false;
        this.localName = null;
        this.value = null;
        this.nodeType = MyXmlNodeType.NONE;
        if (this.m_Pos >= this.m_Text.length) 
            return false;
        let ch = this.m_Text[this.m_Pos];
        if (ch !== '<') {
            this.value = this._readValue(MyXmlReader.m_Char0);
            if (this.value !== null) {
                this.nodeType = MyXmlNodeType.TEXT;
                this.localName = "#text";
                return true;
            }
            return false;
        }
        this.m_Pos++;
        if ((this.m_Pos + 3) > this.m_Text.length) 
            return false;
        ch = this.m_Text[this.m_Pos];
        if (ch === '/') {
            this.m_Pos++;
            this.localName = this._readName();
            this._gotoNonsp();
            if (this.localName !== null && (this.m_Pos < this.m_Text.length) && this.m_Text[this.m_Pos] === '>') {
                this.nodeType = MyXmlNodeType.ENDELEMENT;
                this.m_Pos++;
                return true;
            }
            return false;
        }
        this.localName = this._readName();
        if (this.localName === null) 
            return false;
        this.nodeType = MyXmlNodeType.ELEMENT;
        for (; this.m_Pos < this.m_Text.length; ) {
            this._gotoNonsp();
            if (this.m_Pos >= this.m_Text.length) 
                break;
            ch = this.m_Text[this.m_Pos];
            if (ch === '>') {
                this.m_Pos++;
                break;
            }
            if (ch === '/' && ((this.m_Pos + 1) < this.m_Text.length) && this.m_Text[this.m_Pos + 1] === '>') {
                this.isEmptyElement = true;
                this.m_Pos += 2;
                break;
            }
            let nam = null;
            let val = null;
            let wrapnam102 = new RefOutArgWrapper();
            let wrapval103 = new RefOutArgWrapper();
            let inoutres104 = this._readAttr(wrapnam102, wrapval103);
            nam = wrapnam102.value;
            val = wrapval103.value;
            if (inoutres104) {
                if (!this.attributes.containsKey(nam)) 
                    this.attributes.put(nam, val);
            }
            else 
                break;
        }
        return true;
    }
    
    toString() {
        let tmp = new StringBuilder();
        if (this.nodeType === MyXmlNodeType.ELEMENT) {
            tmp.append("<").append(this.localName);
            for (const kp of this.attributes.entries) {
                tmp.append(" ").append(kp.key).append("=\"").append(kp.value).append("\"");
            }
            if (this.isEmptyElement) 
                tmp.append(" />");
            else 
                tmp.append(">");
        }
        else if (this.nodeType === MyXmlNodeType.ENDELEMENT) 
            tmp.append("</").append(this.localName).append(">");
        else if (this.nodeType === MyXmlNodeType.TEXT) 
            tmp.append("#text: ").append(((this.value != null ? this.value : "")));
        return tmp.toString();
    }
    
    getAttribute(nam) {
        if (this.attributes.containsKey(nam)) 
            return this.attributes.get(nam);
        return null;
    }
    
    static static_constructor() {
        MyXmlReader.m_Char0 = String.fromCharCode(0);
    }
}


MyXmlReader.static_constructor();

module.exports = MyXmlReader