/*
 * 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 OrgProfile = require("./../org/OrgProfile");
const OrganizationReferent = require("./../org/OrganizationReferent");
const TerminParseAttr = require("./../core/TerminParseAttr");
const NumberToken = require("./../NumberToken");
const Token = require("./../Token");
const PersonIdentityReferent = require("./../person/PersonIdentityReferent");
const NounPhraseParseAttr = require("./../core/NounPhraseParseAttr");
const MoneyReferent = require("./../money/MoneyReferent");
const DateRangeReferent = require("./../date/DateRangeReferent");
const MorphGender = require("./../../morph/MorphGender");
const PersonPropertyReferent = require("./../person/PersonPropertyReferent");
const PersonAttrTokenPersonAttrAttachAttrs = require("./../person/internal/PersonAttrTokenPersonAttrAttachAttrs");
const GetTextAttr = require("./../core/GetTextAttr");
const VacanceTokenType = require("./../vacance/internal/VacanceTokenType");
const MorphNumber = require("./../../morph/MorphNumber");
const BracketParseAttr = require("./../core/BracketParseAttr");
const TextToken = require("./../TextToken");
const ReferentToken = require("./../ReferentToken");
const MiscHelper = require("./../core/MiscHelper");
const BracketHelper = require("./../core/BracketHelper");
const ResumeItemType = require("./ResumeItemType");
const PersonReferent = require("./../person/PersonReferent");
const ResourceHelper3 = require("./../core/internal/ResourceHelper3");
const PersonAttrToken = require("./../person/internal/PersonAttrToken");
const ProcessorService = require("./../ProcessorService");
const Analyzer = require("./../Analyzer");
const Referent = require("./../Referent");
const GeoReferent = require("./../geo/GeoReferent");
const ResumeItemReferent = require("./ResumeItemReferent");
const StreetReferent = require("./../address/StreetReferent");
const AddressReferent = require("./../address/AddressReferent");
const MetaResume = require("./MetaResume");
const NumberHelper = require("./../core/NumberHelper");
const MetaToken = require("./../MetaToken");
const NounPhraseHelper = require("./../core/NounPhraseHelper");
const UriReferent = require("./../uri/UriReferent");
const DateReferent = require("./../date/DateReferent");
const VacanceToken = require("./../vacance/internal/VacanceToken");
const PhoneReferent = require("./../phone/PhoneReferent");

/**
 * Анализатор резюме (специфический анализатор)
 */
class ResumeAnalyzer extends Analyzer {
    
    get name() {
        return ResumeAnalyzer.ANALYZER_NAME;
    }
    
    get caption() {
        return "Резюме";
    }
    
    get description() {
        return "Текст содержит одно резюме";
    }
    
    clone() {
        return new ResumeAnalyzer();
    }
    
    get isSpecific() {
        return true;
    }
    
    get typeSystem() {
        return [MetaResume.GLOBAL_META];
    }
    
    get images() {
        let res = new Hashtable();
        res.put(MetaResume.IMAGE_ID.toString(), ResourceHelper3.getBytes("resume.png"));
        return res;
    }
    
    createReferent(type) {
        if (type === ResumeItemReferent.OBJ_TYPENAME) 
            return new ResumeItemReferent();
        return null;
    }
    
    get progressWeight() {
        return 1;
    }
    
    process(kit) {
        let ad = kit.getAnalyzerData(this);
        let hasSex = false;
        let hasMoney = false;
        let hasPos = false;
        let hasSpec = false;
        let hasSkills = false;
        let hasExp = false;
        let hasEdu = false;
        let hasAbout = false;
        let rt = null;
        let pers0 = null;
        let cou = 0;
        for (let t = kit.firstToken; t !== null; t = t.next) {
            let tt = MiscHelper.checkImage(t);
            if (tt !== null) {
                t = tt;
                continue;
            }
            let pers = Utils.as(t.getReferent(), PersonReferent);
            if (pers !== null) {
                if (!t.isNewlineBefore && cou > 10) 
                    break;
                if (cou > 10 && t.beginToken.isValue("ИП", null)) 
                    break;
                rt = new ReferentToken(ad.registerReferent(ResumeItemReferent._new3517(ResumeItemType.PERSON, pers)), t, t);
                kit.embedToken(rt);
                pers0 = pers;
                break;
            }
            if (t.lengthChar > 1) 
                cou++;
        }
        let opyt = false;
        let hasEduOrg = false;
        let curTyp = ResumeItemType.UNDEFINED;
        for (let t = kit.firstToken; t !== null; t = (t === null ? null : t.next)) {
            if (pers0 !== null) {
                if ((t.getReferent() instanceof UriReferent) || (t.getReferent() instanceof PhoneReferent) || (t.getReferent() instanceof AddressReferent)) {
                    let uri = Utils.as(t.getReferent(), UriReferent);
                    if (uri !== null) {
                        if (uri.scheme !== "mailto" && uri.scheme !== "telegram") 
                            continue;
                        if (uri.value.includes("rating@mail.ru")) 
                            continue;
                    }
                    rt = new ReferentToken(ad.registerReferent(ResumeItemReferent._new3517(ResumeItemType.CONTACT, t.getReferent())), t, t);
                    kit.embedToken(rt);
                    continue;
                }
            }
            if (pers0 !== null && !opyt) {
                if ((t.getReferent() instanceof GeoReferent) || (t.getReferent() instanceof StreetReferent)) {
                    let _geo = Utils.as(t.getReferent(), GeoReferent);
                    if (_geo !== null && !_geo.isCity) 
                        continue;
                    rt = new ReferentToken(ad.registerReferent(ResumeItemReferent._new3517(ResumeItemType.CONTACT, t.getReferent())), t, t);
                    kit.embedToken(rt);
                    continue;
                }
            }
            if (t.isValue("КОНТАКТЫ", null)) {
            }
            if (t.isValue2("ДАТА", "РОЖДЕНИЯ") || t.isValue("РОДИТЬСЯ", null)) {
                for (let tt = t.next; tt !== null; tt = tt.next) {
                    let r = tt.getReferent();
                    if (r instanceof DateReferent) {
                        if (pers0 !== null) 
                            pers0.addSlot(PersonReferent.ATTR_BORN, r, false, 0);
                        else {
                        }
                        break;
                    }
                    if (tt.isValue("РОЖДЕНИЕ", null)) 
                        continue;
                    if (tt.getReferent() instanceof GeoReferent) 
                        continue;
                    if (tt.lengthChar > 1) 
                        break;
                }
                continue;
            }
            if (t.getReferent() instanceof PersonIdentityReferent) {
                rt = new ReferentToken(ad.registerReferent(ResumeItemReferent._new3517(ResumeItemType.DOCUMENT, t.getReferent())), t, t);
                kit.embedToken(rt);
                t = rt;
                continue;
            }
            if (!t.isNewlineBefore) 
                continue;
            if (t.isTableControlChar && t.next !== null) 
                t = t.next;
            if (t.isValue("ОБРАЗОВАНИЕ", null)) 
                curTyp = ResumeItemType.STUDY;
            if (t.isValue2("ОПЫТ", "РАБОТЫ") || t.isValue2("МЕСТО", "РАБОТЫ") || t.isValue2("ПЕРИОД", "РАБОТЫ")) {
                opyt = true;
                curTyp = ResumeItemType.ORGANIZATION;
            }
            rt = ResumeAnalyzer._parseOrg(t, curTyp);
            if (rt !== null) {
                rt.referent = ad.registerReferent(rt.referent);
                rt.referent.tag = rt;
                kit.embedToken(rt);
                curTyp = rt.referent.typ;
                if (curTyp === ResumeItemType.STUDY) 
                    hasEduOrg = true;
                t = rt;
                continue;
            }
            rt = ResumeAnalyzer._parseOrg2(t, ad, null);
            if (rt !== null) {
                t = rt;
                curTyp = ResumeItemType.ORGANIZATION;
                continue;
            }
            if (!hasSex) {
                rt = ResumeAnalyzer._parseSex(t, ad);
                if (rt !== null) {
                    hasSex = true;
                    t = rt;
                    continue;
                }
            }
            if (ResumeAnalyzer._checkGeo(t)) 
                continue;
            if (!hasMoney && (t.getReferent() instanceof MoneyReferent)) {
                let _money = new ResumeItemReferent();
                hasMoney = true;
                _money.typ = ResumeItemType.MONEY;
                _money.ref = t.getReferent();
                rt = new ReferentToken(ad.registerReferent(_money), t, t);
                kit.embedToken(rt);
                t = rt;
                continue;
            }
            if (!hasExp) {
                rt = ResumeAnalyzer._parseExperience(t, ad);
                if (rt !== null) {
                    hasExp = true;
                    t = rt;
                    continue;
                }
            }
            if (!hasSpec && t.isValue("СПЕЦИАЛИЗАЦИЯ", null)) {
                if (t.next !== null && t.next.isChar(':')) 
                    t = t.next;
                rt = ResumeAnalyzer._parseList(t.next, ad, ResumeItemType.SPECIALITY);
                if (rt !== null) {
                    hasSpec = true;
                    t = rt;
                    continue;
                }
            }
            let npt = NounPhraseHelper.tryParse(t, NounPhraseParseAttr.NO, 0, null);
            if (npt !== null && ((npt.endToken.isValue("НАВЫК", null) || npt.endToken.isValue("КОМПЕТЕНЦИЯ", null)))) {
                let tt = npt.endToken.next;
                if (tt !== null && tt.isValue2("И", "ДОСТИЖЕНИЕ")) 
                    tt = tt.next.next;
                rt = ResumeAnalyzer._parseList(tt, ad, ResumeItemType.SKILL);
                if (rt !== null) {
                    hasSkills = true;
                    t = rt;
                    continue;
                }
            }
            if (!hasAbout && (((t.isValue2("О", "МНЕ") || t.isValue2("О", "СЕБЕ") || t.isValue2("ЛИЧНЫЕ", "КАЧЕСТВА")) || t.isValue2("ДОПОЛНИТЕЛЬНЫЕ", "СВЕДЕНИЯ")))) {
                rt = ResumeAnalyzer._parseAboutMe(t.next.next, ad);
                if (rt !== null) {
                    hasAbout = true;
                    t = rt;
                    continue;
                }
            }
            if (!hasSpec && hasSex && !hasPos) {
                rt = ResumeAnalyzer._parseList(t, ad, ResumeItemType.POSITION);
                if (rt !== null) {
                    hasPos = true;
                    t = rt;
                    continue;
                }
            }
            if (!hasEdu) {
                let mt = ResumeAnalyzer._parseEducation(t);
                if (mt !== null) {
                    curTyp = ResumeItemType.STUDY;
                    let edu = new ResumeItemReferent();
                    hasEdu = true;
                    edu.typ = ResumeItemType.EDUCATION;
                    edu.value = Utils.asString(mt.tag);
                    rt = new ReferentToken(ad.registerReferent(edu), mt.beginToken, mt.endToken);
                    kit.embedToken(rt);
                    t = rt;
                    continue;
                }
            }
            rt = ResumeAnalyzer._parseDriving(t, ad);
            if (rt !== null) {
                t = rt;
                continue;
            }
        }
        if (!hasEduOrg) {
            for (let t = kit.firstToken; t !== null; t = t.next) {
                let _org = Utils.as(t.getReferent(), OrganizationReferent);
                if (_org === null) 
                    continue;
                if (_org.profiles.includes(OrgProfile.EDUCATION) && !(_org.tag instanceof ResumeItemReferent)) {
                    let it = ad.registerReferent(ResumeItemReferent._new3517(ResumeItemType.STUDY, _org));
                    rt = new ReferentToken(it, t, t);
                    kit.embedToken(rt);
                    break;
                }
            }
        }
    }
    
    static _parseSex(t, ad) {
        if (t.isValue2("ПОЛНЫХ", "ЛЕТ")) {
            t = t.next.next;
            if (t !== null && t.isCharOf(":-")) 
                t = t.next;
            if (t instanceof NumberToken) {
                let age = new ResumeItemReferent();
                age.typ = ResumeItemType.AGE;
                age.value = t.value;
                let rt0 = new ReferentToken(ad.registerReferent(age), t, t);
                t.kit.embedToken(rt0);
                return rt0;
            }
        }
        if (!t.isValue("МУЖЧИНА", null) && !t.isValue("ЖЕНЩИНА", null)) 
            return null;
        let sex = new ResumeItemReferent();
        sex.typ = ResumeItemType.SEX;
        sex.value = (t.isValue("МУЖЧИНА", null) ? "муж" : "жен");
        let rt = new ReferentToken(ad.registerReferent(sex), t, t);
        t.kit.embedToken(rt);
        t = rt;
        for (let tt = t.next; tt !== null; tt = tt.next) {
            if (tt.isNewlineBefore) 
                break;
            if ((tt instanceof NumberToken) && tt.next !== null) {
                if (tt.next.isValue("ГОД", null) || tt.next.isValue("ЛЕТ", null)) {
                    let age = new ResumeItemReferent();
                    age.typ = ResumeItemType.AGE;
                    age.value = tt.value;
                    rt = new ReferentToken(ad.registerReferent(age), tt, tt.next);
                    t.kit.embedToken(rt);
                    t = rt;
                    break;
                }
            }
        }
        return rt;
    }
    
    static _parseExperience(t, ad) {
        if (!t.isValue2("ОПЫТ", "РАБОТЫ")) 
            return null;
        for (let tt = t.next; tt !== null; tt = tt.next) {
            if (tt.isNewlineBefore && !tt.previous.isCharOf(":-")) 
                break;
            if ((tt instanceof NumberToken) && tt.next !== null) {
                if (tt.next.isValue("ГОД", null) || tt.next.isValue("ЛЕТ", null) || tt.next.isValue("МЕСЯЦ", null)) {
                    let experience = new ResumeItemReferent();
                    experience.typ = ResumeItemType.EXPERIENCE;
                    experience.value = tt.value;
                    if (tt.next.isValue("МЕСЯЦ", null)) 
                        experience.value = NumberHelper.doubleToString(Utils.mathRound(tt.realValue / (12), 1));
                    let tt1 = tt.next;
                    if ((tt1.next instanceof NumberToken) && tt1.next.next !== null && tt1.next.next.isValue("МЕСЯЦ", null)) {
                        let d = Utils.mathRound(tt.realValue + ((tt1.next.realValue / (12))), 1);
                        experience.value = NumberHelper.doubleToString(d);
                        tt1 = tt1.next.next;
                    }
                    let rt = new ReferentToken(ad.registerReferent(experience), tt, tt1);
                    t.kit.embedToken(rt);
                    return rt;
                }
            }
        }
        return null;
    }
    
    static _parseEducation(t) {
        let hi = false;
        let middl = false;
        let prof = false;
        let spec = false;
        let tech = false;
        let neok = false;
        let _keyword = false;
        let t0 = t;
        let t1 = t;
        for (; t !== null; t = t.next) {
            if (t0 !== t && t.isNewlineBefore) {
                if (t.previous !== null && t.previous.isCharOf(":-")) {
                }
                else 
                    break;
            }
            if (t.isValue("СРЕДНИЙ", null) || t.isValue("СРЕДНЕ", null) || t.isValue("СРЕДН", null)) 
                middl = true;
            else if (t.isValue("ВЫСШИЙ", null) || t.isValue("ВЫСШ", null)) 
                hi = true;
            else if (t.isValue("НЕОКОНЧЕННЫЙ", null)) 
                neok = true;
            else if (t.isValue("ПРОФЕССИОНАЛЬНЫЙ", null) || t.isValue("ПРОФ", null) || t.isValue("ПРОФИЛЬНЫЙ", null)) 
                prof = true;
            else if ((t.isValue("СПЕЦИАЛЬНЫЙ", null) || t.isValue("СПЕЦ", null) || t.isValue2("ПО", "СПЕЦИАЛЬНОСТЬ")) || t.isValue2("ПО", "НАПРАВЛЕНИЕ")) 
                spec = true;
            else if ((t.isValue("ТЕХНИЧЕСКИЙ", null) || t.isValue("ТЕХ", null) || t.isValue("ТЕХН", null)) || t.isValue("ТЕХНИЧ", null)) 
                tech = true;
            else if (t.isValue("ОБРАЗОВАНИЕ", null)) {
                _keyword = true;
                t1 = t;
            }
            else if (t.lengthChar > 1) 
                break;
        }
        if (!_keyword) 
            return null;
        if (!hi && !middl) {
            if ((spec || prof || tech) || neok) 
                middl = true;
            else 
                return null;
        }
        let val = (hi ? "ВО" : "СО");
        if (spec) 
            val += ",спец";
        if (prof) 
            val += ",проф";
        if (tech) 
            val += ",тех";
        if (neok) 
            val += ",неоконч";
        return MetaToken._new663(t0, t1, val);
    }
    
    static _parseMoral(t) {
        let tok = VacanceToken.M_TERMINS.tryParse(t, TerminParseAttr.NO);
        if (tok === null || tok.termin.tag2 !== null) 
            return null;
        let ty = VacanceTokenType.of(tok.termin.tag);
        if (ty !== VacanceTokenType.MORAL) 
            return null;
        let val = (tok.termin.canonicText[0] + tok.termin.canonicText.substring(1).toLowerCase());
        let t1 = tok.endToken;
        for (let tt = tok.endToken.next; tt !== null; tt = tt.next) {
            if (tt.whitespacesBeforeCount > 2) 
                break;
            if (VacanceToken.M_TERMINS.tryParse(tt, TerminParseAttr.NO) !== null) 
                break;
            let npt = NounPhraseHelper.tryParse(tt, NounPhraseParseAttr.of((NounPhraseParseAttr.PARSEPREPOSITION.value()) | (NounPhraseParseAttr.PARSEPRONOUNS.value())), 0, null);
            if (npt === null) 
                break;
            tt = (t1 = npt.endToken);
        }
        if (t1.endChar > tok.endChar) 
            val = (val + " " + MiscHelper.getTextValue(tok.endToken.next, t1, GetTextAttr.of((GetTextAttr.KEEPQUOTES.value()) | (GetTextAttr.KEEPREGISTER.value()))));
        return MetaToken._new663(t, t1, val);
    }
    
    static _parseDriving(t, ad) {
        if (t === null) 
            return null;
        let t1 = null;
        if (t.isValue("НАЛИЧИЕ", null) && t.next !== null) 
            t = t.next;
        if ((t.isValue2("ВОДИТЕЛЬСКИЕ", "ПРАВА") || t.isValue2("ПРАВА", "КАТЕГОРИИ") || t.isValue2("ВОДИТЕЛЬСКОЕ", "УДОСТОВЕРЕНИЕ")) || t.isValue2("УДОСТОВЕРЕНИЕ", "ВОДИТЕЛЯ") || t.isValue2("ПРАВА", "ВОДИТЕЛЯ")) 
            t1 = t.next.next;
        if (t1 === null) 
            return null;
        let t0 = t;
        let val = null;
        for (t = t1; t !== null; t = t.next) {
            if ((t.isHiphen || t.isTableControlChar || t.isCharOf(":.")) || t.isValue("КАТЕГОРИЯ", null) || t.isValue("КАТ", null)) 
                continue;
            if ((t instanceof TextToken) && t.lengthChar <= 3 && t.chars.isLetter) {
                val = t.term;
                t1 = t;
                for (t = t.next; t !== null; t = t.next) {
                    if (t.whitespacesBeforeCount > 2) 
                        break;
                    else if (t.isChar('.') || t.isCommaAnd) 
                        continue;
                    else if (t.lengthChar === 1 && t.chars.isAllUpper && t.chars.isLetter) {
                        val = (val + t.term);
                        t1 = t;
                    }
                    else 
                        break;
                }
                val = Utils.replaceString(Utils.replaceString(Utils.replaceString(val, "А", "A"), "В", "B"), "С", "C");
                break;
            }
            break;
        }
        if (val === null) 
            return null;
        let drv = new ResumeItemReferent();
        drv.typ = ResumeItemType.DRIVINGLICENSE;
        drv.value = val;
        let rt = new ReferentToken(ad.registerReferent(drv), t0, t1);
        t0.kit.embedToken(rt);
        return rt;
    }
    
    static _parseOnto(t) {
        if (t === null) 
            return null;
        if (t.kit.ontology === null) 
            return null;
        let lii = t.kit.ontology.attachToken(ResumeAnalyzer.ANALYZER_NAME, t);
        if (lii === null || lii.length === 0) 
            return null;
        if (!(lii[0].item.referent instanceof ResumeItemReferent)) 
            return null;
        let val = lii[0].item.referent.value;
        val = (val[0] + val.substring(1).toLowerCase());
        return MetaToken._new663(t, lii[0].endToken, val);
    }
    
    static _startOfItem(t) {
        if (t === null) 
            return false;
        if (t.isTableControlChar && t.next !== null) 
            t = t.next;
        if (t.isNewlineBefore) {
        }
        else if (t.previous !== null && t.previous.isTableControlChar && t.previous.isNewlineBefore) {
        }
        else 
            return false;
        if (t.isValue2("О", "МНЕ") || t.isValue2("О", "СЕБЕ") || t.isValue2("ДОПОЛНИТЕЛЬНЫЕ", "СВЕДЕНИЯ")) 
            return true;
        if (t.isValue("ИНТЕРЕСНЫ", null)) 
            return true;
        let npt = NounPhraseHelper.tryParse(t, NounPhraseParseAttr.NO, 0, null);
        if (npt !== null) {
            let tt = npt.endToken;
            if ((((tt.isValue("КОНТАКТ", null) || tt.isValue("ТЕЛЕФОН", null) || tt.isValue("РЕЗЮМЕ", null)) || tt.isValue("ГРАФИК", null) || tt.isValue("ЗАНЯТОСТЬ", null)) || tt.isValue("ОПЫТ", null) || tt.isValue("ОБРАЗОВАНИЕ", null)) || tt.isValue("ИНФОРМАЦИЯ", null)) 
                return true;
            if (tt.isValue("НАВЫК", null)) {
                if (t.isValue("КЛЮЧЕВОЙ", null) || t.isValue("ПРОФЕССИОНАЛЬНЫЙ", null)) 
                    return true;
            }
            if (tt.isValue("КОМПЕТЕНЦИЯ", null)) 
                return true;
        }
        return false;
    }
    
    static _parseList(t, ad, typ) {
        let rt = null;
        let spec = null;
        for (; t !== null; t = t.next) {
            if (!t.isChar(':') && !t.isTableControlChar) 
                break;
        }
        if (t === null) 
            return null;
        let t0 = t;
        for (; t !== null; t = t.next) {
            if (t.isNewlineBefore) {
                if (t.newlinesBeforeCount > 1 && t !== t0) 
                    break;
                if (ResumeAnalyzer._startOfItem(t)) 
                    break;
                if (t === t0 && typ === ResumeItemType.POSITION) {
                }
                else if (typ === ResumeItemType.SKILL || typ === ResumeItemType.SPECIALITY) {
                }
                else 
                    break;
            }
            if (t.isCharOf(";,")) 
                continue;
            if (BracketHelper.canBeStartOfSequence(t, true, false)) {
                let br = BracketHelper.tryParse(t, BracketParseAttr.NO, 100);
                if (br !== null) {
                    spec = new ResumeItemReferent();
                    spec.typ = typ;
                    spec.value = ResumeAnalyzer._corrValue(MiscHelper.getTextValue(t.next, br.endToken.previous, GetTextAttr.of((GetTextAttr.KEEPQUOTES.value()) | (GetTextAttr.KEEPREGISTER.value()))));
                    rt = new ReferentToken(ad.registerReferent(spec), t, br.endToken);
                    t.kit.embedToken(rt);
                    t = rt;
                    continue;
                }
            }
            if (typ === ResumeItemType.SKILL) {
                let tok = VacanceToken.M_SKILL_ITEMS.tryParse(t, TerminParseAttr.NO);
                if (tok !== null) {
                    spec = new ResumeItemReferent();
                    spec.typ = typ;
                    spec.value = tok.termin.canonicText;
                    rt = new ReferentToken(ad.registerReferent(spec), t, tok.endToken);
                    t.kit.embedToken(rt);
                    t = rt;
                    continue;
                }
            }
            let t1 = t;
            for (let tt = t.next; tt !== null; tt = tt.next) {
                if (tt.isNewlineBefore) {
                    if (tt.previous.isHiphen) 
                        continue;
                    break;
                }
                if (tt.isCharOf(";,") || MiscHelper.canBeStartOfSentence(tt)) 
                    break;
                if (tt.isChar('(')) {
                    let br = BracketHelper.tryParse(tt, BracketParseAttr.NO, 100);
                    if (br !== null) 
                        tt = br.endToken;
                }
                t1 = tt;
            }
            if (t1 === null) 
                break;
            if (t1.next === null) 
                return null;
            if (typ === ResumeItemType.POSITION) {
                let ok = false;
                for (let tt = t1.next; tt !== null; tt = tt.next) {
                    if (tt.isNewlineBefore) {
                        if (tt.getReferent() instanceof MoneyReferent) 
                            ok = true;
                        else if (tt.isValue("СПЕЦИАЛИЗАЦИЯ", null)) 
                            ok = true;
                        break;
                    }
                }
                if (!ok) 
                    return null;
            }
            let rt1 = ResumeAnalyzer._parseDriving(t, ad);
            if (rt1 !== null) {
                t = rt1;
                rt = rt1;
                continue;
            }
            let mt = ResumeAnalyzer._parseMoral(t);
            if (mt !== null) {
                let mor = new ResumeItemReferent();
                mor.typ = ResumeItemType.MORAL;
                mor.value = ResumeAnalyzer._corrValue(Utils.asString(mt.tag));
                rt = new ReferentToken(ad.registerReferent(mor), t, mt.endToken);
            }
            else {
                spec = new ResumeItemReferent();
                spec.typ = typ;
                if ((t.lengthChar === 1 && (t instanceof TextToken) && !t.chars.isLetter) && (t.endChar < t1.beginChar)) 
                    t = t.next;
                for (; t !== null; t = t.next) {
                    if (t.isValue("НАВЫК", null) || t.isTableControlChar || ((t.lengthChar === 1 && (t instanceof TextToken) && !t.chars.isLetter))) {
                    }
                    else 
                        break;
                }
                if (t === null) 
                    break;
                if (t.endChar > t1.endChar) {
                    t = t1;
                    continue;
                }
                spec.value = ResumeAnalyzer._corrValue(MiscHelper.getTextValue(t, t1, GetTextAttr.of((GetTextAttr.KEEPQUOTES.value()) | (GetTextAttr.KEEPREGISTER.value()))));
                if (spec.value === "другое" || spec.value === "языки" || spec.value === "курсы") {
                    t = t1;
                    continue;
                }
                for (let tt = t; tt !== null && (tt.endChar < t1.endChar); tt = tt.next) {
                    let npt = NounPhraseHelper.tryParse(tt, NounPhraseParseAttr.NO, 0, null);
                    if (npt !== null && npt.adjectives.length > 0) {
                        if (npt.endToken.isValue("УРОВЕНЬ", null) || npt.endToken.isValue("НАВЫК", null) || npt.endToken.isValue("ЗНАНИЕ", null)) {
                            if (tt !== t) {
                                spec.misc = npt.getNormalCaseText(null, MorphNumber.UNDEFINED, MorphGender.UNDEFINED, false).toLowerCase();
                                if (tt.previous.isCharOf("-(")) 
                                    tt = tt.previous;
                                if (tt.previous.beginChar >= t.beginChar) {
                                    let tok = VacanceToken.M_SKILL_ITEMS.tryParse(t, TerminParseAttr.NO);
                                    if (tok !== null) 
                                        spec.value = tok.termin.canonicText;
                                    else 
                                        spec.value = ResumeAnalyzer._corrValue(MiscHelper.getTextValue(t, tt.previous, GetTextAttr.of((GetTextAttr.KEEPQUOTES.value()) | (GetTextAttr.KEEPREGISTER.value()))));
                                }
                            }
                            else if (npt.endChar < t1.endChar) {
                                spec.misc = npt.getNormalCaseText(null, MorphNumber.UNDEFINED, MorphGender.UNDEFINED, false).toLowerCase();
                                let tok = VacanceToken.M_SKILL_ITEMS.tryParse(npt.endToken.next, TerminParseAttr.NO);
                                if (tok !== null) 
                                    spec.value = tok.termin.canonicText;
                                else 
                                    spec.value = ResumeAnalyzer._corrValue(MiscHelper.getTextValue(npt.endToken.next, t1, GetTextAttr.of((GetTextAttr.FIRSTNOUNGROUPTONOMINATIVE.value()) | (GetTextAttr.KEEPQUOTES.value()) | (GetTextAttr.KEEPREGISTER.value()))));
                            }
                            break;
                        }
                    }
                }
                if (Utils.isNullOrEmpty(spec.value)) {
                    t = t1;
                    continue;
                }
                rt = new ReferentToken(ad.registerReferent(spec), t, t1);
            }
            t.kit.embedToken(rt);
            t = rt;
        }
        return rt;
    }
    
    static _corrValue(val) {
        if (Utils.isNullOrEmpty(val) || (val.length < 3)) 
            return val;
        val = Utils.replaceString(val, " - ", "-");
        if (val.endsWith(".")) 
            val = val.substring(0, 0 + val.length - 1);
        if (Utils.isUpperCase(val[0]) && Utils.isLowerCase(val[1]) && (val.charCodeAt(0)) > 0x100) 
            val = (val[0].toLowerCase() + val.substring(1));
        return val;
    }
    
    static _parseAboutMe(t, ad) {
        let t0 = t;
        let rt = null;
        for (; t !== null; t = t.next) {
            if (t.isNewlineBefore) {
                if (ResumeAnalyzer._parseEducation(t) !== null) 
                    break;
                if (ResumeAnalyzer._startOfItem(t)) 
                    break;
            }
            let mt = ResumeAnalyzer._parseMoral(t);
            if (mt !== null) {
                let mor = new ResumeItemReferent();
                mor.typ = ResumeItemType.MORAL;
                mor.value = ResumeAnalyzer._corrValue(Utils.asString(mt.tag));
                rt = new ReferentToken(ad.registerReferent(mor), t, mt.endToken);
                t.kit.embedToken(rt);
                t = rt;
                continue;
            }
            mt = ResumeAnalyzer._parseOnto(t);
            if (mt !== null) {
                let mor = new ResumeItemReferent();
                mor.typ = ResumeItemType.SKILL;
                mor.value = ResumeAnalyzer._corrValue(Utils.asString(mt.tag));
                rt = new ReferentToken(ad.registerReferent(mor), t, mt.endToken);
                t.kit.embedToken(rt);
                t = rt;
                continue;
            }
        }
        return rt;
    }
    
    static _parseOrg(t, typ) {
        let t0 = t;
        if (t === null) 
            return null;
        for (; t !== null; t = t.next) {
            if (((t.isCharOf(":-") || t.isTableControlChar || t.isValue("ПЕРИОД", null)) || t.isValue("РАБОТА", null) || t.isValue("ВРЕМЯ", null)) || t.isValue("МЕСТО", null)) {
            }
            else if (((t instanceof NumberToken) && t.isNewlineBefore && t.next !== null) && t.next.isCharOf(".)")) 
                t = t.next;
            else 
                break;
        }
        if (t === null) 
            return null;
        let _org = null;
        let post = null;
        let postAttr = null;
        let dt = t.getReferent();
        let t1 = null;
        if ((dt instanceof DateReferent) || (dt instanceof DateRangeReferent)) {
        }
        else if ((dt instanceof OrganizationReferent) && t0.isNewlineBefore && t.next !== null) {
            _org = Utils.as(dt, OrganizationReferent);
            dt = null;
            t = t.next;
            if (t.isChar('(') && t.next !== null) 
                t = t.next;
            if ((t.getReferent() instanceof DateReferent) || (t.getReferent() instanceof DateRangeReferent)) {
                dt = t.getReferent();
                t1 = t;
                t = t.next;
                if (t !== null && t.isChar(')')) {
                    t1 = t;
                    t = t.next;
                }
            }
            let pat = PersonAttrToken.tryAttach(t, PersonAttrTokenPersonAttrAttachAttrs.NO);
            if (pat === null && t !== null && (t.getReferent() instanceof PersonPropertyReferent)) 
                pat = PersonAttrToken._new3525(t, t, Utils.as(t.getReferent(), PersonPropertyReferent));
            if (pat === null || pat.propRef === null) {
                if (dt !== null && typ !== ResumeItemType.UNDEFINED) {
                }
                else 
                    return null;
            }
            else {
                postAttr = pat;
                dt = Utils.as(pat.propRef.getSlotValue(PersonPropertyReferent.ATTR_REF), Referent);
                if (dt === null && pat.propRef.higher !== null) 
                    dt = Utils.as(pat.propRef.higher.getSlotValue(PersonPropertyReferent.ATTR_REF), Referent);
                t1 = pat.endToken;
                if ((dt instanceof DateReferent) || (dt instanceof DateRangeReferent)) {
                    pat.propRef.addSlot(PersonPropertyReferent.ATTR_REF, null, true, 0);
                    if (pat.propRef.higher !== null) 
                        pat.propRef.higher.addSlot(PersonPropertyReferent.ATTR_REF, null, true, 0);
                }
                else if (dt === null) {
                    if (pat.endToken.next === null) 
                        return null;
                    dt = pat.endToken.next.getReferent();
                    if ((dt instanceof DateReferent) || (dt instanceof DateRangeReferent)) {
                    }
                    else 
                        return null;
                    t1 = pat.endToken.next;
                }
            }
        }
        else 
            return null;
        let cou = 0;
        if (t1 === null) {
            for (t = t.next; t !== null && (cou < 3); t = t.next) {
                if (((post !== null || postAttr !== null)) && _org !== null) 
                    break;
                if (t.isNewlineBefore) 
                    cou++;
                let r = Utils.as(t.getReferent(), OrganizationReferent);
                if (r !== null) {
                    if (_org !== null) {
                        if (r.higher === _org || ((r.higher !== null && r.higher === _org))) {
                        }
                        else 
                            break;
                    }
                    _org = r;
                    t1 = t;
                    cou = 0;
                    continue;
                }
                let p = Utils.as(t.getReferent(), PersonPropertyReferent);
                if (p !== null && post === null) {
                    post = p;
                    t1 = t;
                    cou = 0;
                    continue;
                }
                if (post === null && postAttr === null) {
                    if (t.isValue("ТЕХНИК", null)) {
                    }
                    let pat = PersonAttrToken.tryAttach(t, PersonAttrTokenPersonAttrAttachAttrs.NO);
                    if (pat !== null && pat.propRef !== null) {
                        postAttr = pat;
                        t = (t1 = pat.endToken);
                        if (_org === null) {
                            if (pat.higherPropRef !== null) 
                                _org = Utils.as(pat.higherPropRef.propRef.getSlotValue(PersonPropertyReferent.ATTR_REF), OrganizationReferent);
                            else 
                                _org = Utils.as(pat.propRef.getSlotValue(PersonPropertyReferent.ATTR_REF), OrganizationReferent);
                        }
                        cou = 0;
                        continue;
                    }
                }
                if ((t.getReferent() instanceof DateReferent) || (t.getReferent() instanceof DateRangeReferent)) 
                    break;
                if ((t instanceof NumberToken) && t.isNewlineBefore) {
                    if (t.next !== null && t.next.isCharOf(".)")) 
                        break;
                    let num = Utils.as(t, NumberToken);
                    if (num.intValue !== null) {
                        if (num.intValue >= 2000 && num.intValue <= 2050) 
                            break;
                    }
                }
            }
        }
        if (_org === null) 
            return null;
        if (typ === ResumeItemType.UNDEFINED && _org.profiles.includes(OrgProfile.EDUCATION)) 
            typ = ResumeItemType.STUDY;
        let res = ResumeItemReferent._new3526((typ === ResumeItemType.UNDEFINED ? ResumeItemType.ORGANIZATION : typ));
        res.dateRange = dt;
        res.ref = _org;
        if (post === null && postAttr !== null) 
            post = postAttr.propRef;
        if (post !== null) 
            res.value = post.toStringEx(true, null, 0);
        return new ReferentToken(res, t0, t1);
    }
    
    static _parseOrg2(t, ad, links = null) {
        if (t === null) 
            return null;
        if (!t.isValue2("ОПЫТ", "РАБОТЫ")) 
            return null;
        for (t = t.next; t !== null; t = t.next) {
            if (t.isNewlineBefore) 
                break;
        }
        if (t === null) 
            return null;
        let res = null;
        for (; t !== null; t = t.next) {
            if (ResumeAnalyzer._startOfItem(t)) 
                break;
            if (!t.isNewlineBefore) 
                continue;
            let prop = Utils.as(t.getReferent(), PersonPropertyReferent);
            let _org = null;
            if (prop === null) {
                let pr = PersonAttrToken.tryAttach(t, PersonAttrTokenPersonAttrAttachAttrs.NO);
                if (pr !== null) {
                    prop = pr.propRef;
                    t = pr.endToken;
                }
            }
            if (prop === null) {
                if (res === null) 
                    break;
                continue;
            }
            let t0 = t;
            if (t.next !== null && ((t.next.isValue("В", null) || t.next.isCharOf("-:,")))) 
                t = t.next;
            _org = Utils.as(prop.getSlotValue(PersonPropertyReferent.ATTR_REF), OrganizationReferent);
            if (_org === null) 
                _org = Utils.as(t.getReferent(), OrganizationReferent);
            if (_org === null) 
                break;
            let dtTok = null;
            for (t = t.next; t !== null; t = t.next) {
                if ((t.getReferent() instanceof DateReferent) || (t.getReferent() instanceof DateRangeReferent)) {
                    dtTok = Utils.as(t, ReferentToken);
                    break;
                }
                if (t.lengthChar > 1) 
                    break;
            }
            if (dtTok === null) 
                break;
            let it = ResumeItemReferent._new3526(ResumeItemType.ORGANIZATION);
            it.dateRange = dtTok.referent;
            it.ref = _org;
            it.value = prop.toStringEx(true, null, 0);
            _org.tag = it;
            if (links === null) {
                res = new ReferentToken(ad.registerReferent(it), t0, dtTok);
                t0.kit.embedToken(res);
                t = res;
            }
            else {
                links.push(new ReferentToken(it, t0, dtTok));
                t = dtTok;
            }
        }
        return res;
    }
    
    static _checkGeo(t) {
        if (t === null) 
            return false;
        if (t.isValue2("УКАЗАН", "ПРИМЕРНЫЙ")) 
            return true;
        for (let tt = t; tt !== null; tt = tt.next) {
            if (tt !== t && tt.isNewlineBefore) 
                break;
            let r = tt.getReferent();
            if ((r instanceof GeoReferent) || (r instanceof StreetReferent) || (r instanceof AddressReferent)) 
                return true;
            if (tt.isValue("ГОТОВ", null) || tt.isValue("ПЕРЕЕЗД", null) || tt.isValue("КОМАНДИРОВКА", null)) 
                return true;
        }
        return false;
    }
    
    processOntologyItem(begin) {
        for (let t = begin; t !== null; t = t.next) {
            if (t.next === null) {
                let re = new ResumeItemReferent();
                re.value = MiscHelper.getTextValue(begin, t, GetTextAttr.NO);
                return new ReferentToken(re, begin, t);
            }
        }
        return null;
    }
    
    static initialize() {
        /* this is synchronized block by ResumeAnalyzer.m_Lock, but this feature isn't supported in JS */ {
            if (ResumeAnalyzer.m_Initialized) 
                return;
            ResumeAnalyzer.m_Initialized = true;
            MetaResume.initialize();
            VacanceToken.initialize();
            ProcessorService.registerAnalyzer(new ResumeAnalyzer());
        }
    }
    
    static static_constructor() {
        ResumeAnalyzer.ANALYZER_NAME = "RESUME";
        ResumeAnalyzer.m_Initialized = false;
        ResumeAnalyzer.m_Lock = new Object();
    }
}


ResumeAnalyzer.static_constructor();

module.exports = ResumeAnalyzer