/*
 * 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 TitleItemTokenTypes = require("./internal/TitleItemTokenTypes");
const Token = require("./../Token");
const TerminParseAttr = require("./../core/TerminParseAttr");
const PersonRelations = require("./internal/PersonRelations");
const PersonReferent = require("./../person/PersonReferent");
const MetaToken = require("./../MetaToken");
const TextToken = require("./../TextToken");
const UriReferent = require("./../uri/UriReferent");
const DateReferent = require("./../date/DateReferent");
const BracketHelper = require("./../core/BracketHelper");
const OrganizationKind = require("./../org/OrganizationKind");
const GeoReferent = require("./../geo/GeoReferent");
const Termin = require("./../core/Termin");
const OrganizationReferent = require("./../org/OrganizationReferent");
const TitlePageReferent = require("./TitlePageReferent");
const PullentiNerBooklinkInternalResourceHelper = require("./../booklink/internal/PullentiNerBooklinkInternalResourceHelper");
const ReferentToken = require("./../ReferentToken");
const MorphLang = require("./../../morph/MorphLang");
const MetaTitleInfo = require("./internal/MetaTitleInfo");
const ProcessorService = require("./../ProcessorService");
const TextAnnotation = require("./../TextAnnotation");
const Referent = require("./../Referent");
const Line = require("./internal/Line");
const Analyzer = require("./../Analyzer");
const TitleNameToken = require("./internal/TitleNameToken");
const TitleItemToken = require("./internal/TitleItemToken");
const DateAnalyzer = require("./../date/DateAnalyzer");

/**
 * Анализатор титульной информации - название произведения, авторы, год и другие книжные атрибуты. 
 * Специфический анализатор, то есть нужно явно создавать процессор через функцию CreateSpecificProcessor, 
 * указав имя анализатора.
 */
class TitlePageAnalyzer extends Analyzer {
    
    get name() {
        return TitlePageAnalyzer.ANALYZER_NAME;
    }
    
    get caption() {
        return "Титульный лист";
    }
    
    get description() {
        return "Информация из титульных страниц и из заголовков статей, научных работ, дипломов и т.д.";
    }
    
    clone() {
        return new TitlePageAnalyzer();
    }
    
    get isSpecific() {
        return true;
    }
    
    get progressWeight() {
        return 1;
    }
    
    get typeSystem() {
        return [MetaTitleInfo.globalMeta];
    }
    
    get images() {
        let res = new Hashtable();
        res.put(MetaTitleInfo.TITLE_INFO_IMAGE_ID, PullentiNerBooklinkInternalResourceHelper.getBytes("titleinfo.png"));
        return res;
    }
    
    createReferent(type) {
        if (type === TitlePageReferent.OBJ_TYPENAME) 
            return new TitlePageReferent();
        return null;
    }
    
    processReferent1(begin, end) {
        let et = null;
        let wrapet3546 = new RefOutArgWrapper();
        let tpr = TitlePageAnalyzer._process(begin, (end === null ? 0 : end.endChar), begin.kit, wrapet3546);
        et = wrapet3546.value;
        if (tpr === null) 
            return null;
        return new ReferentToken(tpr, begin, et);
    }
    
    process(kit) {
        let ad = kit.getAnalyzerData(this);
        let et = null;
        let wrapet3547 = new RefOutArgWrapper();
        let tpr = TitlePageAnalyzer._process(kit.firstToken, 0, kit, wrapet3547);
        et = wrapet3547.value;
        if (tpr !== null) 
            ad.registerReferent(tpr);
    }
    
    static _process(begin, maxCharPos, kit, endToken) {
        endToken.value = begin;
        let res = new TitlePageReferent();
        let term = null;
        let lines = Line.parse(begin, 30, 1500, maxCharPos);
        if (lines.length < 1) 
            return null;
        let cou = lines.length;
        let minNewlinesCount = 10;
        let linesCountStat = new Hashtable();
        for (let i = 0; i < lines.length; i++) {
            if (TitleNameToken.canBeStartOfTextOrContent(lines[i].beginToken, lines[i].endToken)) {
                cou = i;
                break;
            }
            let j = lines[i].newlinesBeforeCount;
            if (i > 0 && j > 0) {
                if (!linesCountStat.containsKey(j)) 
                    linesCountStat.put(j, 1);
                else 
                    linesCountStat.put(j, linesCountStat.get(j) + 1);
            }
        }
        let max = 0;
        for (const kp of linesCountStat.entries) {
            if (kp.value > max) {
                max = kp.value;
                minNewlinesCount = kp.key;
            }
        }
        let endChar = (cou > 0 ? lines[cou - 1].endChar : 0);
        if (maxCharPos > 0 && endChar > maxCharPos) 
            endChar = maxCharPos;
        let names = new Array();
        for (let i = 0; i < cou; i++) {
            if (i === 6) {
            }
            for (let j = i; (j < cou) && (j < (i + 5)); j++) {
                if (i === 6 && j === 8) {
                }
                if (j > i) {
                    if (lines[j - 1].isPureEn && lines[j].isPureRu) 
                        break;
                    if (lines[j - 1].isPureRu && lines[j].isPureEn) 
                        break;
                    if (lines[j].newlinesBeforeCount >= (minNewlinesCount * 2)) 
                        break;
                }
                let ttt = TitleNameToken.tryParse(lines[i].beginToken, lines[j].endToken, minNewlinesCount);
                if (ttt !== null) {
                    if (lines[i].isPureEn) 
                        ttt.morph.language = MorphLang.EN;
                    else if (lines[i].isPureRu) 
                        ttt.morph.language = MorphLang.RU;
                    names.push(ttt);
                }
            }
        }
        TitleNameToken.sort(names);
        let nameRt = null;
        if (names.length > 0) {
            let i0 = 0;
            if (names[i0].morph.language.isEn) {
                for (let ii = 1; ii < names.length; ii++) {
                    if (names[ii].morph.language.isRu && names[ii].rank > 0) {
                        i0 = ii;
                        break;
                    }
                }
            }
            term = res.addName(names[i0].beginNameToken, names[i0].endNameToken);
            if (names[i0].typeValue !== null) 
                res.addType(names[i0].typeValue);
            if (names[i0].speciality !== null) 
                res.speciality = names[i0].speciality;
            let rt = new ReferentToken(res, names[i0].beginToken, names[i0].endToken);
            if (kit !== null) 
                kit.embedToken(rt);
            else 
                res.addOccurence(new TextAnnotation(rt.beginToken, rt.endToken));
            endToken.value = rt.endToken;
            nameRt = rt;
            if (begin.beginChar === rt.beginChar) 
                begin = rt;
        }
        if (term !== null && kit !== null) {
            for (let t = kit.firstToken; t !== null; t = t.next) {
                let tok = term.tryParse(t, TerminParseAttr.NO);
                if (tok === null) 
                    continue;
                let t0 = t;
                let t1 = tok.endToken;
                if (t1.next !== null && t1.next.isChar('.')) 
                    t1 = t1.next;
                if (BracketHelper.canBeStartOfSequence(t0.previous, false, false) && BracketHelper.canBeEndOfSequence(t1.next, false, null, false)) {
                    t0 = t0.previous;
                    t1 = t1.next;
                }
                let rt = new ReferentToken(res, t0, t1);
                kit.embedToken(rt);
                t = rt;
            }
        }
        let pr = new PersonRelations();
        let persTyp = TitleItemTokenTypes.UNDEFINED;
        let persTypes = pr.relTypes;
        for (let t = begin; t !== null; t = t.next) {
            if (maxCharPos > 0 && t.beginChar > maxCharPos) 
                break;
            if (t === nameRt) 
                continue;
            let tpt = TitleItemToken.tryAttach(t);
            if (tpt !== null) {
                persTyp = TitleItemTokenTypes.UNDEFINED;
                if (tpt.typ === TitleItemTokenTypes.TYP) {
                    if (res.types.length === 0) 
                        res.addType(tpt.value);
                    else if (res.types.length === 1) {
                        let ty = res.types[0].toUpperCase();
                        if (ty === "РЕФЕРАТ") 
                            res.addType(tpt.value);
                        else if (ty === "АВТОРЕФЕРАТ") {
                            if (tpt.value === "КАНДИДАТСКАЯ ДИССЕРТАЦИЯ") 
                                res.addSlot(TitlePageReferent.ATTR_TYPE, "автореферат кандидатской диссертации", true, 0);
                            else if (tpt.value === "ДОКТОРСКАЯ ДИССЕРТАЦИЯ") 
                                res.addSlot(TitlePageReferent.ATTR_TYPE, "автореферат докторской диссертации", true, 0);
                            else if (tpt.value === "МАГИСТЕРСКАЯ ДИССЕРТАЦИЯ") 
                                res.addSlot(TitlePageReferent.ATTR_TYPE, "автореферат магистерской диссертации", true, 0);
                            else if (tpt.value === "КАНДИДАТСЬКА ДИСЕРТАЦІЯ") 
                                res.addSlot(TitlePageReferent.ATTR_TYPE, "автореферат кандидатської дисертації", true, 0);
                            else if (tpt.value === "ДОКТОРСЬКА ДИСЕРТАЦІЯ") 
                                res.addSlot(TitlePageReferent.ATTR_TYPE, "автореферат докторської дисертації", true, 0);
                            else if (tpt.value === "МАГІСТЕРСЬКА ДИСЕРТАЦІЯ") 
                                res.addSlot(TitlePageReferent.ATTR_TYPE, "автореферат магістерської дисертації", true, 0);
                            else 
                                res.addType(tpt.value);
                        }
                        else if (tpt.value === "РЕФЕРАТ" || tpt.value === "АВТОРЕФЕРАТ") {
                            if (!ty.includes(tpt.value)) 
                                res.addType(tpt.value);
                        }
                    }
                }
                else if (tpt.typ === TitleItemTokenTypes.SPECIALITY) {
                    if (res.speciality === null) 
                        res.speciality = tpt.value;
                }
                else if (persTypes.includes(tpt.typ)) 
                    persTyp = tpt.typ;
                t = tpt.endToken;
                if (t.endChar > endToken.value.endChar) 
                    endToken.value = t;
                if (t.next !== null && t.next.isCharOf(":-")) 
                    t = t.next;
                continue;
            }
            if (t.endChar > endChar) 
                break;
            let rli = t.getReferents();
            if (rli === null) 
                continue;
            if (!t.isNewlineBefore && (t.previous instanceof TextToken)) {
                let s = t.previous.term;
                if (s === "ИМЕНИ" || s === "ИМ") 
                    continue;
                if (s === "." && t.previous.previous !== null && t.previous.previous.isValue("ИМ", null)) 
                    continue;
            }
            for (const r of rli) {
                if (r instanceof PersonReferent) {
                    if (r !== rli[0]) 
                        continue;
                    let p = Utils.as(r, PersonReferent);
                    if (persTyp !== TitleItemTokenTypes.UNDEFINED) {
                        if (t.previous !== null && t.previous.isChar('.')) 
                            persTyp = TitleItemTokenTypes.UNDEFINED;
                    }
                    let typ = pr.calcTypFromAttrs(p);
                    if (typ !== TitleItemTokenTypes.UNDEFINED) {
                        pr.add(p, typ, 1);
                        persTyp = typ;
                    }
                    else if (persTyp !== TitleItemTokenTypes.UNDEFINED) 
                        pr.add(p, persTyp, 1);
                    else if (t.previous !== null && t.previous.isChar('©')) {
                        persTyp = TitleItemTokenTypes.WORKER;
                        pr.add(p, persTyp, 1);
                    }
                    else {
                        for (let tt = t.next; tt !== null; tt = tt.next) {
                            let rr = tt.getReferent();
                            if (rr === res) {
                                persTyp = TitleItemTokenTypes.WORKER;
                                break;
                            }
                            if (rr instanceof PersonReferent) {
                                if (pr.calcTypFromAttrs(Utils.as(r, PersonReferent)) !== TitleItemTokenTypes.UNDEFINED) 
                                    break;
                                else 
                                    continue;
                            }
                            if (rr !== null) 
                                break;
                            tpt = TitleItemToken.tryAttach(tt);
                            if (tpt !== null) {
                                if (tpt.typ !== TitleItemTokenTypes.TYP && tpt.typ !== TitleItemTokenTypes.TYPANDTHEME) 
                                    break;
                                tt = tpt.endToken;
                                if (tt.endChar > endToken.value.endChar) 
                                    endToken.value = tt;
                                continue;
                            }
                        }
                        if (persTyp === TitleItemTokenTypes.UNDEFINED) {
                            for (let tt = t.previous; tt !== null; tt = tt.previous) {
                                let rr = tt.getReferent();
                                if (rr === res) {
                                    persTyp = TitleItemTokenTypes.WORKER;
                                    break;
                                }
                                if (rr !== null) 
                                    break;
                                if ((tt.isValue("СТУДЕНТ", null) || tt.isValue("СТУДЕНТКА", null) || tt.isValue("СЛУШАТЕЛЬ", null)) || tt.isValue("ДИПЛОМНИК", null) || tt.isValue("ИСПОЛНИТЕЛЬ", null)) {
                                    persTyp = TitleItemTokenTypes.WORKER;
                                    break;
                                }
                                tpt = TitleItemToken.tryAttach(tt);
                                if (tpt !== null && tpt.typ !== TitleItemTokenTypes.TYP) 
                                    break;
                            }
                        }
                        if (persTyp !== TitleItemTokenTypes.UNDEFINED) 
                            pr.add(p, persTyp, 1);
                        else 
                            pr.add(p, persTyp, 0.5);
                        if (t.endChar > endToken.value.endChar) 
                            endToken.value = t;
                    }
                    continue;
                }
                if (r === rli[0]) 
                    persTyp = TitleItemTokenTypes.UNDEFINED;
                if (r instanceof DateReferent) {
                    if (res.date === null) {
                        res.date = Utils.as(r, DateReferent);
                        if (res.date.findSlot(DateReferent.ATTR_HOUR, null, true) !== null && res.date.higher !== null) 
                            res.date = res.date.higher;
                        if (t.endChar > endToken.value.endChar) 
                            endToken.value = t;
                    }
                }
                else if (r instanceof GeoReferent) {
                    if (res.city === null && r.isCity) {
                        res.city = Utils.as(r, GeoReferent);
                        if (t.endChar > endToken.value.endChar) 
                            endToken.value = t;
                    }
                }
                if (r instanceof OrganizationReferent) {
                    let _org = Utils.as(r, OrganizationReferent);
                    if (_org.types.includes("курс") && _org.number !== null) {
                        let i = 0;
                        let wrapi3548 = new RefOutArgWrapper();
                        let inoutres3549 = Utils.tryParseInt(_org.number, wrapi3548);
                        i = wrapi3548.value;
                        if (inoutres3549) {
                            if (i > 0 && (i < 8)) 
                                res.studentYear = i;
                        }
                    }
                    for (; _org.higher !== null; _org = _org.higher) {
                        if (_org.kind !== OrganizationKind.DEPARTMENT) 
                            break;
                    }
                    if (_org.kind !== OrganizationKind.DEPARTMENT) {
                        if (res.org === null) 
                            res.org = _org;
                        else if (OrganizationReferent.canBeHigher(res.org, _org)) 
                            res.org = _org;
                    }
                    if (t.endChar > endToken.value.endChar) 
                        endToken.value = t;
                }
                if ((r instanceof UriReferent) || (r instanceof GeoReferent)) {
                    if (t.endChar > endToken.value.endChar) 
                        endToken.value = t;
                }
            }
        }
        for (const ty of persTypes) {
            for (const p of pr.getPersons(ty)) {
                if (pr.getAttrNameForType(ty) !== null) 
                    res.addSlot(pr.getAttrNameForType(ty), p, false, 0);
            }
        }
        if (res.getSlotValue(TitlePageReferent.ATTR_AUTHOR) === null) {
            for (const p of pr.getPersons(TitleItemTokenTypes.UNDEFINED)) {
                res.addSlot(TitlePageReferent.ATTR_AUTHOR, p, false, 0);
                break;
            }
        }
        if (res.city === null && res.org !== null) {
            let s = res.org.findSlot(OrganizationReferent.ATTR_GEO, null, true);
            if (s !== null && (s.value instanceof GeoReferent)) {
                if (s.value.isCity) 
                    res.city = Utils.as(s.value, GeoReferent);
            }
        }
        if (res.date === null) {
            for (let t = begin; t !== null && t.endChar <= endChar; t = t.next) {
                let city = Utils.as(t.getReferent(), GeoReferent);
                if (city === null) 
                    continue;
                if (t.next instanceof TextToken) {
                    if (t.next.isCharOf(":,") || t.next.isHiphen) 
                        t = t.next;
                }
                let rt = t.kit.processReferent(DateAnalyzer.ANALYZER_NAME, t.next, null);
                if (rt !== null) {
                    rt.saveToLocalOntology();
                    res.date = Utils.as(rt.referent, DateReferent);
                    if (kit !== null) 
                        kit.embedToken(rt);
                    break;
                }
            }
        }
        if (res.slots.length === 0) 
            return null;
        else 
            return res;
    }
    
    static initialize() {
        if (TitlePageAnalyzer.m_Inited) 
            return;
        TitlePageAnalyzer.m_Inited = true;
        MetaTitleInfo.initialize();
        try {
            Termin.ASSIGN_ALL_TEXTS_AS_NORMAL = true;
            TitleItemToken.initialize();
            Termin.ASSIGN_ALL_TEXTS_AS_NORMAL = false;
        } catch (ex) {
            throw new Error(ex.message);
        }
        ProcessorService.registerAnalyzer(new TitlePageAnalyzer());
    }
    
    static static_constructor() {
        TitlePageAnalyzer.ANALYZER_NAME = "TITLEPAGE";
        TitlePageAnalyzer.m_Inited = false;
    }
}


TitlePageAnalyzer.static_constructor();

module.exports = TitlePageAnalyzer