/*
 * 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 Hashtable = require("./../../unisharp/Hashtable");
const RefOutArgWrapper = require("./../../unisharp/RefOutArgWrapper");

const ReferentToken = require("./../ReferentToken");
const NumberToken = require("./../NumberToken");
const FioTemplateType = require("./../person/internal/FioTemplateType");
const BookLinkTyp = require("./internal/BookLinkTyp");
const Token = require("./../Token");
const MetaToken = require("./../MetaToken");
const TextToken = require("./../TextToken");
const BookLinkAnalyzerRegionTyp = require("./BookLinkAnalyzerRegionTyp");
const GetTextAttr = require("./../core/GetTextAttr");
const PersonItemTokenParseAttr = require("./../person/internal/PersonItemTokenParseAttr");
const PersonItemTokenItemType = require("./../person/internal/PersonItemTokenItemType");
const UriReferent = require("./../uri/UriReferent");
const TitleItemTokenTypes = require("./internal/TitleItemTokenTypes");
const NounPhraseParseAttr = require("./../core/NounPhraseParseAttr");
const MiscHelper = require("./../core/MiscHelper");
const BookLinkRefType = require("./BookLinkRefType");
const BracketParseAttr = require("./../core/BracketParseAttr");
const DateReferent = require("./../date/DateReferent");
const BracketHelper = require("./../core/BracketHelper");
const Termin = require("./../core/Termin");
const NounPhraseHelper = require("./../core/NounPhraseHelper");
const PersonItemToken = require("./../person/internal/PersonItemToken");
const MetaBookLinkRef = require("./internal/MetaBookLinkRef");
const Referent = require("./../Referent");
const PersonReferent = require("./../person/PersonReferent");
const OrganizationReferent = require("./../org/OrganizationReferent");
const GeoReferent = require("./../geo/GeoReferent");
const TitleItemToken = require("./internal/TitleItemToken");
const ProcessorService = require("./../ProcessorService");
const BookLinkRefReferent = require("./BookLinkRefReferent");
const BookLinkReferent = require("./BookLinkReferent");
const Analyzer = require("./../Analyzer");
const PullentiNerDecreeInternalResourceHelper = require("./../decree/internal/PullentiNerDecreeInternalResourceHelper");
const MetaBookLink = require("./internal/MetaBookLink");
const BookLinkToken = require("./internal/BookLinkToken");

/**
 * Анализатор ссылок на внешнюю литературу (библиография)
 */
class BookLinkAnalyzer extends Analyzer {
    
    get name() {
        return BookLinkAnalyzer.ANALYZER_NAME;
    }
    
    get caption() {
        return "Ссылки на литературу";
    }
    
    get description() {
        return "Ссылки из списка литературы";
    }
    
    get isSpecific() {
        return false;
    }
    
    get progressWeight() {
        return 1;
    }
    
    clone() {
        return new BookLinkAnalyzer();
    }
    
    get usedExternObjectTypes() {
        return [DateReferent.OBJ_TYPENAME, GeoReferent.OBJ_TYPENAME, OrganizationReferent.OBJ_TYPENAME, PersonReferent.OBJ_TYPENAME];
    }
    
    get typeSystem() {
        return [MetaBookLink.globalMeta, MetaBookLinkRef.globalMeta];
    }
    
    get images() {
        let res = new Hashtable();
        res.put(MetaBookLink.IMAGE_ID, PullentiNerDecreeInternalResourceHelper.getBytes("booklink.png"));
        res.put(MetaBookLinkRef.IMAGE_ID, PullentiNerDecreeInternalResourceHelper.getBytes("booklinkref.png"));
        res.put(MetaBookLinkRef.IMAGE_ID_INLINE, PullentiNerDecreeInternalResourceHelper.getBytes("booklinkrefinline.png"));
        res.put(MetaBookLinkRef.IMAGE_ID_LAST, PullentiNerDecreeInternalResourceHelper.getBytes("booklinkreflast.png"));
        return res;
    }
    
    createReferent(type) {
        if (type === BookLinkReferent.OBJ_TYPENAME) 
            return new BookLinkReferent();
        if (type === BookLinkRefReferent.OBJ_TYPENAME) 
            return new BookLinkRefReferent();
        return null;
    }
    
    process(kit) {
        let ad = kit.getAnalyzerData(this);
        let isLitBlock = 0;
        let refsByNum = new Hashtable();
        let rts = [ ];
        for (let t = kit.firstToken; t !== null; t = t.next) {
            if (t.isIgnored) 
                continue;
            if (t.isChar('(')) {
                let br = BracketHelper.tryParse(t, BracketParseAttr.NO, 100);
                if (br !== null && br.lengthChar > 70 && (br.lengthChar < 400)) {
                    if (br.isNewlineAfter || ((br.endToken.next !== null && br.endToken.next.isCharOf(".;")))) {
                        rts = BookLinkAnalyzer.tryParse(t.next, false, br.endChar);
                        if (rts !== null && rts.length >= 1) {
                            if (rts.length > 1) {
                                rts[1].referent = ad.registerReferent(rts[1].referent);
                                kit.embedToken(rts[1]);
                                rts[0].referent.book = Utils.as(rts[1].referent, BookLinkReferent);
                                if (rts[0].beginChar === rts[1].beginChar) 
                                    rts[0].beginToken = rts[1];
                                if (rts[0].endChar === rts[1].endChar) 
                                    rts[0].endToken = rts[1];
                            }
                            rts[0].beginToken = t;
                            rts[0].endToken = br.endToken;
                            rts[0].referent.typ = BookLinkRefType.INLINE;
                            rts[0].referent = ad.registerReferent(rts[0].referent);
                            kit.embedToken(rts[0]);
                            t = rts[0];
                            continue;
                        }
                    }
                }
            }
            if (!t.isNewlineBefore) 
                continue;
            if (isLitBlock <= 0) {
                let tt = BookLinkToken.parseStartOfLitBlock(t);
                if (tt !== null) {
                    isLitBlock = 5;
                    t = tt;
                    continue;
                }
            }
            rts = BookLinkAnalyzer.tryParse(t, isLitBlock > 0, 0);
            if (rts === null || (rts.length < 1)) {
                if ((--isLitBlock) < 0) 
                    isLitBlock = 0;
                continue;
            }
            if ((++isLitBlock) > 5) 
                isLitBlock = 5;
            if (rts.length > 1) {
                rts[1].referent = ad.registerReferent(rts[1].referent);
                kit.embedToken(rts[1]);
                rts[0].referent.book = Utils.as(rts[1].referent, BookLinkReferent);
                if (rts[0].beginChar === rts[1].beginChar) 
                    rts[0].beginToken = rts[1];
                if (rts[0].endChar === rts[1].endChar) 
                    rts[0].endToken = rts[1];
            }
            let re = Utils.as(rts[0].referent, BookLinkRefReferent);
            re = Utils.as(ad.registerReferent(re), BookLinkRefReferent);
            rts[0].referent = re;
            kit.embedToken(rts[0]);
            t = rts[0];
            if (re.number !== null) {
                let li = [ ];
                let wrapli521 = new RefOutArgWrapper();
                let inoutres522 = refsByNum.tryGetValue(re.number, wrapli521);
                li = wrapli521.value;
                if (!inoutres522) 
                    refsByNum.put(re.number, (li = new Array()));
                li.push(re);
            }
        }
        for (let t = kit.firstToken; t !== null; t = t.next) {
            if (t.isIgnored) 
                continue;
            if (!(t instanceof TextToken)) 
                continue;
            let rt = BookLinkAnalyzer.tryParseShortInline(t);
            if (rt === null) 
                continue;
            let re = Utils.as(rt.referent, BookLinkRefReferent);
            let li = [ ];
            let wrapli523 = new RefOutArgWrapper();
            let inoutres524 = refsByNum.tryGetValue(Utils.notNull(re.number, ""), wrapli523);
            li = wrapli523.value;
            if (!inoutres524) 
                continue;
            let i = 0;
            for (i = 0; i < li.length; i++) {
                if (t.beginChar < li[i].occurrence[0].beginChar) 
                    break;
            }
            if (i >= li.length) 
                continue;
            re.book = li[i].book;
            if (re.pages === null) 
                re.pages = li[i].pages;
            re.typ = BookLinkRefType.INLINE;
            re = Utils.as(ad.registerReferent(re), BookLinkRefReferent);
            rt.referent = re;
            kit.embedToken(rt);
            t = rt;
        }
    }
    
    static tryParseShortInline(t) {
        if (t === null) 
            return null;
        let re = null;
        if (t.isChar('[') && !t.isNewlineBefore) {
            let bb = BookLinkToken.tryParse(t, 0);
            if (bb !== null && bb.typ === BookLinkTyp.NUMBER) {
                re = new BookLinkRefReferent();
                re.number = bb.value;
                return new ReferentToken(re, t, bb.endToken);
            }
        }
        if (t.isChar('(')) {
            let bbb = BookLinkToken.tryParse(t.next, 0);
            if (bbb === null) 
                return null;
            if (bbb.typ === BookLinkTyp.SEE) {
                for (let tt = bbb.endToken.next; tt !== null; tt = tt.next) {
                    if (tt.isCharOf(",:.")) 
                        continue;
                    if (tt.isChar('[')) {
                        if (((tt.next instanceof NumberToken) && tt.next.next !== null && tt.next.next.isChar(']')) && tt.next.next !== null && tt.next.next.next.isChar(')')) {
                            re = new BookLinkRefReferent();
                            re.number = tt.next.value.toString();
                            return new ReferentToken(re, t, tt.next.next.next);
                        }
                    }
                    if ((tt instanceof NumberToken) && tt.next !== null && tt.next.isChar(')')) {
                        re = new BookLinkRefReferent();
                        re.number = tt.value.toString();
                        return new ReferentToken(re, t, tt.next);
                    }
                    break;
                }
                return null;
            }
            if (bbb.typ === BookLinkTyp.NUMBER) {
                let tt1 = bbb.endToken.next;
                if (tt1 !== null && tt1.isComma) 
                    tt1 = tt1.next;
                let bbb2 = BookLinkToken.tryParse(tt1, 0);
                if ((bbb2 !== null && bbb2.typ === BookLinkTyp.PAGERANGE && bbb2.endToken.next !== null) && bbb2.endToken.next.isChar(')')) {
                    re = new BookLinkRefReferent();
                    re.number = bbb.value;
                    re.pages = bbb2.value;
                    return new ReferentToken(re, t, bbb2.endToken.next);
                }
            }
        }
        return null;
    }
    
    static tryParse(t, isInLit, maxChar = 0) {
        if (t === null) 
            return null;
        let isBracketRegime = false;
        if (t.previous !== null && t.previous.isChar('(')) 
            isBracketRegime = true;
        let blt = BookLinkToken.tryParse(t, 0);
        if (blt === null) 
            blt = BookLinkToken.tryParseAuthor(t, FioTemplateType.UNDEFINED);
        if (blt === null && !isBracketRegime) 
            return null;
        let t0 = t;
        let coef = 0;
        let isElectrRes = false;
        let decree = null;
        let regtyp = BookLinkAnalyzerRegionTyp.UNDEFINED;
        let num = null;
        let specSee = null;
        let bookPrev = null;
        if (isBracketRegime) 
            regtyp = BookLinkAnalyzerRegionTyp.AUTHORS;
        else if (blt.typ === BookLinkTyp.PERSON) {
            if (!isInLit) 
                return null;
            regtyp = BookLinkAnalyzerRegionTyp.AUTHORS;
        }
        else if (blt.typ === BookLinkTyp.NUMBER) {
            num = blt.value;
            t = blt.endToken.next;
            if (t === null || t.isNewlineBefore) 
                return null;
            if (!t.isWhitespaceBefore) {
                if (t instanceof NumberToken) {
                    let n = t.value;
                    if ((((n === "3" || n === "0")) && !t.isWhitespaceAfter && (t.next instanceof TextToken)) && t.next.chars.isAllLower) {
                    }
                    else 
                        return null;
                }
                else if (!(t instanceof TextToken) || t.chars.isAllLower) {
                    let r = t.getReferent();
                    if (r instanceof PersonReferent) {
                    }
                    else if (isInLit && r !== null && r.typeName === "DECREE") {
                    }
                    else 
                        return null;
                }
            }
            for (; t !== null; t = t.next) {
                if (t instanceof NumberToken) 
                    break;
                if (!(t instanceof TextToken)) 
                    break;
                if (BracketHelper.canBeStartOfSequence(t, true, false)) 
                    break;
                if (!t.chars.isLetter) 
                    continue;
                let bbb = BookLinkToken.tryParse(t, 0);
                if (bbb !== null) {
                    if (bbb.typ === BookLinkTyp.TAMZE) {
                        specSee = bbb;
                        t = bbb.endToken.next;
                        break;
                    }
                    if (bbb.typ === BookLinkTyp.SEE) {
                        t = bbb.endToken;
                        continue;
                    }
                }
                break;
            }
            if (specSee !== null && specSee.typ === BookLinkTyp.TAMZE) {
                coef++;
                let max = 1000;
                for (let tt = t0; tt !== null && max > 0; tt = tt.previous,max--) {
                    if (tt.getReferent() instanceof BookLinkRefReferent) {
                        bookPrev = tt.getReferent().book;
                        break;
                    }
                }
            }
            let blt1 = BookLinkToken.tryParseAuthor(t, FioTemplateType.UNDEFINED);
            if (blt1 !== null && blt1.typ === BookLinkTyp.PERSON) 
                regtyp = BookLinkAnalyzerRegionTyp.AUTHORS;
            else {
                let ok = false;
                for (let tt = t; tt !== null; tt = (tt === null ? null : tt.next)) {
                    if (tt.isNewlineBefore) 
                        break;
                    if (isInLit && tt.getReferent() !== null && tt.getReferent().typeName === "DECREE") {
                        ok = true;
                        decree = tt;
                        break;
                    }
                    let bbb = BookLinkToken.tryParse(tt, 0);
                    if (bbb === null) 
                        continue;
                    if (bbb.typ === BookLinkTyp.ELECTRONRES) {
                        isElectrRes = true;
                        ok = true;
                        break;
                    }
                    if (bbb.typ === BookLinkTyp.DELIMETER) {
                        tt = bbb.endToken.next;
                        if (BookLinkToken.tryParseAuthor(tt, FioTemplateType.UNDEFINED) !== null) {
                            ok = true;
                            break;
                        }
                        bbb = BookLinkToken.tryParse(tt, 0);
                        if (bbb !== null) {
                            if (bbb.typ === BookLinkTyp.EDITORS || bbb.typ === BookLinkTyp.TRANSLATE || bbb.typ === BookLinkTyp.SOSTAVITEL) {
                                ok = true;
                                break;
                            }
                        }
                    }
                }
                if (!ok && !isInLit) {
                    if (BookLinkToken.checkLinkBefore(t0, num)) {
                    }
                    else 
                        return null;
                }
                regtyp = BookLinkAnalyzerRegionTyp.NAME;
            }
        }
        else 
            return null;
        let res = new BookLinkReferent();
        let corrAuthors = new Array();
        let t00 = t;
        let blt00 = null;
        let startOfName = null;
        let prevPersTempl = FioTemplateType.UNDEFINED;
        if (regtyp === BookLinkAnalyzerRegionTyp.AUTHORS) {
            for (; t !== null; t = t.next) {
                if (maxChar > 0 && t.beginChar >= maxChar) 
                    break;
                if (t.isCharOf(".;") || t.isCommaAnd) 
                    continue;
                if (t.isChar('/')) 
                    break;
                if ((t.isChar('(') && t.next !== null && t.next.isValue("EDS", null)) && t.next.next !== null && t.next.next.isChar(')')) {
                    t = t.next.next.next;
                    break;
                }
                blt = BookLinkToken.tryParseAuthor(t, prevPersTempl);
                if (blt === null && t.previous !== null && t.previous.isAnd) 
                    blt = BookLinkToken.tryParseAuthor(t.previous, FioTemplateType.UNDEFINED);
                if (blt === null) {
                    if ((t.getReferent() instanceof OrganizationReferent) && blt00 !== null) {
                        let bbb2 = BookLinkToken.tryParse(t.next, 0);
                        if (bbb2 !== null) {
                            if (bbb2.typ === BookLinkTyp.YEAR) {
                                res.addSlot(BookLinkReferent.ATTR_AUTHOR, t.getReferent(), false, 0);
                                res.year = Utils.parseInt(bbb2.value);
                                coef += 0.5;
                                t = bbb2.endToken.next;
                            }
                        }
                    }
                    break;
                }
                if (blt.typ === BookLinkTyp.PERSON) {
                    let tt2 = blt.endToken.next;
                    let bbb2 = BookLinkToken.tryParse(tt2, 0);
                    if (bbb2 !== null) {
                        if (bbb2.typ === BookLinkTyp.YEAR) {
                            res.year = Utils.parseInt(bbb2.value);
                            coef += 0.5;
                            blt.endToken = bbb2.endToken;
                            blt00 = null;
                        }
                    }
                    if (blt00 !== null && ((blt00.endToken.next === blt.beginToken || blt.beginToken.previous.isChar('.')))) {
                        let tt11 = blt.endToken.next;
                        let nex = BookLinkToken.tryParse(tt11, 0);
                        if (nex !== null && nex.typ === BookLinkTyp.ANDOTHERS) {
                        }
                        else {
                            if (tt11 === null) 
                                break;
                            if (tt11.isChar('/') && tt11.next !== null && tt11.next.isChar('/')) 
                                break;
                            if (tt11.isChar(':')) 
                                break;
                            if ((blt.toString().indexOf('.') < 0) && blt00.toString().indexOf('.') > 0) 
                                break;
                            if ((tt11 instanceof TextToken) && tt11.chars.isAllLower) 
                                break;
                            if (tt11.isCharOf(",.;") && tt11.next !== null) 
                                tt11 = tt11.next;
                            nex = BookLinkToken.tryParse(tt11, 0);
                            if (nex !== null && nex.typ !== BookLinkTyp.PERSON && nex.typ !== BookLinkTyp.ANDOTHERS) 
                                break;
                        }
                    }
                    else if ((blt00 !== null && blt00.personTemplate !== FioTemplateType.UNDEFINED && blt.personTemplate !== blt00.personTemplate) && blt.personTemplate === FioTemplateType.NAMESURNAME) {
                        if (blt.endToken.next === null || !blt.endToken.next.isCommaAnd) 
                            break;
                        if (BookLinkToken.tryParseAuthor(blt.endToken.next.next, FioTemplateType.UNDEFINED) !== null) {
                        }
                        else 
                            break;
                    }
                    if (blt00 === null && blt.personTemplate === FioTemplateType.NAMESURNAME) {
                        let tt = blt.endToken.next;
                        if (tt !== null && tt.isHiphen) 
                            tt = tt.next;
                        if (tt instanceof NumberToken) 
                            break;
                    }
                    BookLinkAnalyzer._addAuthor(res, blt);
                    coef++;
                    t = blt.endToken;
                    if (t.getReferent() instanceof PersonReferent) 
                        corrAuthors.push(Utils.as(t, ReferentToken));
                    blt00 = blt;
                    prevPersTempl = blt.personTemplate;
                    if ((((startOfName = blt.startOfName))) !== null) {
                        t = t.next;
                        break;
                    }
                    continue;
                }
                if (blt.typ === BookLinkTyp.ANDOTHERS) {
                    coef += 0.5;
                    t = blt.endToken.next;
                    res.authorsAndOther = true;
                    break;
                }
                break;
            }
        }
        if (t === null) 
            return null;
        if ((t.isNewlineBefore && t !== t0 && num === null) && res.findSlot(BookLinkReferent.ATTR_AUTHOR, null, true) === null) 
            return null;
        if (startOfName === null) {
            if (t.chars.isAllLower) 
                coef -= (1);
            if (t.chars.isLatinLetter && !isElectrRes && num === null) {
                if (res.getSlotValue(BookLinkReferent.ATTR_AUTHOR) === null) 
                    return null;
            }
        }
        let tn0 = t;
        let tn1 = null;
        let uri = null;
        let nextNum = null;
        let nn = 0;
        let wrapnn529 = new RefOutArgWrapper();
        let inoutres530 = Utils.tryParseInt((num != null ? num : ""), wrapnn529);
        nn = wrapnn529.value;
        if (inoutres530) 
            nextNum = (nn + 1).toString();
        let br = (BracketHelper.canBeStartOfSequence(t, true, false) ? BracketHelper.tryParse(t, BracketParseAttr.of((BracketParseAttr.CANCONTAINSVERBS.value()) | (BracketParseAttr.CANBEMANYLINES.value())), 100) : null);
        if (br !== null) 
            t = t.next;
        let pages = null;
        for (; t !== null; t = t.next) {
            if (maxChar > 0 && t.beginChar >= maxChar) 
                break;
            if (br !== null && br.endToken === t) {
                tn1 = t;
                break;
            }
            let tit = TitleItemToken.tryAttach(t);
            if (tit !== null) {
                if ((tit.typ === TitleItemTokenTypes.TYP && tn0 === t && br === null) && BracketHelper.canBeStartOfSequence(tit.endToken.next, true, false)) {
                    br = BracketHelper.tryParse(tit.endToken.next, BracketParseAttr.NO, 100);
                    if (br !== null) {
                        coef += (1);
                        if (num !== null) 
                            coef++;
                        tn0 = br.beginToken;
                        tn1 = br.endToken;
                        res.typ = tit.value.toLowerCase();
                        t = br.endToken.next;
                        break;
                    }
                }
            }
            if (t.isNewlineBefore && t !== tn0) {
                if (br !== null && (t.endChar < br.endChar)) {
                }
                else if (!MiscHelper.canBeStartOfSentence(t)) {
                }
                else {
                    if (t.newlinesBeforeCount > 1) 
                        break;
                    if ((t instanceof NumberToken) && num !== null && t.intValue !== null) {
                        if (num === (t.intValue - 1).toString()) 
                            break;
                    }
                    else if (num !== null) {
                    }
                    else {
                        let nnn = NounPhraseHelper.tryParse(t.previous, NounPhraseParseAttr.of(((NounPhraseParseAttr.PARSEPREPOSITION.value()) | (NounPhraseParseAttr.PARSEADVERBS.value()) | (NounPhraseParseAttr.PARSENUMERICASADJECTIVE.value())) | (NounPhraseParseAttr.MULTILINES.value())), 0, null);
                        if (nnn !== null && nnn.endChar >= t.endChar) {
                        }
                        else 
                            break;
                    }
                }
            }
            if (t.isCharOf(".;") && t.whitespacesAfterCount > 0) {
                if ((((tit = TitleItemToken.tryAttach(t.next)))) !== null) {
                    if (tit.typ === TitleItemTokenTypes.TYP) 
                        break;
                }
                let stop = true;
                let words = 0;
                let notwords = 0;
                for (let tt = t.next; tt !== null; tt = tt.next) {
                    let blt0 = BookLinkToken.tryParse(tt, 0);
                    if (blt0 === null) {
                        if (tt.isNewlineBefore) 
                            break;
                        if ((tt instanceof TextToken) && !tt.getMorphClassInDictionary().isUndefined) 
                            words++;
                        else 
                            notwords++;
                        if (words > 6 && words > (notwords * 4)) {
                            stop = false;
                            break;
                        }
                        continue;
                    }
                    if ((blt0.typ === BookLinkTyp.DELIMETER || blt0.typ === BookLinkTyp.TRANSLATE || blt0.typ === BookLinkTyp.TYPE) || blt0.typ === BookLinkTyp.GEO || blt0.typ === BookLinkTyp.PRESS) 
                        stop = false;
                    break;
                }
                if (br !== null && br.endToken.previous.endChar > t.endChar) 
                    stop = false;
                if (stop) 
                    break;
            }
            if (t === decree) {
                t = t.next;
                break;
            }
            blt = BookLinkToken.tryParse(t, 0);
            if (blt === null) {
                tn1 = t;
                continue;
            }
            if (blt.typ === BookLinkTyp.DELIMETER) 
                break;
            if (((blt.typ === BookLinkTyp.MISC || blt.typ === BookLinkTyp.TRANSLATE || blt.typ === BookLinkTyp.NAMETAIL) || blt.typ === BookLinkTyp.TYPE || blt.typ === BookLinkTyp.VOLUME) || blt.typ === BookLinkTyp.PAGERANGE || blt.typ === BookLinkTyp.PAGES) {
                coef++;
                break;
            }
            if (blt.typ === BookLinkTyp.GEO || blt.typ === BookLinkTyp.PRESS) {
                if (t.previous.isHiphen || t.previous.isCharOf(".;") || blt.addCoef > 0) 
                    break;
            }
            if (blt.typ === BookLinkTyp.YEAR) {
                if (t.previous !== null && t.previous.isComma) 
                    break;
            }
            if (blt.typ === BookLinkTyp.ELECTRONRES) {
                isElectrRes = true;
                break;
            }
            if (blt.typ === BookLinkTyp.URL) {
                if (t === tn0 || t.previous.isCharOf(":.")) {
                    isElectrRes = true;
                    break;
                }
            }
            tn1 = t;
        }
        if (tn1 === null && startOfName === null) {
            if (isElectrRes) {
                let uriRe = new BookLinkReferent();
                let rt0 = new ReferentToken(uriRe, t00, t);
                let rts0 = new Array();
                let bref0 = BookLinkRefReferent._new525(uriRe);
                if (num !== null) 
                    bref0.number = num;
                let rt01 = new ReferentToken(bref0, t0, rt0.endToken);
                let ok = false;
                for (; t !== null; t = t.next) {
                    if (t.isNewlineBefore) 
                        break;
                    let blt0 = BookLinkToken.tryParse(t, 0);
                    if (blt0 !== null) {
                        if (blt0.ref instanceof UriReferent) {
                            uriRe.addSlot(BookLinkReferent.ATTR_URL, Utils.as(blt0.ref, UriReferent), false, 0);
                            ok = true;
                        }
                        t = blt0.endToken;
                    }
                    rt0.endToken = rt01.endToken = t;
                }
                if (ok) {
                    rts0.push(rt01);
                    rts0.push(rt0);
                    return rts0;
                }
            }
            if (decree !== null && num !== null) {
                let rts0 = new Array();
                let bref0 = BookLinkRefReferent._new525(decree.getReferent());
                if (num !== null) 
                    bref0.number = num;
                let rt01 = new ReferentToken(bref0, t0, decree);
                for (t = decree.next; t !== null; t = t.next) {
                    if (t.isNewlineBefore) 
                        break;
                    if (t instanceof TextToken) {
                        if (t.isPureVerb) 
                            return null;
                    }
                    rt01.endToken = t;
                }
                rts0.push(rt01);
                return rts0;
            }
            if (bookPrev !== null) {
                let tt = t;
                while (tt !== null && ((tt.isCharOf(",.") || tt.isHiphen))) {
                    tt = tt.next;
                }
                let blt0 = BookLinkToken.tryParse(tt, 0);
                if (blt0 !== null && blt0.typ === BookLinkTyp.PAGERANGE) {
                    let rts0 = new Array();
                    let bref0 = BookLinkRefReferent._new525(bookPrev);
                    if (num !== null) 
                        bref0.number = num;
                    bref0.pages = blt0.value;
                    let rt00 = new ReferentToken(bref0, t0, blt0.endToken);
                    rts0.push(rt00);
                    return rts0;
                }
            }
            return null;
        }
        if (br !== null && ((tn1 === br.endToken || tn1 === br.endToken.previous))) {
            tn0 = tn0.next;
            tn1 = tn1.previous;
        }
        if (startOfName === null) {
            while (tn0 !== null) {
                if (tn0.isCharOf(":,~")) 
                    tn0 = tn0.next;
                else 
                    break;
            }
        }
        for (; tn1 !== null && tn1.beginChar > tn0.beginChar; tn1 = tn1.previous) {
            if (tn1.isCharOf(".;,:(~") || tn1.isHiphen || tn1.isValue("РЕД", null)) {
            }
            else 
                break;
        }
        let nam = MiscHelper.getTextValue(tn0, tn1, GetTextAttr.of((GetTextAttr.KEEPQUOTES.value()) | (GetTextAttr.KEEPREGISTER.value())));
        if (startOfName !== null) {
            if (nam === null || (nam.length < 3)) 
                nam = startOfName;
            else 
                nam = (startOfName + (tn0.isWhitespaceBefore ? " " : "") + nam);
        }
        if (nam === null) 
            return null;
        res.name = nam;
        if (num === null && !isInLit) {
            if (nam.length < 20) 
                return null;
            coef -= (2);
        }
        if (nam.length > 500) 
            coef -= (Utils.intDiv(nam.length, 500));
        if (isBracketRegime) 
            coef--;
        if (nam.length > 200) {
            if (num === null) 
                return null;
            if (res.findSlot(BookLinkReferent.ATTR_AUTHOR, null, true) === null && !BookLinkToken.checkLinkBefore(t0, num)) 
                return null;
        }
        let en = 0;
        let ru = 0;
        let ua = 0;
        let cha = 0;
        let nocha = 0;
        let chalen = 0;
        let lt0 = tn0;
        let lt1 = tn1;
        if (tn1 === null) {
            if (t === null) 
                return null;
            lt0 = t0;
            lt1 = t;
            tn1 = t.previous;
        }
        for (let tt = lt0; tt !== null && tt.endChar <= lt1.endChar; tt = tt.next) {
            if ((tt instanceof TextToken) && tt.chars.isLetter) {
                if (tt.chars.isLatinLetter) 
                    en++;
                else if (tt.morph.language.isUa) 
                    ua++;
                else if (tt.morph.language.isRu) 
                    ru++;
                if (tt.lengthChar > 2) {
                    cha++;
                    chalen += tt.lengthChar;
                }
            }
            else if (!(tt instanceof ReferentToken)) 
                nocha++;
        }
        if (ru > (ua + en)) 
            res.lang = "RU";
        else if (ua > (ru + en)) 
            res.lang = "UA";
        else if (en > (ru + ua)) 
            res.lang = "EN";
        if (nocha > 3 && nocha > cha && startOfName === null) {
            if (nocha > (Utils.intDiv(chalen, 3))) 
                coef -= (2);
        }
        if (res.lang === "EN") {
            for (let tt = tn0.next; tt !== null && (tt.endChar < tn1.endChar); tt = tt.next) {
                if (tt.isComma && tt.next !== null && ((!tt.next.chars.isAllLower || (tt.next instanceof ReferentToken)))) {
                    if (tt.next.next !== null && tt.next.next.isCommaAnd) {
                        if (tt.next instanceof ReferentToken) {
                        }
                        else 
                            continue;
                    }
                    nam = MiscHelper.getTextValue(tn0, tt.previous, GetTextAttr.of((GetTextAttr.KEEPQUOTES.value()) | (GetTextAttr.KEEPREGISTER.value())));
                    if (nam !== null && nam.length > 15) {
                        res.name = nam;
                        break;
                    }
                }
            }
        }
        let rt = new ReferentToken(res, t00, tn1);
        let authors = true;
        let edits = false;
        br = null;
        for (; t !== null; t = t.next) {
            if (maxChar > 0 && t.beginChar >= maxChar) 
                break;
            if (BracketHelper.canBeStartOfSequence(t, false, false)) {
                br = BracketHelper.tryParse(t, BracketParseAttr.CANBEMANYLINES, 100);
                if (br !== null && br.lengthChar > 300) 
                    br = null;
            }
            blt = BookLinkToken.tryParse(t, 0);
            if (t.isNewlineBefore && !t.isChar('/') && !t.previous.isChar('/')) {
                if (blt !== null && blt.typ === BookLinkTyp.NUMBER) 
                    break;
                if (t.previous.isCharOf(":")) {
                }
                else if (blt !== null && ((((blt.typ === BookLinkTyp.DELIMETER || blt.typ === BookLinkTyp.PAGERANGE || blt.typ === BookLinkTyp.PAGES) || blt.typ === BookLinkTyp.GEO || blt.typ === BookLinkTyp.PRESS) || blt.typ === BookLinkTyp.N))) {
                }
                else if (num !== null && BookLinkToken.tryParseAuthor(t, FioTemplateType.UNDEFINED) !== null) {
                }
                else if (num !== null && blt !== null && blt.typ !== BookLinkTyp.NUMBER) {
                }
                else if (br !== null && (t.endChar < br.endChar) && t.beginChar > br.beginChar) {
                }
                else {
                    let ok = false;
                    let mmm = 50;
                    for (let tt = t.next; tt !== null && mmm > 0; tt = tt.next,mmm--) {
                        if (tt.isNewlineBefore) {
                            let blt2 = BookLinkToken.tryParse(tt, 0);
                            if (blt2 !== null && blt2.typ === BookLinkTyp.NUMBER && blt2.value === nextNum) {
                                ok = true;
                                break;
                            }
                            if (blt2 !== null) {
                                if (blt2.typ === BookLinkTyp.PAGES || blt2.typ === BookLinkTyp.GEO || blt2.typ === BookLinkTyp.PRESS) {
                                    ok = true;
                                    break;
                                }
                            }
                        }
                    }
                    if (!ok) {
                        let npt = NounPhraseHelper.tryParse(t.previous, NounPhraseParseAttr.of(((NounPhraseParseAttr.MULTILINES.value()) | (NounPhraseParseAttr.PARSEADVERBS.value()) | (NounPhraseParseAttr.PARSEPREPOSITION.value())) | (NounPhraseParseAttr.PARSEVERBS.value()) | (NounPhraseParseAttr.PARSEPRONOUNS.value())), 0, null);
                        if (npt !== null && npt.endChar >= t.endChar) 
                            ok = true;
                    }
                    if (!ok) 
                        break;
                }
            }
            rt.endToken = t;
            if (blt !== null) 
                rt.endToken = blt.endToken;
            if (t.isCharOf(".,") || t.isHiphen) 
                continue;
            if (t.isValue("С", null)) {
            }
            if (regtyp === BookLinkAnalyzerRegionTyp.FIRST && blt !== null && blt.typ === BookLinkTyp.EDITORS) {
                edits = true;
                t = blt.endToken;
                coef++;
                continue;
            }
            if (regtyp === BookLinkAnalyzerRegionTyp.FIRST && blt !== null && blt.typ === BookLinkTyp.SOSTAVITEL) {
                edits = false;
                t = blt.endToken;
                coef++;
                continue;
            }
            if (regtyp === BookLinkAnalyzerRegionTyp.FIRST && authors) {
                let blt2 = BookLinkToken.tryParseAuthor(t, prevPersTempl);
                if (blt2 !== null && blt2.typ === BookLinkTyp.PERSON) {
                    prevPersTempl = blt2.personTemplate;
                    if (!edits) 
                        BookLinkAnalyzer._addAuthor(res, blt2);
                    coef++;
                    t = blt2.endToken;
                    continue;
                }
                if (blt2 !== null && blt2.typ === BookLinkTyp.ANDOTHERS) {
                    if (!edits) 
                        res.authorsAndOther = true;
                    coef++;
                    t = blt2.endToken;
                    continue;
                }
                authors = false;
            }
            if (blt === null) 
                continue;
            if (blt.typ === BookLinkTyp.ELECTRONRES || blt.typ === BookLinkTyp.URL) {
                isElectrRes = true;
                if (blt.typ === BookLinkTyp.ELECTRONRES) 
                    coef += 1.5;
                else 
                    coef += 0.5;
                if (blt.ref instanceof UriReferent) 
                    res.addSlot(BookLinkReferent.ATTR_URL, Utils.as(blt.ref, UriReferent), false, 0);
            }
            else if (blt.typ === BookLinkTyp.YEAR) {
                if (res.year === 0) {
                    res.year = Utils.parseInt(blt.value);
                    coef += 0.5;
                }
            }
            else if (blt.typ === BookLinkTyp.DELIMETER) {
                coef++;
                if (blt.lengthChar === 2) 
                    regtyp = BookLinkAnalyzerRegionTyp.SECOND;
                else 
                    regtyp = BookLinkAnalyzerRegionTyp.FIRST;
            }
            else if ((((blt.typ === BookLinkTyp.MISC || blt.typ === BookLinkTyp.TYPE || blt.typ === BookLinkTyp.PAGES) || blt.typ === BookLinkTyp.NAMETAIL || blt.typ === BookLinkTyp.TRANSLATE) || blt.typ === BookLinkTyp.PRESS || blt.typ === BookLinkTyp.VOLUME) || blt.typ === BookLinkTyp.N) 
                coef++;
            else if (blt.typ === BookLinkTyp.PAGERANGE) {
                pages = blt;
                coef++;
                if (isBracketRegime && blt.endToken.next !== null && blt.endToken.next.isChar(')')) {
                    coef += (2);
                    if (res.name !== null && res.findSlot(BookLinkReferent.ATTR_AUTHOR, null, true) !== null) 
                        coef = 10;
                }
            }
            else if (blt.typ === BookLinkTyp.GEO && ((regtyp === BookLinkAnalyzerRegionTyp.SECOND || regtyp === BookLinkAnalyzerRegionTyp.FIRST))) 
                coef++;
            else if (blt.typ === BookLinkTyp.GEO && t.previous !== null && t.previous.isChar('.')) 
                coef++;
            else if (blt.typ === BookLinkTyp.ANDOTHERS) {
                coef++;
                if (authors) 
                    res.authorsAndOther = true;
            }
            coef += blt.addCoef;
            t = blt.endToken;
        }
        if ((coef < 2.5) && num !== null) {
            if (BookLinkToken.checkLinkBefore(t0, num)) 
                coef += (2);
            else if (BookLinkToken.checkLinkAfter(rt.endToken, num)) 
                coef += (1);
        }
        if (rt.lengthChar > 500) 
            return null;
        if (isInLit) 
            coef++;
        if (coef < 2.5) {
            if (isElectrRes && uri !== null) {
            }
            else if (coef >= 2 && isInLit) {
            }
            else 
                return null;
        }
        for (const rr of corrAuthors) {
            let pits0 = PersonItemToken.tryAttachList(rr.beginToken, PersonItemTokenParseAttr.CANINITIALBEDIGIT, 10);
            if (pits0 === null || (pits0.length < 2)) 
                continue;
            if (pits0[0].typ === PersonItemTokenItemType.VALUE) {
                let exi = false;
                for (let i = rr.referent.slots.length - 1; i >= 0; i--) {
                    let s = rr.referent.slots[i];
                    if (s.typeName === PersonReferent.ATTR_LASTNAME) {
                        let ln = Utils.asString(s.value);
                        if (ln === null) 
                            continue;
                        if (ln === pits0[0].value) {
                            exi = true;
                            continue;
                        }
                        if (ln.indexOf('-') > 0) 
                            ln = ln.substring(0, 0 + ln.indexOf('-'));
                        if (pits0[0].beginToken.isValue(ln, null)) 
                            rr.referent.slots.splice(i, 1);
                    }
                }
                if (!exi) 
                    rr.referent.addSlot(PersonReferent.ATTR_LASTNAME, pits0[0].value, false, 0);
            }
        }
        let rts = new Array();
        let bref = BookLinkRefReferent._new525(res);
        if (num !== null) 
            bref.number = num;
        let rt1 = new ReferentToken(bref, t0, rt.endToken);
        if (pages !== null) {
            if (pages.value !== null) 
                bref.pages = pages.value;
            rt.endToken = pages.beginToken.previous;
        }
        rts.push(rt1);
        rts.push(rt);
        return rts;
    }
    
    static _addAuthor(blr, tok) {
        if (tok.ref !== null) 
            blr.addSlot(BookLinkReferent.ATTR_AUTHOR, tok.ref, false, 0);
        else if (tok.tok !== null) {
            blr.addSlot(BookLinkReferent.ATTR_AUTHOR, tok.tok.referent, false, 0);
            blr.addExtReferent(tok.tok);
        }
        else if (tok.value !== null) 
            blr.addSlot(BookLinkReferent.ATTR_AUTHOR, tok.value, false, 0);
    }
    
    static initialize() {
        MetaBookLink.initialize();
        MetaBookLinkRef.initialize();
        try {
            Termin.ASSIGN_ALL_TEXTS_AS_NORMAL = true;
            BookLinkToken.initialize();
            Termin.ASSIGN_ALL_TEXTS_AS_NORMAL = false;
        } catch (ex) {
            throw new Error(ex.message);
        }
        ProcessorService.registerAnalyzer(new BookLinkAnalyzer());
    }
    
    static static_constructor() {
        BookLinkAnalyzer.ANALYZER_NAME = "BOOKLINK";
    }
}


BookLinkAnalyzer.static_constructor();

module.exports = BookLinkAnalyzer