/*
 * SDK Pullenti Lingvo, 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.ner.address;

/**
 * Сущность: улица, проспект, площадь, шоссе и т.п. Выделяется анализатором AddressAnalyzer.
 * 
 */
public class StreetReferent extends com.pullenti.ner.Referent {

    public StreetReferent() {
        super(OBJ_TYPENAME);
        setInstanceOf(com.pullenti.ner.address.internal.MetaStreet.globalMeta);
    }

    /**
     * Имя типа сущности TypeName ("STREET")
     */
    public static final String OBJ_TYPENAME = "STREET";

    /**
     * Имя атрибута - тип (улица, переулок, площадь...)
     */
    public static final String ATTR_TYPE = "TYP";

    /**
     * Класс объекта (StreetKind)
     */
    public static final String ATTR_KIND = "KIND";

    /**
     * Имя атрибута - наименование (м.б. несколько вариантов)
     */
    public static final String ATTR_NAME = "NAME";

    /**
     * Имя атрибута - номер (м.б. несколько вариантов)
     */
    public static final String ATTR_NUMBER = "NUMBER";

    /**
     * Имя атрибута - вышележащая улица (например, улица в микрорайоне)
     */
    public static final String ATTR_HIGHER = "HIGHER";

    /**
     * Имя атрибута - географический объект
     */
    public static final String ATTR_GEO = "GEO";

    /**
     * Имя атрибута - дополнительная ссылка (для территории организации - на саму организацию)
     */
    public static final String ATTR_REF = "REF";

    /**
     * Имя атрибута - дополнительная информация
     */
    public static final String ATTR_MISC = "MISC";

    /**
     * Имя атрибута - числовая дополнительная информация (типа - очередь для ГСК и т.п.)
     */
    public static final String ATTR_PARAM = "PARAM";

    /**
     * Имя атрибута - код ФИАС (определяется анализатором FiasAnalyzer)
     */
    public static final String ATTR_FIAS = "FIAS";

    public static final String ATTR_BTI = "BTI";

    public static final String ATTR_OKM = "OKM";

    public java.util.ArrayList<String> getTyps() {
        if (m_Typs != null) {
            int cou = 0;
            for (com.pullenti.ner.Slot s : getSlots()) {
                if (com.pullenti.unisharp.Utils.stringsEq(s.getTypeName(), ATTR_TYPE)) 
                    cou++;
            }
            if (cou == m_Typs.size()) 
                return m_Typs;
        }
        java.util.ArrayList<String> res = new java.util.ArrayList<String>();
        for (com.pullenti.ner.Slot s : getSlots()) {
            if (com.pullenti.unisharp.Utils.stringsEq(s.getTypeName(), ATTR_TYPE)) 
                res.add(s.getValue().toString());
        }
        m_Typs = res;
        return res;
    }


    private java.util.ArrayList<String> m_Typs = null;

    public java.util.ArrayList<String> getNames() {
        java.util.ArrayList<String> res = new java.util.ArrayList<String>();
        for (com.pullenti.ner.Slot s : getSlots()) {
            if (com.pullenti.unisharp.Utils.stringsEq(s.getTypeName(), ATTR_NAME)) 
                res.add(s.getValue().toString());
        }
        return res;
    }


    public String getNumbers() {
        java.util.ArrayList<String> nums = this.getStringValues(ATTR_NUMBER);
        if (nums == null || nums.size() == 0) 
            return null;
        if (nums.size() == 1) 
            return nums.get(0);
        java.util.Collections.sort(nums);
        StringBuilder tmp = new StringBuilder();
        for (String n : nums) {
            if (tmp.length() > 0) 
                tmp.append("+");
            tmp.append(n);
        }
        return tmp.toString();
    }

    public String setNumbers(String value) {
        if (value == null) 
            return value;
        int i = value.indexOf('+');
        if (i > 0) {
            setNumbers(value.substring(0, 0 + i));
            setNumbers(value.substring(i + 1));
        }
        else 
            this.addSlot(ATTR_NUMBER, value, false, 0);
        return value;
    }


    private StreetReferent m_Higher;

    public StreetReferent getHigher() {
        return m_Higher;
    }

    public StreetReferent setHigher(StreetReferent value) {
        if (value == this) 
            return value;
        if (value != null) {
            StreetReferent d = value;
            java.util.ArrayList<StreetReferent> li = new java.util.ArrayList<StreetReferent>();
            for (; d != null; d = d.getHigher()) {
                if (d == this) 
                    return value;
                else if (com.pullenti.unisharp.Utils.stringsEq(d.toString(), this.toString())) 
                    return value;
                if (li.contains(d)) 
                    return value;
                li.add(d);
            }
        }
        this.addSlot(ATTR_HIGHER, null, true, 0);
        if (value != null) 
            this.addSlot(ATTR_HIGHER, value, true, 0);
        m_Higher = value;
        return value;
    }


    public java.util.ArrayList<com.pullenti.ner.geo.GeoReferent> getGeos() {
        java.util.ArrayList<com.pullenti.ner.geo.GeoReferent> res = new java.util.ArrayList<com.pullenti.ner.geo.GeoReferent>();
        for (com.pullenti.ner.Slot a : getSlots()) {
            if (com.pullenti.unisharp.Utils.stringsEq(a.getTypeName(), ATTR_GEO) && (a.getValue() instanceof com.pullenti.ner.geo.GeoReferent)) 
                res.add((com.pullenti.ner.geo.GeoReferent)com.pullenti.unisharp.Utils.cast(a.getValue(), com.pullenti.ner.geo.GeoReferent.class));
        }
        return res;
    }


    public com.pullenti.ner.geo.GeoReferent getCity() {
        for (com.pullenti.ner.geo.GeoReferent g : getGeos()) {
            if (g.isCity()) 
                return g;
            else if (g.getHigher() != null && g.getHigher().isCity()) 
                return g.getHigher();
        }
        return null;
    }


    @Override
    public com.pullenti.ner.Referent getParentReferent() {
        StreetReferent hi = getHigher();
        if (hi != null) 
            return hi;
        return (com.pullenti.ner.geo.GeoReferent)com.pullenti.unisharp.Utils.cast(this.getSlotValue(ATTR_GEO), com.pullenti.ner.geo.GeoReferent.class);
    }


    @Override
    public String toStringEx(boolean shortVariant, com.pullenti.morph.MorphLang lang, int lev) {
        StringBuilder tmp = new StringBuilder();
        String nam = this.getStringValue(ATTR_NAME);
        String misc = null;
        java.util.ArrayList<String> _typs = getTyps();
        StreetKind ki = getKind();
        if (_typs.size() > 0) {
            for (int i = 0; i < _typs.size(); i++) {
                if (nam != null && (nam.indexOf(_typs.get(i).toUpperCase()) >= 0) && nam.length() > _typs.get(i).length()) 
                    continue;
                if (tmp.length() > 0) 
                    tmp.append('/');
                tmp.append(_typs.get(i));
            }
        }
        else 
            tmp.append((lang != null && lang.isUa() ? "вулиця" : "улица"));
        String num = getNumbers();
        if ((num != null && !(num.indexOf("км") >= 0) && ki != StreetKind.ORG) && ki != StreetKind.AREA) {
            tmp.append(" ").append(num);
            num = null;
        }
        java.util.ArrayList<String> miscs = this.getStringValues(ATTR_MISC);
        for (String m : miscs) {
            if (Character.isUpperCase(m.charAt(0)) && (m.length() < 4)) {
                tmp.append(" ").append(m);
                misc = m;
                break;
            }
        }
        if (misc == null && miscs.size() > 0) {
            if (nam != null && (nam.indexOf(miscs.get(0).toUpperCase()) >= 0)) {
            }
            else 
                tmp.append(" ").append(com.pullenti.ner.core.MiscHelper.convertFirstCharUpperAndOtherLower(miscs.get(0)));
            misc = miscs.get(0);
        }
        if (nam != null) 
            tmp.append(" ").append(com.pullenti.ner.core.MiscHelper.convertFirstCharUpperAndOtherLower(nam));
        if (num != null) 
            tmp.append(" ").append(num);
        String par = this.getStringValue(ATTR_PARAM);
        if (par != null) 
            tmp.append(", ").append(par);
        if (!shortVariant && getCity() != null) 
            tmp.append("; ").append(this.getCity().toStringEx(true, lang, lev + 1));
        return tmp.toString();
    }

    public StreetKind getKind() {
        String str = this.getStringValue(ATTR_KIND);
        if (str == null) 
            return StreetKind.UNDEFINED;
        try {
            return (StreetKind)StreetKind.of(str);
        } catch (Exception ex463) {
        }
        return StreetKind.UNDEFINED;
    }

    public StreetKind setKind(StreetKind value) {
        if (value == StreetKind.UNDEFINED) 
            this.addSlot(ATTR_KIND, null, true, 0);
        else 
            this.addSlot(ATTR_KIND, value.toString().toUpperCase(), true, 0);
        return value;
    }


    public void addTyp(String typ) {
        this.addSlot(ATTR_TYPE, typ, false, 0);
        if (getKind() == StreetKind.UNDEFINED) {
            if (com.pullenti.unisharp.Utils.stringsEq(typ, "железная дорога")) 
                setKind(StreetKind.RAILWAY);
            else if ((typ.indexOf("дорога") >= 0) || com.pullenti.unisharp.Utils.stringsEq(typ, "шоссе") || (typ.indexOf("магистраль") >= 0)) 
                setKind(StreetKind.ROAD);
            else if ((typ.indexOf("метро") >= 0)) 
                setKind(StreetKind.METRO);
            else if (com.pullenti.unisharp.Utils.stringsEq(typ, "территория")) 
                setKind(StreetKind.AREA);
            else if (com.pullenti.ner.address.internal.StreetItemToken._isRegion(typ)) 
                setKind(StreetKind.AREA);
            else if (com.pullenti.ner.address.internal.StreetItemToken._isSpec(typ)) 
                setKind(StreetKind.SPEC);
        }
    }

    public void addName(com.pullenti.ner.address.internal.StreetItemToken sit) {
        this.addSlot(ATTR_NAME, (sit.value != null ? sit.value : com.pullenti.ner.core.MiscHelper.getTextValueOfMetaToken(sit, com.pullenti.ner.core.GetTextAttr.NO)), false, 0);
        if (sit.altValue != null) 
            this.addSlot(ATTR_NAME, sit.altValue, false, 0);
        if (sit.altValue2 != null) 
            this.addSlot(ATTR_NAME, sit.altValue2, false, 0);
    }

    public void addMisc(String v) {
        if (v != null) 
            this.addSlot(ATTR_MISC, v, false, 0);
    }

    @Override
    public boolean canBeEquals(com.pullenti.ner.Referent obj, com.pullenti.ner.core.ReferentsEqualType typ) {
        return this._canBeEquals(obj, typ, false, 0);
    }

    private boolean _canBeEquals(com.pullenti.ner.Referent obj, com.pullenti.ner.core.ReferentsEqualType typ, boolean ignoreGeo, int level) {
        if (level > 5) 
            return false;
        level++;
        boolean ret = this._canBeEquals2(obj, typ, ignoreGeo, level);
        level--;
        return ret;
    }

    private boolean _canBeEquals2(com.pullenti.ner.Referent obj, com.pullenti.ner.core.ReferentsEqualType typ, boolean ignoreGeo, int level) {
        StreetReferent stri = (StreetReferent)com.pullenti.unisharp.Utils.cast(obj, StreetReferent.class);
        if (stri == null) 
            return false;
        if (getKind() != stri.getKind()) 
            return false;
        java.util.ArrayList<String> typs1 = getTyps();
        java.util.ArrayList<String> typs2 = stri.getTyps();
        boolean ok = false;
        if (typs1.size() > 0 && typs2.size() > 0) {
            for (String t : typs1) {
                if (typs2.contains(t)) {
                    ok = true;
                    break;
                }
            }
            if (!ok) 
                return false;
        }
        String num = getNumbers();
        String num1 = stri.getNumbers();
        if (num != null || num1 != null) {
            if (num == null || num1 == null) 
                return false;
            if (com.pullenti.unisharp.Utils.stringsNe(num, num1)) 
                return false;
        }
        String par1 = this.getStringValue(ATTR_PARAM);
        String par2 = stri.getStringValue(ATTR_PARAM);
        if (par1 != null || par2 != null) {
            if (com.pullenti.unisharp.Utils.stringsNe(par1, par2)) 
                return false;
        }
        java.util.ArrayList<String> names1 = getNames();
        java.util.ArrayList<String> names2 = stri.getNames();
        if (names1.size() > 0 || names2.size() > 0) {
            ok = false;
            for (String n : names1) {
                if (names2.contains(n)) {
                    ok = true;
                    break;
                }
            }
            if (!ok) 
                return false;
        }
        if (getHigher() != null && stri.getHigher() != null) {
            if (!getHigher()._canBeEquals(stri.getHigher(), typ, ignoreGeo, level)) 
                return false;
        }
        if (ignoreGeo) 
            return true;
        java.util.ArrayList<com.pullenti.ner.geo.GeoReferent> geos1 = getGeos();
        java.util.ArrayList<com.pullenti.ner.geo.GeoReferent> geos2 = stri.getGeos();
        if (geos1.size() > 0 && geos2.size() > 0) {
            ok = false;
            for (com.pullenti.ner.geo.GeoReferent g1 : geos1) {
                for (com.pullenti.ner.geo.GeoReferent g2 : geos2) {
                    if (g1.canBeEquals(g2, typ)) {
                        ok = true;
                        break;
                    }
                }
            }
            if (!ok) {
                if (getCity() != null && stri.getCity() != null) 
                    ok = this.getCity().canBeEquals(stri.getCity(), typ);
            }
            if (!ok) 
                return false;
        }
        return true;
    }

    @Override
    public com.pullenti.ner.Slot addSlot(String attrName, Object attrValue, boolean clearOldValue, int statCount) {
        if (com.pullenti.unisharp.Utils.stringsEq(attrName, ATTR_NAME) && (attrValue instanceof String)) {
            String str = (String)com.pullenti.unisharp.Utils.cast(attrValue, String.class);
            if (str.indexOf('.') > 0) {
                for (int i = 1; i < (str.length() - 1); i++) {
                    if (str.charAt(i) == '.' && str.charAt(i + 1) != ' ') 
                        str = str.substring(0, 0 + i + 1) + " " + str.substring(i + 1);
                }
            }
            attrValue = str;
        }
        return super.addSlot(attrName, attrValue, clearOldValue, statCount);
    }

    @Override
    public void mergeSlots(com.pullenti.ner.Referent obj, boolean mergeStatistic) {
        super.mergeSlots(obj, mergeStatistic);
    }

    @Override
    public boolean canBeGeneralFor(com.pullenti.ner.Referent obj) {
        if (!this._canBeEquals(obj, com.pullenti.ner.core.ReferentsEqualType.WITHINONETEXT, true, 0)) 
            return false;
        java.util.ArrayList<com.pullenti.ner.geo.GeoReferent> geos1 = getGeos();
        java.util.ArrayList<com.pullenti.ner.geo.GeoReferent> geos2 = ((StreetReferent)com.pullenti.unisharp.Utils.cast(obj, StreetReferent.class)).getGeos();
        if (geos2.size() == 0 || geos1.size() > 0) 
            return false;
        return true;
    }

    @Override
    public com.pullenti.ner.core.IntOntologyItem createOntologyItem() {
        com.pullenti.ner.core.IntOntologyItem oi = new com.pullenti.ner.core.IntOntologyItem(this);
        java.util.ArrayList<String> _names = getNames();
        for (String n : _names) {
            oi.termins.add(new com.pullenti.ner.core.Termin(n, null, false));
        }
        return oi;
    }

    public void correct() {
        java.util.ArrayList<String> _names = getNames();
        for (int i = _names.size() - 1; i >= 0; i--) {
            String ss = _names.get(i);
            int jj = ss.indexOf(' ');
            if (jj < 0) 
                continue;
            if (ss.lastIndexOf(' ') != jj) 
                continue;
            String[] pp = com.pullenti.unisharp.Utils.split(ss, String.valueOf(' '), false);
            if (pp.length == 2) {
                String ss2 = (pp[1] + " " + pp[0]);
                if (!_names.contains(ss2)) 
                    this.addSlot(ATTR_NAME, ss2, false, 0);
            }
        }
    }

    public static StreetReferent _new1583(StreetKind _arg1) {
        StreetReferent res = new StreetReferent();
        res.setKind(_arg1);
        return res;
    }
}
