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

/**
 * Поддержка сложной нумерации разделов, пунктов, формул и т.п. 
 * (составная, возможны римские цифры, буквы)
 */
public class ComplexNumToken extends com.pullenti.ner.MetaToken {

    public ComplexNumToken(com.pullenti.ner.Token b, com.pullenti.ner.Token e) {
        super(b, e, null);
    }

    /**
     * Элементы составного номера
     */
    public java.util.ArrayList<SingleNumToken> nums = new java.util.ArrayList<SingleNumToken>();

    public String getNormal() {
        if (nums.size() == 0) 
            return null;
        String res = nums.get(0).getNormal();
        for (int i = 1; i < nums.size(); i++) {
            res = (res + "." + nums.get(i).getNormal());
        }
        return res;
    }


    public String getSignature() {
        StringBuilder res = new StringBuilder();
        if (getPrefix() != null) 
            res.append(this.getPrefix());
        for (SingleNumToken n : nums) {
            if (n.vals.size() == 0) 
                continue;
            if (n.vals.get(0).typ == SingleNumValueType.DIGIT) 
                res.append('n');
            else if (n.vals.get(0).typ == SingleNumValueType.ROMAN) 
                res.append('r');
            else if (n.vals.get(0).typ == SingleNumValueType.LETTER) 
                res.append('l');
            else 
                res.append('?');
        }
        if (getSuffix() != null) 
            res.append(this.getSuffix());
        return res.toString();
    }


    public String getPrefix() {
        return (nums.size() > 0 ? nums.get(0).prefix : null);
    }


    public String getSuffix() {
        return (nums.size() > 0 ? nums.get(nums.size() - 1).suffix : null);
    }


    public boolean isOne() {
        if (nums.size() == 0) 
            return false;
        return nums.get(nums.size() - 1).isOne();
    }


    @Override
    public String toString() {
        return this.toStringEx(false);
    }

    public String toStringEx(boolean ignoreSuffix) {
        if (nums.size() == 0) 
            return "";
        String res = nums.get(0).value;
        for (int i = 1; i < nums.size(); i++) {
            res = (res + ((nums.get(i).prefix != null ? nums.get(i).prefix : "")) + nums.get(i).value + (nums.get(i).suffix == null || nums.get(i).value.endsWith(nums.get(i).suffix) ? "" : nums.get(i).suffix));
        }
        if (ignoreSuffix && getSuffix() != null && res.endsWith(this.getSuffix())) 
            res = res.substring(0, 0 + res.length() - this.getSuffix().length());
        return res;
    }

    /**
     * Выделить сложный номер с указанного токена
     * @param t 
     * @param prev предыдущий номер (если есть)
     * @param force обязательно ли выделять
     * @param ignoreLastSuffix суффикс у последнего составного числа игнорировать
     * @return номер или null
     */
    public static ComplexNumToken tryParse(com.pullenti.ner.Token t, ComplexNumToken prev, boolean force, boolean ignoreLastSuffix) {
        if (t == null) 
            return null;
        if (t instanceof com.pullenti.ner.ReferentToken) {
            com.pullenti.ner.Referent r = t.getReferent();
            if (r != null && com.pullenti.unisharp.Utils.stringsEq(r.getTypeName(), "BOOKLINKREF")) 
                t = ((com.pullenti.ner.ReferentToken)com.pullenti.unisharp.Utils.cast(t, com.pullenti.ner.ReferentToken.class)).getBeginToken();
        }
        SingleNumToken nt = SingleNumToken.tryParse(t, true, force);
        if (nt == null) 
            return null;
        ComplexNumToken res = new ComplexNumToken(t, nt.getEndToken());
        res.nums.add(nt);
        for (t = nt.getEndToken().getNext(); t != null; t = t.getNext()) {
            if (t.isWhitespaceBefore()) {
                if (t.getWhitespacesBeforeCount() > 2) 
                    break;
                if (force && t.isCharOf("<(")) {
                }
                else 
                    break;
            }
            nt = SingleNumToken.tryParse(t, false, force);
            if (nt == null) {
                if (((force && t.isHiphen() && !t.isNewlineBefore()) && !t.isNewlineAfter() && (t.getNext() instanceof com.pullenti.ner.NumberToken)) && res.nums.get(res.nums.size() - 1).suffix == null) {
                    nt = SingleNumToken.tryParse(t.getNext(), false, false);
                    if (nt != null) {
                        res.nums.get(res.nums.size() - 1).setEndToken(t);
                        res.nums.get(res.nums.size() - 1).suffix = "-";
                    }
                }
                if (nt == null) 
                    break;
            }
            if (nt.vals.get(0).typ == SingleNumValueType.LETTER) {
                if (res.nums.get(0).vals.get(0).typ == SingleNumValueType.LETTER) {
                    if (com.pullenti.unisharp.Utils.stringsEq(res.nums.get(0).suffix, ")")) 
                        break;
                    return null;
                }
                if (res.nums.get(res.nums.size() - 1).vals.get(0).typ == SingleNumValueType.LETTER) {
                    if (com.pullenti.unisharp.Utils.stringsEq(res.nums.get(res.nums.size() - 1).suffix, ")")) 
                        break;
                    return null;
                }
            }
            if (nt.suffix == null && com.pullenti.unisharp.Utils.stringsEq(res.getSuffix(), ")") && !nt.value.startsWith("<")) 
                break;
            if (t.getMorphClassInDictionary().isPreposition() && res.getSuffix() != null) {
                if (t.getNext() != null && t.getNext().isCharOf("<.]>)")) {
                }
                else 
                    break;
            }
            res.nums.add(nt);
            res.setEndToken((t = nt.getEndToken()));
        }
        if (res.nums.size() == 1) {
            if (com.pullenti.unisharp.Utils.stringsEq(res.getPrefix(), "<") && com.pullenti.unisharp.Utils.stringsEq(res.getSuffix(), ">")) 
                return null;
            if (!force && res.isNewlineBefore() && res.isNewlineAfter()) 
                return null;
        }
        if ((ignoreLastSuffix && res.getSuffix() != null && res.getSuffix().length() == 1) && res.getEndToken().isChar(res.getSuffix().charAt(0))) {
            res.setEndToken(res.getEndToken().getPrevious());
            SingleNumToken n1 = res.nums.get(res.nums.size() - 1);
            if (n1.value != null && n1.value.endsWith(n1.suffix)) 
                n1.value = n1.value.substring(0, 0 + n1.value.length() - 1);
            n1.suffix = null;
            n1.setEndToken(res.getEndToken());
        }
        return res;
    }

    public static void correctSeq(java.util.ArrayList<ComplexNumToken> seq) {
        if (seq.size() == 0) 
            return;
        seq.get(0).correct(null);
        for (int i = 1; i < seq.size(); i++) {
            seq.get(i).correct(seq.get(i - 1));
        }
        int lat = 0;
        int cyr = 0;
        for (ComplexNumToken s : seq) {
            for (SingleNumToken n : s.nums) {
                for (SingleNumValue v : n.vals) {
                    if (v.typ == SingleNumValueType.LETTER) {
                        if (((int)(v.letter)) < 0x80) 
                            lat++;
                        else 
                            cyr++;
                    }
                }
            }
        }
        if (lat > cyr || cyr > lat) {
            for (ComplexNumToken s : seq) {
                for (SingleNumToken n : s.nums) {
                    for (int i = n.vals.size() - 1; i >= 0; i--) {
                        if (n.vals.get(i).typ == SingleNumValueType.LETTER && n.vals.size() > 1) {
                            if (((int)(n.vals.get(i).letter)) < 0x80) {
                                if (cyr > lat) 
                                    n.vals.remove(i);
                            }
                            else if (lat > cyr) 
                                n.vals.remove(i);
                        }
                    }
                }
            }
        }
    }

    private void correct(ComplexNumToken prev) {
        if (prev != null && prev.nums.size() == nums.size()) 
            nums.get(nums.size() - 1).correct(prev.nums.get(prev.nums.size() - 1));
        else if (prev == null) 
            nums.get(nums.size() - 1).correct(null);
    }

    public boolean canBePsevdoSubseq(ComplexNumToken sub) {
        if (sub == null) 
            return false;
        if (com.pullenti.unisharp.Utils.stringsNe(getPrefix(), sub.getPrefix()) || com.pullenti.unisharp.Utils.stringsNe(getSuffix(), sub.getSuffix())) 
            return false;
        if ((nums.size() + 1) != sub.nums.size()) 
            return false;
        if (!sub.nums.get(sub.nums.size() - 1).isOne()) 
            return false;
        SingleNumComparer comp = new SingleNumComparer();
        for (int i = 0; i < nums.size(); i++) {
            comp.process(nums.get(i), sub.nums.get(i));
            if (comp.typ != ComplexNumCompareType.EQUALS) 
                return false;
        }
        return true;
    }
    public ComplexNumToken() {
        super();
    }
}
