/*
 * 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#.NET project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

const Utils = require("./../../unisharp/Utils");
const StringBuilder = require("./../../unisharp/StringBuilder");

const LanguageHelper = require("./../../morph/LanguageHelper");
const MetaToken = require("./../MetaToken");
const ComplexNumCompareType = require("./ComplexNumCompareType");
const SingleNumComparer = require("./SingleNumComparer");
const NumberSpellingType = require("./../NumberSpellingType");
const SingleNumValueType = require("./SingleNumValueType");
const TextToken = require("./../TextToken");
const NumberToken = require("./../NumberToken");
const SingleNumValue = require("./SingleNumValue");
const MiscHelper = require("./MiscHelper");
const NumberHelper = require("./NumberHelper");

/**
 * Элемент составного номера
 */
class SingleNumToken extends MetaToken {
    
    constructor(b, e) {
        super(b, e, null);
        this.vals = new Array();
        this.value = null;
        this.prefix = null;
        this.suffix = null;
    }
    
    toString() {
        let res = new StringBuilder();
        res.append(this.value).append(": ");
        for (let i = 0; i < this.vals.length; i++) {
            if (i > 0) 
                res.append("/");
            res.append(this.vals[i].toString());
        }
        return res.toString();
    }
    
    get normal() {
        if (this.vals.length === 0) 
            return "?";
        if (this.vals[0].typ === SingleNumValueType.LETTER) 
            return (this.vals[0].letter);
        return this.vals[0].val.toString();
    }
    
    _addNum(val, rom, upper = false) {
        let res = new SingleNumValue();
        res.val = val;
        if (rom) 
            res.typ = SingleNumValueType.ROMAN;
        if (rom && upper) 
            this.vals.splice(0, 0, res);
        else 
            this.vals.push(res);
    }
    
    _addChar(ch, up) {
        for (const v of this.vals) {
            if (ch === v.letter) 
                return;
        }
        let res = new SingleNumValue();
        res.typ = SingleNumValueType.LETTER;
        res.letter = ch.toLowerCase();
        res.upper = up;
        this.vals.push(res);
    }
    
    static tryParse(t, first, force = false) {
        if (t === null) 
            return null;
        if (t.isValue("I", null)) {
        }
        if (!first && t.isWhitespaceBefore) {
            if (!force && !t.isCharOf(".(<")) 
                return null;
        }
        let t0 = t;
        let res = null;
        if (t.isChar('(') && !t.isWhitespaceAfter) {
            res = SingleNumToken.tryParse(t.next, first, false);
            if (res !== null && res.endToken.isChar(')')) {
                res.beginToken = t;
                res.prefix = "(";
                return res;
            }
            else 
                return null;
        }
        if (t.isChar('<') && !t.isWhitespaceAfter) {
            res = SingleNumToken.tryParse(t.next, first, false);
            if (res !== null && res.endToken.isChar('>')) {
                res.beginToken = t;
                res.prefix = "<";
                if (!first) {
                    res.prefix = (res.suffix = null);
                    res.value = "<" + res.value;
                }
                if (!res.endToken.isWhitespaceAfter) {
                    t = res.endToken.next;
                    if (t !== null) {
                        if (t.isCharOf(".])\\")) {
                            res.endToken = t;
                            res.suffix = t.getSourceText();
                            res.value += res.suffix;
                        }
                    }
                }
            }
            return res;
        }
        let hasPref = false;
        if (first) {
            let tt = MiscHelper.checkNumberPrefix(t);
            if (tt !== null && !tt.isCharOf(".)")) {
                if (t.isNewlineBefore) {
                    hasPref = true;
                    t = tt;
                }
                else if (t.previous !== null && ((SingleNumToken._checkKeyword(t.previous) || t.previous.isNewlineBefore))) {
                    hasPref = true;
                    t = tt;
                }
            }
        }
        let nt = Utils.as(t, NumberToken);
        if (nt !== null && nt.intValue !== null && (nt.intValue < 3000)) {
            if (nt.typ === NumberSpellingType.WORDS && t === t0) {
                if (!first) 
                    return null;
                if (force) {
                }
                else if (!t.isNewlineBefore && SingleNumToken._checkKeyword(t.previous)) {
                }
                else if (t.next !== null && !t.isNewlineAfter && SingleNumToken._checkKeyword(t.next)) {
                }
                else 
                    return null;
            }
            if (t.next !== null) {
                if (t.next.isValue("ГОД", null) || t.next.isValue("ЛЕТ", null)) 
                    return null;
            }
            res = new SingleNumToken(t0, t);
            res._addNum(t.intValue, false, false);
        }
        else if ((t instanceof TextToken) && t.chars.isLetter && t.lengthChar === 1) {
            if (Utils.isNullOrEmpty(t.term)) 
                return null;
            if (t.next !== null && t.next.isCharOf(")")) {
            }
            else if (!first || force) {
            }
            else {
                if (t.previous !== null && t.previous.isCharOf("(<") && ((t.previous.isNewlineBefore || SingleNumToken._checkKeyword(t.previous.previous)))) {
                }
                else if (SingleNumToken._checkKeyword(t.previous)) {
                }
                else if (t.chars.isAllUpper && t.isCharOf("IXХ") && !t.isWhitespaceAfter) {
                }
                else if (t.isNewlineBefore && !t.isWhitespaceAfter) {
                }
                else 
                    return null;
                if (t.next !== null && t.next.isCharOf(".)>")) {
                }
                else if (!t.isWhitespaceAfter && t.next.isChar('(')) {
                }
                else if (t.isNewlineAfter) {
                }
                else 
                    return null;
            }
            nt = null;
            if (t.chars.isAllUpper || t.isValue("I", null)) 
                nt = NumberHelper.tryParseRoman(t);
            let up = t.chars.isAllUpper;
            res = new SingleNumToken(t0, t);
            let ch = t.term[0];
            res._addChar(ch, up);
            if ((ch.charCodeAt(0)) < 0x80) {
                let cyr = LanguageHelper.getCyrForLat(ch);
                if (cyr !== (String.fromCharCode(0))) 
                    res._addChar(cyr, up);
            }
            else {
                let lat = LanguageHelper.getLatForCyr(ch);
                if (lat !== (String.fromCharCode(0))) 
                    res._addChar(lat, up);
            }
            if (ch === 'I') 
                res._addNum(1, true, up);
            if (ch === 'V') 
                res._addNum(5, true, up);
            if (ch === 'X' || ch === 'Х') 
                res._addNum(10, true, up);
        }
        else if (t.isCharOf("ˡ¹²³")) {
            res = new SingleNumToken(t, t);
            res._addNum((t.isCharOf("ˡ¹") ? 1 : (t.isChar('²') ? 2 : 3)), false, false);
        }
        else {
            nt = NumberHelper.tryParseRoman(t);
            if (nt === null || nt.intValue === null) 
                return null;
            let ok = false;
            if (!first || force) 
                ok = true;
            else if (t.next !== null && t.next.isCharOf(".)")) 
                ok = true;
            else if (!t.isNewlineBefore && SingleNumToken._checkKeyword(t.previous)) 
                ok = true;
            if (!ok) 
                return null;
            res = new SingleNumToken(t0, t);
            res._addNum(nt.intValue, true, nt.chars.isAllUpper);
        }
        if (res === null) 
            return null;
        if (!res.endToken.isWhitespaceAfter) {
            t = res.endToken.next;
            if (t !== null) {
                if (t.isCharOf(".])>\\")) {
                    res.endToken = t;
                    res.suffix = t.getSourceText();
                }
            }
        }
        if (res.value === null) 
            res.value = res.getSourceText();
        if ((!hasPref && first && !force) && res.suffix === null && !res.isNewlineAfter) {
            let tt = res.endToken.next;
            if ((tt instanceof TextToken) && tt.chars.isAllLower) 
                return null;
        }
        if (res.value.length === 1 && res.suffix === null && res.prefix === null) {
            if (Utils.isLetter(res.value[0]) && res.beginToken.chars.isAllUpper) {
                if (res.beginToken.next !== null && res.beginToken.next.chars.isAllLower) 
                    return null;
            }
        }
        return res;
    }
    
    static _checkKeyword(t) {
        if (!(t instanceof TextToken)) 
            return false;
        let term = t.term;
        if (((term === "СТАТЬЯ" || term === "ГЛАВА" || term === "РАЗДЕЛ") || term === "ЧАСТЬ" || term === "ПОДРАЗДЕЛ") || term === "ПАРАГРАФ" || term === "ПОДПАРАГРАФ") 
            return true;
        return false;
    }
    
    get isOne() {
        for (const v of this.vals) {
            if (v.isOne) 
                return true;
        }
        return false;
    }
    
    correct(prev) {
        if (prev === null) {
            if (this.isOne) {
                for (let i = this.vals.length - 1; i >= 0; i--) {
                    if (!this.vals[i].isOne) 
                        this.vals.splice(i, 1);
                }
            }
            return;
        }
        let comp = new SingleNumComparer();
        comp.process(prev, this);
        if (comp.typ !== ComplexNumCompareType.LESS) 
            return;
        for (let i = prev.vals.length - 1; i >= 0; i--) {
            if (prev.vals[i] !== comp.val1) 
                prev.vals.splice(i, 1);
        }
        for (let i = this.vals.length - 1; i >= 0; i--) {
            if (this.vals[i] !== comp.val2) 
                this.vals.splice(i, 1);
        }
    }
}


module.exports = SingleNumToken