/*
 * 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 DenominationReferent = require("./../../denomination/DenominationReferent");
const DateReferent = require("./../../date/DateReferent");
const NumberToken = require("./../../NumberToken");
const GeoReferent = require("./../../geo/GeoReferent");
const PersonReferent = require("./../../person/PersonReferent");
const BracketHelper = require("./../../core/BracketHelper");
const UriReferent = require("./../../uri/UriReferent");
const MetaToken = require("./../../MetaToken");
const TextToken = require("./../../TextToken");
const PersonAttrTokenPersonAttrAttachAttrs = require("./../../person/internal/PersonAttrTokenPersonAttrAttachAttrs");
const PhoneReferent = require("./../../phone/PhoneReferent");
const NumberSpellingType = require("./../../NumberSpellingType");
const PersonAttrToken = require("./../../person/internal/PersonAttrToken");
const TitleItemTokenTypes = require("./TitleItemTokenTypes");
const BookLinkTyp = require("./../../booklink/internal/BookLinkTyp");
const MorphNumber = require("./../../../morph/MorphNumber");
const OrgItemTypeToken = require("./../../org/internal/OrgItemTypeToken");
const TitleItemToken = require("./TitleItemToken");
const BracketParseAttr = require("./../../core/BracketParseAttr");
const OrganizationReferent = require("./../../org/OrganizationReferent");
const NounPhraseParseAttr = require("./../../core/NounPhraseParseAttr");
const FioTemplateType = require("./../../person/internal/FioTemplateType");
const NounPhraseHelper = require("./../../core/NounPhraseHelper");
const BookLinkToken = require("./../../booklink/internal/BookLinkToken");

/**
 * Название статьи
 */
class TitleNameToken extends MetaToken {
    
    constructor(begin, end) {
        super(begin, end, null);
        this.rank = 0;
        this.beginNameToken = null;
        this.endNameToken = null;
        this.typeValue = null;
        this.speciality = null;
    }
    
    toString() {
        if (this.beginNameToken === null || this.endNameToken === null) 
            return "?";
        let mt = new MetaToken(this.beginNameToken, this.endNameToken);
        if (this.typeValue === null) 
            return (String(this.rank) + ": " + mt.toString());
        else 
            return (String(this.rank) + ": " + mt.toString() + " (" + this.typeValue + ")");
    }
    
    static sort(li) {
        for (let k = 0; k < li.length; k++) {
            let ch = false;
            for (let i = 0; i < (li.length - 1); i++) {
                if (li[i].rank < li[i + 1].rank) {
                    ch = true;
                    let v = li[i];
                    li[i] = li[i + 1];
                    li[i + 1] = v;
                }
            }
            if (!ch) 
                break;
        }
    }
    
    static canBeStartOfTextOrContent(begin, end) {
        let t = null;
        if (begin.isValue("СОДЕРЖАНИЕ", "ЗМІСТ") || begin.isValue("ОГЛАВЛЕНИЕ", null) || begin.isValue("СОДЕРЖИМОЕ", null)) {
            t = begin;
            if (t.next !== null && t.next.isCharOf(":.")) 
                t = t.next;
            if (t === end) 
                return true;
        }
        if (begin.isValue("ОТ", "ВІД") && begin.next !== null && begin.next.isValue("РЕДАКЦИЯ", "РЕДАКЦІЯ")) {
            if (begin.next.next !== null && begin.next.next.isChar(':')) 
                return true;
        }
        let words = 0;
        let verbs = 0;
        for (t = begin; t !== end.next; t = t.next) {
            if (t instanceof TextToken) {
                if (t.chars.isLetter) 
                    words++;
                if (t.chars.isAllLower && t.isPureVerb) 
                    verbs++;
            }
        }
        if (words > 10 && verbs > 1) 
            return true;
        return false;
    }
    
    static tryParse(begin, end, minNewlinesCount) {
        let res = new TitleNameToken(begin, end);
        if (!res.calcRankAndValue(minNewlinesCount)) 
            return null;
        if (res.beginNameToken === null || res.endNameToken === null) 
            return null;
        return res;
    }
    
    calcRankAndValue(minNewlinesCount) {
        this.rank = 0;
        if (this.beginToken.chars.isAllLower) 
            this.rank -= 30;
        let words = 0;
        let upWords = 0;
        let notwords = 0;
        let lineNumber = 0;
        let tstart = this.beginToken;
        let tend = this.endToken;
        for (let t = this.beginToken; t !== this.endToken.next && t !== null && t.endChar <= this.endToken.endChar; t = t.next) {
            if (t.isNewlineBefore) {
            }
            let tit = TitleItemToken.tryAttach(t);
            if (tit !== null) {
                if (tit.typ === TitleItemTokenTypes.THEME || tit.typ === TitleItemTokenTypes.TYPANDTHEME) {
                    if (t !== this.beginToken) {
                        if (lineNumber > 0) 
                            return false;
                        words = (upWords = (notwords = 0));
                        tstart = tit.endToken.next;
                    }
                    t = tit.endToken;
                    if (t.next === null) 
                        return false;
                    if (t.next.chars.isLetter && t.next.chars.isAllLower) 
                        this.rank += 20;
                    else 
                        this.rank += 100;
                    tstart = t.next;
                    if (tit.typ === TitleItemTokenTypes.TYPANDTHEME) 
                        this.typeValue = tit.value;
                    continue;
                }
                if (tit.typ === TitleItemTokenTypes.TYP) {
                    if (t === this.beginToken) {
                        if (tit.endToken.isNewlineAfter) {
                            this.typeValue = tit.value;
                            this.rank += 5;
                            tstart = tit.endToken.next;
                        }
                    }
                    t = tit.endToken;
                    words++;
                    if (tit.beginToken !== tit.endToken) 
                        words++;
                    if (tit.chars.isAllUpper) 
                        upWords++;
                    continue;
                }
                if (tit.typ === TitleItemTokenTypes.DUST || tit.typ === TitleItemTokenTypes.SPECIALITY) {
                    if (t === this.beginToken) 
                        return false;
                    this.rank -= 20;
                    if (tit.typ === TitleItemTokenTypes.SPECIALITY) 
                        this.speciality = tit.value;
                    t = tit.endToken;
                    continue;
                }
                if (tit.typ === TitleItemTokenTypes.CONSULTANT || tit.typ === TitleItemTokenTypes.BOSS || tit.typ === TitleItemTokenTypes.EDITOR) {
                    t = tit.endToken;
                    if (t.next !== null && ((t.next.isCharOf(":") || t.next.isHiphen || t.whitespacesAfterCount > 4))) 
                        this.rank -= 10;
                    else 
                        this.rank -= 2;
                    continue;
                }
                return false;
            }
            let blt = BookLinkToken.tryParse(t, 0);
            if (blt !== null) {
                if (blt.typ === BookLinkTyp.MISC || blt.typ === BookLinkTyp.N || blt.typ === BookLinkTyp.PAGES) 
                    this.rank -= 10;
                else if (blt.typ === BookLinkTyp.N || blt.typ === BookLinkTyp.PAGERANGE) 
                    this.rank -= 20;
            }
            if (t === this.beginToken && BookLinkToken.tryParseAuthor(t, FioTemplateType.UNDEFINED) !== null) 
                this.rank -= 20;
            if (t.isNewlineBefore && t !== this.beginToken) {
                lineNumber++;
                if (lineNumber > 4) 
                    return false;
                if (t.chars.isAllLower) 
                    this.rank += 10;
                else if (t.previous.isChar('.')) 
                    this.rank -= 10;
                else if (t.previous.isCharOf(",-")) 
                    this.rank += 10;
                else {
                    let npt = NounPhraseHelper.tryParse(t.previous, NounPhraseParseAttr.NO, 0, null);
                    if (npt !== null && npt.endChar >= t.endChar) 
                        this.rank += 10;
                }
            }
            if (t !== this.beginToken && t.newlinesBeforeCount > minNewlinesCount) 
                this.rank -= (t.newlinesBeforeCount - minNewlinesCount);
            let bst = BracketHelper.tryParse(t, BracketParseAttr.NO, 100);
            if (bst !== null && bst.isQuoteType && bst.endToken.endChar <= this.endToken.endChar) {
                if (words === 0) {
                    tstart = bst.beginToken;
                    this.rank += 10;
                    if (bst.endToken === this.endToken) {
                        tend = this.endToken;
                        this.rank += 10;
                    }
                }
            }
            let rli = t.getReferents();
            if (rli !== null) {
                for (const r of rli) {
                    if (r instanceof OrganizationReferent) {
                        if (t.isNewlineBefore) 
                            this.rank -= 10;
                        else 
                            this.rank -= 4;
                        continue;
                    }
                    if ((r instanceof GeoReferent) || (r instanceof PersonReferent)) {
                        if (t.isNewlineBefore) {
                            this.rank -= 5;
                            if (t.isNewlineAfter || t.next === null) 
                                this.rank -= 20;
                            else if (t.next.isHiphen || (t.next instanceof NumberToken) || (t.next.getReferent() instanceof DateReferent)) 
                                this.rank -= 20;
                            else if (t !== this.beginToken) 
                                this.rank -= 20;
                        }
                        continue;
                    }
                    if ((r instanceof GeoReferent) || (r instanceof DenominationReferent)) 
                        continue;
                    if ((r instanceof UriReferent) || (r instanceof PhoneReferent)) 
                        return false;
                    if (t.isNewlineBefore) 
                        this.rank -= 4;
                    else 
                        this.rank -= 2;
                    if (t === this.beginToken && (this.endToken.getReferent() instanceof PersonReferent)) 
                        this.rank -= 10;
                }
                words++;
                if (t.chars.isAllUpper) 
                    upWords++;
                if (t === this.beginToken) {
                    if (t.isNewlineAfter) 
                        this.rank -= 10;
                    else if (t.next !== null && t.next.isChar('.') && t.next.isNewlineAfter) 
                        this.rank -= 10;
                }
                continue;
            }
            if (t instanceof NumberToken) {
                if (t.typ === NumberSpellingType.WORDS) {
                    words++;
                    if (t.chars.isAllUpper) 
                        upWords++;
                }
                else 
                    notwords++;
                continue;
            }
            let pat = PersonAttrToken.tryAttach(t, PersonAttrTokenPersonAttrAttachAttrs.NO);
            if (pat !== null) {
                if (t.isNewlineBefore) {
                    if (!pat.morph._case.isUndefined && !pat.morph._case.isNominative) {
                    }
                    else if (pat.chars.isAllUpper) {
                    }
                    else 
                        this.rank -= 20;
                }
                else if (t.chars.isAllLower) 
                    this.rank--;
                for (; t !== null; t = t.next) {
                    words++;
                    if (t.chars.isAllUpper) 
                        upWords++;
                    if (t === pat.endToken) 
                        break;
                }
                continue;
            }
            let oitt = OrgItemTypeToken.tryAttach(t, true);
            if (oitt !== null) {
                if (oitt.morph.number !== MorphNumber.PLURAL && !oitt.isDoubtRootWord) {
                    if (!oitt.morph._case.isUndefined && !oitt.morph._case.isNominative) {
                        words++;
                        if (t.chars.isAllUpper) 
                            upWords++;
                    }
                    else {
                        this.rank -= 4;
                        if (t === this.beginToken) 
                            this.rank -= 5;
                    }
                }
                else {
                    words += 1;
                    if (t.chars.isAllUpper) 
                        upWords++;
                }
                t = oitt.endToken;
                continue;
            }
            let tt = Utils.as(t, TextToken);
            if (tt !== null) {
                if (tt.isChar('©')) 
                    this.rank -= 10;
                if (tt.isChar('_')) 
                    this.rank--;
                if (tt.chars.isLetter) {
                    if (tt.lengthChar > 2) {
                        words++;
                        if (t.chars.isAllUpper) 
                            upWords++;
                    }
                }
                else if (!tt.isChar(',')) 
                    notwords++;
                if (tt.isPureVerb) {{
                            this.rank -= 30;
                            words--;
                        }
                    break;
                }
                if (tt === this.endToken) {
                    if (tt.morph._class.isPreposition || tt.morph._class.isConjunction) 
                        this.rank -= 10;
                    else if (tt.isChar('.')) 
                        this.rank += 5;
                }
                else if (tt.isCharOf("._")) 
                    this.rank -= 5;
            }
        }
        this.rank += words;
        this.rank -= notwords;
        if ((words < 1) && (this.rank < 50)) 
            return false;
        if (tstart === null || tend === null) 
            return false;
        if (tstart.endChar > tend.endChar) 
            return false;
        let tit1 = TitleItemToken.tryAttach(this.endToken.next);
        if (tit1 !== null && ((tit1.typ === TitleItemTokenTypes.TYP || tit1.typ === TitleItemTokenTypes.SPECIALITY))) {
            if (tit1.endToken.isNewlineAfter) 
                this.rank += 15;
            else 
                this.rank += 10;
            if (tit1.typ === TitleItemTokenTypes.SPECIALITY) 
                this.speciality = tit1.value;
        }
        if (upWords > 4 && upWords > (Math.floor((0.8 * (words))))) {
            if (tstart.previous !== null && (tstart.previous.getReferent() instanceof PersonReferent)) 
                this.rank += (5 + upWords);
        }
        this.beginNameToken = tstart;
        this.endNameToken = tend;
        return true;
    }
}


module.exports = TitleNameToken