/*
 * 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
 */

package com.pullenti.unitext.internal.misc;

public class MyXmlReader {

    public static MyXmlReader create(byte[] data) {
        MyXmlReader res = new MyXmlReader();
        int hlen = 0;
        com.pullenti.unisharp.Outargwrapper<Integer> wraphlen101 = new com.pullenti.unisharp.Outargwrapper<Integer>();
        com.pullenti.util.EncodingWrapper enc = com.pullenti.util.EncodingWrapper.checkEncoding(data, wraphlen101);
        hlen = (wraphlen101.value != null ? wraphlen101.value : 0);
        if (enc == null) 
            enc = new com.pullenti.util.EncodingWrapper(com.pullenti.util.EncodingStandard.ACSII, null, 0);
        res.m_Text = enc.getString(data, hlen, data.length - hlen);
        res.m_Pos = 0;
        while (true) {
            if (!res._readHead()) 
                break;
        }
        return res;
    }

    private void _gotoNonsp() {
        for (; m_Pos < m_Text.length(); m_Pos++) {
            if (!com.pullenti.unisharp.Utils.isWhitespace(m_Text.charAt(m_Pos))) 
                break;
        }
    }

    private boolean _readHead() {
        this._gotoNonsp();
        if (((m_Pos + 10) < m_Text.length()) && m_Text.charAt(m_Pos) == '<' && m_Text.charAt(m_Pos + 1) == '?') {
            m_Pos += 2;
            for (; m_Pos < m_Text.length(); m_Pos++) {
                if (m_Text.charAt(m_Pos) == '>' && m_Text.charAt(m_Pos - 1) == '?') {
                    m_Pos++;
                    return true;
                }
            }
        }
        return false;
    }

    private StringBuilder m_Tmp = new StringBuilder();

    private StringBuilder m_Tmp2;

    private static char m_Char0 = (char)0;

    private String _readName() {
        this._gotoNonsp();
        m_Tmp.setLength(0);
        for (; m_Pos < m_Text.length(); m_Pos++) {
            char ch = m_Text.charAt(m_Pos);
            if (Character.isLetter(ch) || ch == '_') 
                m_Tmp.append(ch);
            else if (m_Tmp.length() > 0 && ((Character.isDigit(ch) || ch == '-' || ch == ':'))) 
                m_Tmp.append(ch);
            else 
                break;
        }
        if (m_Tmp.length() > 0) 
            return m_Tmp.toString();
        return null;
    }

    private char _readChar() {
        if (m_Pos >= m_Text.length()) 
            return m_Char0;
        char ch = m_Text.charAt(m_Pos);
        m_Pos++;
        if (ch != '&') 
            return ch;
        if (m_Pos >= m_Text.length()) 
            return ch;
        if (m_Tmp2 == null) 
            m_Tmp2 = new StringBuilder();
        m_Tmp2.setLength(0);
        for (; m_Pos < m_Text.length(); m_Pos++) {
            if (m_Text.charAt(m_Pos) == ';') {
                m_Pos++;
                break;
            }
            else 
                m_Tmp2.append(m_Text.charAt(m_Pos));
        }
        String txt = m_Tmp2.toString().toUpperCase();
        if (com.pullenti.unisharp.Utils.stringsEq(txt, "LT")) 
            return '<';
        if (com.pullenti.unisharp.Utils.stringsEq(txt, "GT")) 
            return '>';
        if (com.pullenti.unisharp.Utils.stringsEq(txt, "AMP")) 
            return '&';
        if (com.pullenti.unisharp.Utils.stringsEq(txt, "QUOT")) 
            return '"';
        if (com.pullenti.unisharp.Utils.stringsEq(txt, "APOS")) 
            return '\'';
        if (com.pullenti.unisharp.Utils.stringsEq(txt, "NBSP")) 
            return (char)0xA0;
        if (txt.length() == 0) 
            return m_Char0;
        if (txt.charAt(0) == 'X') {
            int cod = 0;
            for (int i = 1; i < txt.length(); i++) {
                if (Character.isDigit(txt.charAt(i))) 
                    cod = ((cod * 16) + ((int)txt.charAt(i))) - 0x30;
                else if (((int)txt.charAt(i)) >= 0x41 && ((int)txt.charAt(i)) <= 0x46) 
                    cod = (((cod * 16) + ((int)txt.charAt(i))) - 0x41) + 10;
            }
            return (char)cod;
        }
        if (Character.isDigit(txt.charAt(0))) {
            int cod = 0;
            for (int i = 1; i < txt.length(); i++) {
                if (Character.isDigit(txt.charAt(i))) 
                    cod = ((cod * 10) + ((int)txt.charAt(i))) - 0x30;
            }
            return (char)cod;
        }
        return txt.charAt(0);
    }

    private String _readValue(char attrChar) {
        m_Tmp.setLength(0);
        for (; m_Pos < m_Text.length(); ) {
            char ch = m_Text.charAt(m_Pos);
            if (attrChar == ch) {
                m_Pos++;
                break;
            }
            if (attrChar == m_Char0) {
                if (ch == '<') 
                    break;
            }
            ch = this._readChar();
            if (ch != m_Char0) 
                m_Tmp.append(ch);
            else 
                break;
        }
        return m_Tmp.toString();
    }

    private boolean _readAttr(com.pullenti.unisharp.Outargwrapper<String> nam, com.pullenti.unisharp.Outargwrapper<String> val) {
        val.value = null;
        int pos = m_Pos;
        nam.value = this._readName();
        if (nam.value == null) 
            return false;
        this._gotoNonsp();
        if (m_Pos >= m_Text.length() || m_Text.charAt(m_Pos) != '=') 
            return false;
        m_Pos++;
        this._gotoNonsp();
        if (m_Pos < m_Text.length()) {
            char ch = m_Text.charAt(m_Pos);
            if (ch == '"' || ch == '\'') {
                m_Pos++;
                val.value = this._readValue(ch);
                if (val.value != null) {
                    if ((m_Pos < m_Text.length()) && m_Text.charAt(m_Pos) == ch) 
                        m_Pos++;
                    return true;
                }
            }
        }
        m_Pos = pos;
        return false;
    }

    private String m_Text;

    private int m_Pos;

    public boolean read() {
        attributes.clear();
        isEmptyElement = false;
        localName = null;
        value = null;
        nodeType = MyXmlNodeType.NONE;
        if (m_Pos >= m_Text.length()) 
            return false;
        char ch = m_Text.charAt(m_Pos);
        if (ch != '<') {
            value = this._readValue(m_Char0);
            if (value != null) {
                nodeType = MyXmlNodeType.TEXT;
                localName = "#text";
                return true;
            }
            return false;
        }
        m_Pos++;
        if ((m_Pos + 3) > m_Text.length()) 
            return false;
        ch = m_Text.charAt(m_Pos);
        if (ch == '/') {
            m_Pos++;
            localName = this._readName();
            this._gotoNonsp();
            if (localName != null && (m_Pos < m_Text.length()) && m_Text.charAt(m_Pos) == '>') {
                nodeType = MyXmlNodeType.ENDELEMENT;
                m_Pos++;
                return true;
            }
            return false;
        }
        localName = this._readName();
        if (localName == null) 
            return false;
        nodeType = MyXmlNodeType.ELEMENT;
        for (; m_Pos < m_Text.length(); ) {
            this._gotoNonsp();
            if (m_Pos >= m_Text.length()) 
                break;
            ch = m_Text.charAt(m_Pos);
            if (ch == '>') {
                m_Pos++;
                break;
            }
            if (ch == '/' && ((m_Pos + 1) < m_Text.length()) && m_Text.charAt(m_Pos + 1) == '>') {
                isEmptyElement = true;
                m_Pos += 2;
                break;
            }
            String nam;
            String val;
            com.pullenti.unisharp.Outargwrapper<String> wrapnam102 = new com.pullenti.unisharp.Outargwrapper<String>();
            com.pullenti.unisharp.Outargwrapper<String> wrapval103 = new com.pullenti.unisharp.Outargwrapper<String>();
            boolean inoutres104 = this._readAttr(wrapnam102, wrapval103);
            nam = wrapnam102.value;
            val = wrapval103.value;
            if (inoutres104) {
                if (!attributes.containsKey(nam)) 
                    attributes.put(nam, val);
            }
            else 
                break;
        }
        return true;
    }

    @Override
    public String toString() {
        StringBuilder tmp = new StringBuilder();
        if (nodeType == MyXmlNodeType.ELEMENT) {
            tmp.append("<").append(localName);
            for (java.util.Map.Entry<String, String> kp : attributes.entrySet()) {
                tmp.append(" ").append(kp.getKey()).append("=\"").append(kp.getValue()).append("\"");
            }
            if (isEmptyElement) 
                tmp.append(" />");
            else 
                tmp.append(">");
        }
        else if (nodeType == MyXmlNodeType.ENDELEMENT) 
            tmp.append("</").append(localName).append(">");
        else if (nodeType == MyXmlNodeType.TEXT) 
            tmp.append("#text: ").append(((value != null ? value : "")));
        return tmp.toString();
    }

    public MyXmlNodeType nodeType = MyXmlNodeType.NONE;

    public String localName;

    public String value;

    public java.util.HashMap<String, String> attributes = new java.util.HashMap<String, String>();

    public String getAttribute(String nam) {
        if (attributes.containsKey(nam)) 
            return attributes.get(nam);
        return null;
    }

    public boolean isEmptyElement;

    public MyXmlReader() {
    }
}
