/*
 * 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.html;

public class HtmlParserNode {

    public int indexFrom;

    public int indexTo;

    public String tagName;

    public TagTypes tagType = TagTypes.UNDEFINED;

    public HtmlTag tag;

    public int closeTagIndex;

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

    public String pureText;

    public boolean whitespacePreserve;

    public boolean whitespaceBefore;

    public boolean printed;

    public boolean isEmpty() {
        if (tagName != null) 
            return false;
        if (attributes != null && attributes.size() > 0) 
            return false;
        if (!com.pullenti.unisharp.Utils.isNullOrEmpty(pureText)) {
            if (whitespacePreserve) 
                return false;
            for (int i = 0; i < pureText.length(); i++) {
                if (!com.pullenti.unisharp.Utils.isWhitespace(pureText.charAt(i))) 
                    return false;
            }
        }
        return true;
    }


    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        if (tagType != TagTypes.UNDEFINED) {
            if (tagType == TagTypes.CLOSE) 
                res.append("</").append(tagName).append(">");
            else {
                res.append("<").append(tagName);
                if (attributes != null) {
                    for (java.util.Map.Entry<String, String> kp : attributes.entrySet()) {
                        res.append(" ").append(kp.getKey()).append("='").append(kp.getValue()).append("'");
                    }
                }
                if (tagType == TagTypes.OPEN) 
                    res.append(">");
                else 
                    res.append("/>");
            }
        }
        else if (pureText != null) 
            res.append(pureText);
        return res.toString();
    }

    public boolean analize(String _html, int indFrom, String endTag, boolean whiteSpacePreserve) {
        if (indFrom >= _html.length()) 
            return false;
        indexFrom = indFrom;
        tagName = null;
        tagType = TagTypes.UNDEFINED;
        if (attributes == null) 
            attributes = new java.util.HashMap<String, String>();
        else 
            attributes.clear();
        pureText = null;
        int i;
        int j;
        char ch = _html.charAt(indFrom);
        if (ch != '<' || ((endTag != null && !isEndTag(_html, indFrom, endTag)))) {
            StringBuilder strTmp = null;
            boolean comment = false;
            int lastNbsp = 0;
            for (i = indFrom; i < _html.length(); i++) {
                boolean nbr = false;
                if (_html.charAt(i) == '<') {
                    if (!comment) {
                        if (endTag == null || isEndTag(_html, i, endTag)) 
                            break;
                    }
                    if ((((i + 3) < _html.length()) && _html.charAt(i + 1) == '!' && _html.charAt(i + 2) == '-') && _html.charAt(i + 3) == '-') {
                        comment = true;
                        i += 3;
                        continue;
                    }
                    ch = _html.charAt(i);
                    j = 1;
                }
                else {
                    if (comment && _html.charAt(i) == '-') {
                        if (((i + 2) < _html.length()) && _html.charAt(i + 1) == '-' && _html.charAt(i + 2) == '>') {
                            comment = false;
                            i += 2;
                            continue;
                        }
                    }
                    com.pullenti.unisharp.Outargwrapper<Character> wrapch28 = new com.pullenti.unisharp.Outargwrapper<Character>();
                    com.pullenti.unisharp.Outargwrapper<Boolean> wrapnbr29 = new com.pullenti.unisharp.Outargwrapper<Boolean>();
                    int inoutres30 = parseChar(_html, i, wrapch28, wrapnbr29);
                    ch = (wrapch28.value != null ? wrapch28.value : 0);
                    nbr = (wrapnbr29.value != null ? wrapnbr29.value : false);
                    if ((((j = inoutres30))) < 1) 
                        break;
                }
                if (com.pullenti.unisharp.Utils.isWhitespace(ch)) 
                    ch = ' ';
                if (ch == ' ' && !whiteSpacePreserve) {
                    boolean prevSp = (strTmp == null ? true : strTmp.charAt(strTmp.length() - 1) == ' ');
                    if (!prevSp || nbr) {
                        if (strTmp == null) 
                            strTmp = new StringBuilder();
                        strTmp.append(ch);
                    }
                    if (nbr) 
                        lastNbsp++;
                }
                else {
                    lastNbsp = 0;
                    if (strTmp == null) 
                        strTmp = new StringBuilder();
                    if (nbr && whiteSpacePreserve && ch == ' ') 
                        ch = (char)0xA0;
                    strTmp.append(ch);
                }
                if (whiteSpacePreserve) 
                    whitespacePreserve = true;
                i += (j - 1);
            }
            if (lastNbsp == 0 && !whiteSpacePreserve && strTmp != null) {
                for (int jj = strTmp.length() - 1; jj > 0; jj--) {
                    if (strTmp.charAt(jj) != ' ') 
                        break;
                    else 
                        strTmp.setLength(strTmp.length() - 1);
                }
            }
            if (strTmp != null) 
                pureText = strTmp.toString();
            indexTo = i - 1;
            return true;
        }
        if ((indFrom + 2) >= _html.length()) 
            return false;
        ch = _html.charAt(indFrom + 1);
        if (Character.isLetter(ch)) {
            if (indFrom > 0 && com.pullenti.unisharp.Utils.isWhitespace(_html.charAt(indFrom - 1))) 
                whitespaceBefore = true;
            tagName = readLatinWord(_html, indFrom + 1);
            if (tagName == null) {
                indexTo = indFrom + 1;
                return true;
            }
            if (com.pullenti.unisharp.Utils.stringsEq(tagName, "BR")) {
            }
            tagType = TagTypes.OPEN;
            StringBuilder strTmp = null;
            for (i = indFrom + 1 + tagName.length(); i < _html.length(); i++) {
                ch = _html.charAt(i);
                if (com.pullenti.unisharp.Utils.isWhitespace(ch)) 
                    continue;
                if (ch == '>') {
                    i++;
                    break;
                }
                if (ch == '/') {
                    if ((i + 1) >= _html.length()) 
                        return false;
                    if (_html.charAt(i + 1) == '>') 
                        i++;
                    tagType = TagTypes.OPENCLOSE;
                    i++;
                    break;
                }
                String attrName = readLatinWord(_html, i);
                if (attrName == null) 
                    continue;
                i += attrName.length();
                if ((i + 2) >= _html.length() || _html.charAt(i) != '=') {
                    i--;
                    continue;
                }
                i++;
                if (strTmp != null) 
                    strTmp.setLength(0);
                char bracket = (char)0;
                if (_html.charAt(i) == '\'' || _html.charAt(i) == '"') {
                    bracket = _html.charAt(i);
                    i++;
                }
                for (; i < _html.length(); i++) {
                    ch = _html.charAt(i);
                    if (bracket != ((char)0)) {
                        if (ch == bracket) {
                            i++;
                            break;
                        }
                    }
                    else if (ch == '>') 
                        break;
                    else if (com.pullenti.unisharp.Utils.isWhitespace(ch)) 
                        break;
                    else if (ch == '/' && ((i + 1) < _html.length()) && _html.charAt(i + 1) == '>') {
                    }
                    boolean nbr;
                    com.pullenti.unisharp.Outargwrapper<Character> wrapch31 = new com.pullenti.unisharp.Outargwrapper<Character>();
                    com.pullenti.unisharp.Outargwrapper<Boolean> wrapnbr32 = new com.pullenti.unisharp.Outargwrapper<Boolean>();
                    int inoutres33 = parseChar(_html, i, wrapch31, wrapnbr32);
                    ch = (wrapch31.value != null ? wrapch31.value : 0);
                    nbr = (wrapnbr32.value != null ? wrapnbr32.value : false);
                    if ((((j = inoutres33))) < 1) {
                        ch = _html.charAt(i);
                        j = 1;
                    }
                    if (strTmp == null) 
                        strTmp = new StringBuilder();
                    strTmp.append(ch);
                    i += (j - 1);
                }
                i--;
                if (!attributes.containsKey(attrName) && strTmp != null && strTmp.length() > 0) 
                    attributes.put(attrName, strTmp.toString());
            }
            indexTo = i - 1;
            return true;
        }
        if (_html.charAt(indFrom + 1) == '/') {
            i = indFrom + 2;
            tagName = readLatinWord(_html, i);
            if (tagName != null) {
                i += tagName.length();
                if ((i < _html.length()) && _html.charAt(i) == '>') {
                    i++;
                    tagType = TagTypes.CLOSE;
                }
            }
            indexTo = i - 1;
            return true;
        }
        if ((((indFrom + 5) < _html.length()) && _html.charAt(indFrom + 1) == '!' && _html.charAt(indFrom + 2) == '-') && _html.charAt(indFrom + 3) == '-') {
            for (i = indFrom + 4; i < (_html.length() - 3); i++) {
                if (_html.charAt(i) == '-' && _html.charAt(i + 1) == '-' && _html.charAt(i + 2) == '>') {
                    indexTo = i + 2;
                    return true;
                }
            }
            return false;
        }
        for (i = indFrom; i < _html.length(); i++) {
            if (_html.charAt(i) == '>') {
                i++;
                break;
            }
        }
        indexTo = i - 1;
        return true;
    }

    public static String decodeString(String txt) {
        if (com.pullenti.unisharp.Utils.isNullOrEmpty(txt) || (txt.indexOf('&') < 0)) 
            return txt;
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < txt.length(); i++) {
            char ch;
            boolean nbsp;
            com.pullenti.unisharp.Outargwrapper<Character> wrapch34 = new com.pullenti.unisharp.Outargwrapper<Character>();
            com.pullenti.unisharp.Outargwrapper<Boolean> wrapnbsp35 = new com.pullenti.unisharp.Outargwrapper<Boolean>();
            int j = parseChar(txt, i, wrapch34, wrapnbsp35);
            ch = (wrapch34.value != null ? wrapch34.value : 0);
            nbsp = (wrapnbsp35.value != null ? wrapnbsp35.value : false);
            if (j < 0) 
                break;
            res.append(ch);
            i += (j - 1);
        }
        return res.toString();
    }

    private static int parseChar(String txt, int ind, com.pullenti.unisharp.Outargwrapper<Character> ch, com.pullenti.unisharp.Outargwrapper<Boolean> nbsp) {
        ch.value = (char)0;
        nbsp.value = false;
        if (ind >= txt.length()) 
            return -1;
        if (txt.charAt(ind) != '&') {
            ch.value = txt.charAt(ind);
            return 1;
        }
        StringBuilder strTmp = new StringBuilder();
        int i;
        for (i = ind + 1; i < txt.length(); i++) {
            if (txt.charAt(i) == ';') 
                break;
            else {
                strTmp.append(txt.charAt(i));
                if (strTmp.length() > 7) 
                    break;
            }
        }
        if (i >= txt.length() || txt.charAt(i) != ';') {
            if (strTmp.toString().startsWith("nbsp")) {
                ch.value = ' ';
                nbsp.value = true;
                return 5;
            }
            ch.value = '&';
            return 1;
        }
        int ret = (i + 1) - ind;
        if (strTmp.length() == 0) 
            return ret;
        String s = strTmp.toString();
        if (m_SpecChars.containsKey(s)) {
            ch.value = m_SpecChars.get(s);
            if (com.pullenti.unisharp.Utils.stringsEq(s, "nbsp")) 
                nbsp.value = true;
            return ret;
        }
        if (s.charAt(0) != '#' || (strTmp.length() < 2)) {
            ch.value = '&';
            return ret;
        }
        if (Character.isDigit(s.charAt(1))) {
            try {
                ch.value = (char)com.pullenti.unisharp.Utils.parseInteger(s.substring(1), 0, null);
                nbsp.value = com.pullenti.unisharp.Utils.isWhitespace(ch.value);
            } catch (Exception ex36) {
            }
            return ret;
        }
        if (s.charAt(1) == 'x' || s.charAt(1) == 'X') {
            try {
                int code = 0;
                s = s.toUpperCase();
                for (int ii = 2; ii < s.length(); ii++) {
                    if (Character.isDigit(s.charAt(ii))) 
                        code = (code << 4) + ((((int)s.charAt(ii)) - ((int)'0')));
                    else if (s.charAt(ii) >= 'A' && s.charAt(ii) <= 'F') 
                        code = (code << 4) + (((((int)s.charAt(ii)) - ((int)'A')) + 10));
                }
                ch.value = (char)code;
                nbsp.value = com.pullenti.unisharp.Utils.isWhitespace(ch.value);
            } catch (Exception ex37) {
            }
            return ret;
        }
        ch.value = s.charAt(1);
        return ret;
    }

    private static String readLatinWord(String str, int ind) {
        if ((ind + 1) >= str.length()) 
            return null;
        int i;
        for (i = ind; i < str.length(); i++) {
            if (!Character.isLetter(str.charAt(i)) && str.charAt(i) != ':' && str.charAt(i) != '_') {
                if (i == 0) 
                    break;
                if (!Character.isDigit(str.charAt(i)) && str.charAt(i) != '.' && str.charAt(i) != '-') 
                    break;
            }
            else {
                int cod = (int)str.charAt(i);
                if (cod > 0x80) 
                    break;
            }
        }
        if (i <= ind) 
            return null;
        return str.substring(ind, ind + i - ind).toUpperCase();
    }

    private static boolean isEndTag(String _html, int pos, String _tagName) {
        if ((pos + 3) >= _html.length() || _tagName == null) 
            return false;
        if (_html.charAt(pos) != '<' && _html.charAt(pos + 1) != '/') 
            return false;
        if (com.pullenti.unisharp.Utils.stringsNe(readLatinWord(_html, pos + 2), _tagName)) 
            return false;
        return true;
    }

    private static java.util.HashMap<String, Character> m_SpecChars;


    public static class TagTypes implements Comparable<TagTypes> {
    
        public static final TagTypes UNDEFINED; // 0
    
        public static final TagTypes OPEN; // 1
    
        public static final TagTypes CLOSE; // 2
    
        public static final TagTypes OPENCLOSE; // 3
    
    
        public int value() { return m_val; }
        private int m_val;
        private String m_str;
        private TagTypes(int val, String str) { m_val = val; m_str = str; }
        @Override
        public String toString() {
            if(m_str != null) return m_str;
            return ((Integer)m_val).toString();
        }
        @Override
        public int hashCode() {
            return (int)m_val;
        }
        @Override
        public int compareTo(TagTypes v) {
            if(m_val < v.m_val) return -1;
            if(m_val > v.m_val) return 1;
            return 0;
        }
        private static java.util.HashMap<Integer, TagTypes> mapIntToEnum; 
        private static java.util.HashMap<String, TagTypes> mapStringToEnum; 
        private static TagTypes[] m_Values; 
        private static java.util.Collection<Integer> m_Keys; 
        public static TagTypes of(int val) {
            if (mapIntToEnum.containsKey(val)) return mapIntToEnum.get(val);
            TagTypes item = new TagTypes(val, ((Integer)val).toString());
            mapIntToEnum.put(val, item);
            mapStringToEnum.put(item.m_str.toUpperCase(), item);
            return item; 
        }
        public static TagTypes of(String str) {
            str = str.toUpperCase(); 
            if (mapStringToEnum.containsKey(str)) return mapStringToEnum.get(str);
            return null; 
        }
        public static boolean isDefined(Object val) {
            if(val instanceof Integer) return m_Keys.contains((Integer)val); 
            return false; 
        }
        public static TagTypes[] getValues() {
            return m_Values; 
        }
        static {
            mapIntToEnum = new java.util.HashMap<Integer, TagTypes>();
            mapStringToEnum = new java.util.HashMap<String, TagTypes>();
            UNDEFINED = new TagTypes(0, "UNDEFINED");
            mapIntToEnum.put(UNDEFINED.value(), UNDEFINED);
            mapStringToEnum.put(UNDEFINED.m_str.toUpperCase(), UNDEFINED);
            OPEN = new TagTypes(1, "OPEN");
            mapIntToEnum.put(OPEN.value(), OPEN);
            mapStringToEnum.put(OPEN.m_str.toUpperCase(), OPEN);
            CLOSE = new TagTypes(2, "CLOSE");
            mapIntToEnum.put(CLOSE.value(), CLOSE);
            mapStringToEnum.put(CLOSE.m_str.toUpperCase(), CLOSE);
            OPENCLOSE = new TagTypes(3, "OPENCLOSE");
            mapIntToEnum.put(OPENCLOSE.value(), OPENCLOSE);
            mapStringToEnum.put(OPENCLOSE.m_str.toUpperCase(), OPENCLOSE);
            java.util.Collection<TagTypes> col = mapIntToEnum.values();
            m_Values = new TagTypes[col.size()];
            col.toArray(m_Values);
            m_Keys = new java.util.ArrayList<Integer>(mapIntToEnum.keySet());
        }
    }

    public HtmlParserNode() {
    }
    public static HtmlParserNode _globalInstance;
    
    static {
        try { _globalInstance = new HtmlParserNode(); } 
        catch(Exception e) { }
        m_SpecChars = new java.util.HashMap<String, Character>();
        m_SpecChars.put("nbsp", ' ');
        m_SpecChars.put("lt", '<');
        m_SpecChars.put("gt", '>');
        m_SpecChars.put("quot", '"');
        m_SpecChars.put("apos", '\'');
        String data = "iexcl=161;cent=162;pound=163;curren=164;yen=165;brvbar=166;sect=167;uml=168;copy=169;ordf=170;laquo=171;not=172;shy=173;reg=174;macr=175;deg=176;plusmn=177;sup2=178;sup3=179;acute=180;micro=181;para=182;middot=183;cedil=184;sup1=185;ordm=186;raquo=187;frac14=188;frac12=189;frac34=190;iquest=191;Agrave=192;Aacute=193;Acirc=194;Atilde=195;Auml=196;Aring=197;AElig=198;Ccedil=199;Egrave=200;Eacute=201;Ecirc=202;Euml=203;Igrave=204;Iacute=205;Icirc=206;Iuml=207;ETH=208;Ntilde=209;Ograve=210;Oacute=211;Ocirc=212;Otilde=213;Ouml=214;times=215;Oslash=216;Ugrave=217;Uacute=218;Ucirc=219;Uuml=220;Yacute=221;THORN=222;szlig=223;agrave=224;aacute=225;acirc=226;atilde=227;auml=228;aring=229;aelig=230;ccedil=231;egrave=232;eacute=233;ecirc=234;euml=235;igrave=236;iacute=237;icirc=238;iuml=239;eth=240;ntilde=241;ograve=242;oacute=243;ocirc=244;otilde=245;ouml=246;divide=247;oslash=248;ugrave=249;uacute=250;ucirc=251;uuml=252;yacute=253;thorn=254;yuml=255;Alpha=913;Beta=914;Gamma=915;Delta=916;Epsilon=917;Zeta=918;Eta=919;Theta=920;Iota=921;Kappa=922;Lambda=923;Mu=924;Nu=925;Xi=926;Omicron=927;Pi=928;Rho=929;Sigma=931;Tau=932;Upsilon=933;Phi=934;Chi=935;Psi=936;Omega=937;alpha=945;beta=946;gamma=947;delta=948;epsilon=949;zeta=950;eta=951;theta=952;iota=953;kappa=954;lambda=955;mu=956;nu=957;xi=958;omicron=959;pi=960;rho=961;sigmaf=962;sigma=963;tau=964;upsilon=965;phi=966;chi=967;psi=968;omega=969;thetasym=977;upsih=978;piv=982;bull=8226;hellip=8230;prime=8242;Prime=8243;oline=8254;frasl=8260;weierp=8472;image=8465;real=8476;trade=8482;alefsym=8501;larr=8592;uarr=8593;rarr=8594;darr=8595;harr=8596;crarr=8629;lArr=8656;uArr=8657;rArr=8658;dArr=8659;hArr=8660;forall=8704;part=8706;exist=8707;empty=8709;nabla=8711;isin=8712;notin=8713;ni=8715;prod=8719;sum=8721;minus=8722;lowast=8727;radic=8730;prop=8733;infin=8734;ang=8736;and=8743;or=8744;cap=8745;cup=8746;int=8747;there4=8756;sim=8764;cong=8773;asymp=8776;ne=8800;equiv=8801;le=8804;ge=8805;sub=8834;sup=8835;nsub=8836;sube=8838;supe=8839;oplus=8853;otimes=8855;perp=8869;sdot=8901;lceil=8968;rceil=8969;lfloor=8970;rfloor=8971;lang=9001;rang=9002;loz=9674;spades=9824;clubs=9827;hearts=9829;diams=9830;amp=38;OElig=338;oelig=339;Scaron=352;scaron=353;Yuml=376;circ=710;tilde=732;ensp=8194;emsp=8195;thinsp=8201;zwnj=8204;zwj=8205;lrm=8206;rlm=8207;ndash=8211;mdash=8212;lsquo=8216;rsquo=8217;sbquo=8218;ldquo=8220;rdquo=8221;bdquo=8222;dagger=8224;Dagger=8225;permil=8240;lsaquo=8249;rsaquo=8250;euro=8364";
        for (String s : com.pullenti.unisharp.Utils.split(data, String.valueOf(';'), false)) {
            int i = s.indexOf('=');
            String key = s.substring(0, 0 + i);
            int cod = com.pullenti.unisharp.Utils.parseInteger(s.substring(i + 1), 0, null);
            m_SpecChars.put(key, (char)cod);
        }
    }
}
