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

const AddressItemType = require("./../../address/internal/AddressItemType");
const BracketHelper = require("./../../core/BracketHelper");
const AddressItemToken = require("./../../address/internal/AddressItemToken");
const PersonItemTokenParseAttr = require("./PersonItemTokenParseAttr");
const MorphNumber = require("./../../../morph/MorphNumber");
const PersonNormalNode = require("./PersonNormalNode");
const PersonReferent = require("./../PersonReferent");
const ShortNameHelper = require("./ShortNameHelper");
const MorphLang = require("./../../../morph/MorphLang");
const LanguageHelper = require("./../../../morph/LanguageHelper");
const PersonNormalResult = require("./../PersonNormalResult");
const SourceOfAnalysis = require("./../../SourceOfAnalysis");
const NumberToken = require("./../../NumberToken");
const MorphologyService = require("./../../../morph/MorphologyService");
const TextToken = require("./../../TextToken");
const ProcessorService = require("./../../ProcessorService");
const PersonItemToken = require("./PersonItemToken");

class PersonNormalHelper {
    
    static analyze(res, txt, corr) {
        const PersonNormalData = require("./../PersonNormalData");
        let co = null;
        if (corr !== null && corr.containsKey("")) 
            co = corr.get("");
        let ttt = new StringBuilder(txt);
        for (let i = 1; i < (ttt.length - 2); i++) {
            if (ttt.charAt(i) === '-' && Utils.isLowerCase(ttt.charAt(i + 1))) 
                ttt.setCharAt(i + 1, ttt.charAt(i + 1).toUpperCase());
            else if (ttt.charAt(i) === '-' && ttt.charAt(i + 1) === ' ' && Utils.isLetter(ttt.charAt(i + 2))) {
                ttt.setCharAt(i + 2, ttt.charAt(i + 2).toUpperCase());
                ttt.remove(i + 1, 1);
            }
        }
        for (let i = ttt.length - 2; i >= 0; i--) {
            if (ttt.charAt(i) === ' ' && ttt.charAt(i + 1) === ' ') 
                ttt.remove(i + 1, 1);
            else if (LanguageHelper.isHiphen(ttt.charAt(i)) && LanguageHelper.isHiphen(ttt.charAt(i + 1))) 
                ttt.remove(i + 1, 1);
            else if (ttt.charAt(i) === '\t') 
                ttt.setCharAt(i, '\n');
        }
        txt = ttt.toString();
        res.resTyp = PersonNormalResult.NOTPERSON;
        res.errorMessage = "Похоже на просто текст";
        if (txt.length > 200) 
            return;
        let ar = null;
        let altSurname = null;
        let addcorr = null;
        for (let kk = 0; kk < 20; kk++) {
            ar = ProcessorService.getEmptyProcessor().process(SourceOfAnalysis._new3442(txt, co, false, false), null, null);
            if (ar === null || ar.firstToken === null) 
                return;
            let ch = false;
            for (let t = ar.firstToken; t !== null; t = t.next) {
                if (((((t instanceof TextToken) && !t.chars.isLetter && !t.isWhitespaceBefore) && (t.previous instanceof TextToken) && t.previous.chars.isCyrillicLetter) && !t.isWhitespaceAfter && (t.next instanceof TextToken)) && t.next.chars.isCyrillicLetter) {
                    let str = t.previous.term + t.next.term;
                    let mb = MorphologyService.getWordBaseInfo(str, MorphLang.RU, true, true);
                    if (mb._class.isProperSurname || mb._class.isProperName || mb._class.isProperSecname) {
                        let ok = true;
                        if (t.isHiphen && !t.next.chars.isAllLower) {
                            ok = false;
                            if (PersonNormalHelper.m_MaleNames.includes(str) || PersonNormalHelper.m_MaleSecnames.includes(str) || PersonNormalHelper.m_FemaleSecnames.includes(str)) 
                                ok = true;
                        }
                        if (ok) {
                            txt = (txt.substring(0, 0 + t.beginChar) + txt.substring(t.endChar + 1));
                            ch = true;
                            break;
                        }
                    }
                }
                if ((((t instanceof TextToken) && ((t.chars.isCapitalUpper || t.chars.isAllUpper)) && t.whitespacesAfterCount === 1) && (t.next instanceof TextToken) && ((t.next.chars.isAllLower || t.lengthChar === 1))) && t.chars.isLetter && t.next.chars.isLetter) {
                    if (t.lengthChar === 1 && (t.next.lengthChar < 4)) 
                        continue;
                    if ((t.lengthChar < 4) && t.next.lengthChar === 1) 
                        continue;
                    let str = t.term + t.next.term;
                    let mb = MorphologyService.getWordBaseInfo(str, MorphLang.RU, true, true);
                    if (mb._class.isProperSurname || mb._class.isProperName || mb._class.isProperSecname) {
                        txt = txt.substring(0, 0 + t.endChar + 1) + txt.substring(t.next.beginChar);
                        ch = true;
                        break;
                    }
                }
                else if (((t instanceof NumberToken) && !t.isWhitespaceAfter && (t.next instanceof TextToken)) && t.next.chars.isLetter) {
                    let n = t.value;
                    let str = null;
                    if (n === "0") 
                        str = "О" + t.next.term;
                    else if (n === "3") 
                        str = "З" + t.next.term;
                    if (str !== null) {
                        let mb = MorphologyService.getWordBaseInfo(str, MorphLang.RU, true, true);
                        if ((mb._class.isProperSurname || mb._class.isProperName || mb._class.isProperSecname) || t.lengthChar === 1) {
                            txt = (txt.substring(0, 0 + t.endChar) + str[0] + txt.substring(t.next.beginChar));
                            ch = true;
                            break;
                        }
                    }
                    if (!t.isWhitespaceBefore && (t.previous instanceof TextToken) && t.previous.chars.isCyrillicLetter) {
                        let mb = MorphologyService.getWordBaseInfo(t.previous.term + t.next.term, MorphLang.RU, true, true);
                        if (mb._class.isProperSurname || mb._class.isProperName || mb._class.isProperSecname) {
                            txt = (txt.substring(0, 0 + t.beginChar) + txt.substring(t.endChar + 1));
                            ch = true;
                            break;
                        }
                    }
                }
                else if (t.isValue("РАНЕЕ", null) && (t.next instanceof TextToken) && t.previous !== null) {
                    if (t.next.endChar < (txt.length - 1)) 
                        txt = txt.substring(0, 0 + t.previous.endChar + 1) + " " + txt.substring(t.next.endChar + 1);
                    else 
                        txt = txt.substring(0, 0 + t.previous.endChar + 1);
                    ch = true;
                    break;
                }
                else if ((t.isValue("ДО", null) && (t.next instanceof TextToken) && t.previous !== null) && t.next !== null) {
                    let tt = t.next;
                    if (tt.isHiphen || tt.isCharOf("\\/")) {
                        if (tt.next !== null) 
                            tt = tt.next;
                    }
                    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) || tt.isValue("РАСТОРЖЕНИЕ", null)) || tt.isValue("РАСТОРЖ", null)) {
                        for (tt = tt.next; tt !== null; tt = tt.next) {
                            if (((tt.isChar('.') || tt.isValue("ФАМИЛИЯ", null) || tt.isValue("ФАМ", null)) || tt.isValue("ФАМИЛ", null) || tt.isValue("БР", null)) || tt.isValue("БРАК", null)) {
                            }
                            else 
                                break;
                        }
                        if (tt instanceof TextToken) {
                            let ppp = PersonItemToken.tryAttach(tt, PersonItemTokenParseAttr.CANBELOWER, null);
                            if (ppp !== null) {
                                if (ppp.lastname !== null) {
                                    altSurname = ppp.value;
                                    tt = ppp.endToken.next;
                                }
                            }
                        }
                        if (t.previous !== null && t.previous.previous !== null && ((t.previous.isHiphen || t.previous.isCharOf("\\/")))) 
                            t = t.previous;
                        if (tt !== null) 
                            txt = txt.substring(0, 0 + t.previous.endChar + 1) + " " + txt.substring(tt.beginChar);
                        else 
                            txt = txt.substring(0, 0 + t.previous.endChar + 1);
                        ch = true;
                        break;
                    }
                }
                else if (t.next === null && (t instanceof TextToken) && t.beginChar > 10) {
                    let mc = t.getMorphClassInDictionary();
                    if ((mc.isProperSecname || mc.isProperName || t.previous === null) || t.previous.previous === null) {
                    }
                    else {
                        let rr = new PersonNormalData(null);
                        rr.middlename = t.term;
                        PersonNormalHelper._corrCoef(t, rr, corr);
                        if (rr.corrWords.containsKey(t.term)) {
                            addcorr = rr.corrWords;
                            txt = txt.substring(0, 0 + t.beginChar) + rr.corrWords.get(t.term);
                            ch = true;
                            break;
                        }
                    }
                }
                if ((t instanceof TextToken) && t.lengthChar > 10 && t.chars.isCyrillicLetter) {
                    if ((!t.chars.isAllLower && !t.chars.isCapitalUpper && !t.chars.isAllUpper) && !t.chars.isLastLower) {
                        let str = t.getSourceText();
                        if (Utils.isUpperCase(str[0]) && Utils.isLowerCase(str[1])) {
                            for (let ii = 2; ii < (str.length - 4); ii++) {
                                if (Utils.isUpperCase(str[ii]) && Utils.isLowerCase(str[ii + 1]) && Utils.isLetter(str[ii + 1])) {
                                    let s1 = str.substring(0, 0 + ii).toUpperCase();
                                    let s2 = str.substring(ii).toUpperCase();
                                    let b1 = MorphologyService.getWordBaseInfo(s1, MorphLang.RU, true, true);
                                    let b2 = MorphologyService.getWordBaseInfo(s2, MorphLang.RU, true, true);
                                    if (b1._class.isProper && b2._class.isProper) {
                                        txt = txt.substring(0, 0 + t.beginChar + ii) + " " + txt.substring(t.beginChar + ii);
                                        ch = true;
                                    }
                                    break;
                                }
                            }
                        }
                        if (ch) 
                            break;
                    }
                }
                if (t.isHiphen) {
                    let okk = false;
                    if (t.isWhitespaceBefore || t.isWhitespaceAfter) 
                        okk = true;
                    else if ((t.previous !== null && t.previous.morph._class.isProperSurname && t.next !== null) && t.next.getMorphClassInDictionary().isProperName) 
                        okk = true;
                    if (okk) {
                        txt = txt.substring(0, 0 + t.beginChar) + " " + txt.substring(t.endChar + 1);
                        ch = true;
                        break;
                    }
                }
            }
            if (!ch) 
                break;
        }
        let maxChar = 0;
        for (let t = ar.firstToken; t !== null; t = t.next) {
            if (t.isValue("ДО", null) && t.next !== null && t.next.isValue("БРАК", null)) {
                maxChar = t.previous.endChar;
                break;
            }
            else if (t.isValue("БЕЗ", null) && t.next !== null && t.next.isValue("ОТЧЕСТВА", null)) {
                maxChar = t.previous.endChar;
                break;
            }
            else if (t.isValue("БЕЗ", null) && t.next !== null && t.next.isValue("СОГЛАСИЕ", null)) 
                return;
            else if (t.isValue("ПО", null) && t.next !== null && t.next.isValue("ДАННЫЙ", null)) {
                maxChar = t.previous.endChar;
                break;
            }
            else if ((t instanceof TextToken) && t.next === null) {
                let term = t.term;
                if (((term === "НЕТ" || term === "РФ" || term === "РОССИЯ") || term === "МУЖ" || term === "ЖЕН") || term === "ЖЕНА") {
                    maxChar = t.previous.endChar;
                    break;
                }
            }
        }
        let cou = 0;
        let dict = 0;
        let prdict = 0;
        let props = 0;
        let _org = 0;
        for (let tt = ar.firstToken; tt !== null; tt = tt.next) {
            if (maxChar > 0 && tt.beginChar > maxChar) 
                break;
            cou++;
            let ait = AddressItemToken.tryParsePureItem(tt, null, null);
            if (ait !== null) {
                if (ait.typ === AddressItemType.NUMBER || ait.value === null) 
                    continue;
                res.resTyp = PersonNormalResult.NOTPERSON;
                res.errorMessage = "Похоже на просто текст";
                return;
            }
            let mc = tt.getMorphClassInDictionary();
            if (mc.isProperName || mc.isProperSecname || mc.isProperSurname) {
                prdict = 0;
                dict--;
                props++;
                continue;
            }
            let oty = tt.kit.processReferent("ORGANIZATION", tt, "TYPE");
            if (oty !== null && oty.endToken.isValue("ОЛИМПИАДА", null)) 
                oty = null;
            if (oty !== null) {
                _org++;
                if (oty.beginToken !== oty.endToken || tt === ar.firstToken) {
                    let ok = false;
                    if (oty.endToken.next !== null) {
                        let mc1 = oty.endToken.next.getMorphClassInDictionary();
                        if (mc1.isProperName || mc1.isProperSecname) 
                            ok = true;
                    }
                    if (!ok) {
                        res.errorMessage = "Похоже на организацию";
                        return;
                    }
                }
            }
            if (BracketHelper.isBracket(tt, true)) {
                if (_org > 0) {
                    res.errorMessage = "Похоже на организацию";
                    return;
                }
            }
            if (tt.lengthChar >= 2 && ((tt.chars.isAllLower || !mc.isUndefined))) {
                if (!tt.chars.isAllLower && (tt.lengthChar < 5)) {
                }
                else if (mc.isAdjective) {
                    prdict++;
                    dict += prdict;
                }
            }
            else 
                prdict = 0;
        }
        if (dict > (cou - 2) || ((dict === 2 && (cou < 5))) || dict >= 3) {
            if (props < 2) 
                return;
        }
        if (_org > 1 || ((_org > 0 && (props < 1)))) {
            res.errorMessage = "Похоже на организацию";
            return;
        }
        let t0 = ar.firstToken;
        for (let tt = t0; tt !== null; tt = tt.next) {
            if (maxChar > 0 && tt.beginChar > maxChar) 
                break;
            if (tt.lengthChar === 1 && !tt.chars.isLetter) {
                t0 = tt.next;
                continue;
            }
            if (!tt.chars.isAllLower) 
                break;
            let mc = tt.getMorphClassInDictionary();
            if (mc.isProper) 
                break;
            if (mc.isUndefined) {
                if (tt.next !== null && tt.next.isCharOf(",.")) {
                }
                else 
                    break;
            }
            break;
        }
        let attrs = ((PersonItemTokenParseAttr.CANBELOWER.value()) | (PersonItemTokenParseAttr.MUSTBEITEMALWAYS.value()) | (PersonItemTokenParseAttr.NOMINATIVECASE.value())) | (PersonItemTokenParseAttr.SURNAMEPREFIXNOTMERGE.value());
        let pits = PersonItemToken.tryAttachList(t0, PersonItemTokenParseAttr.of(attrs), 10);
        let tt0 = ar.firstToken;
        if (pits !== null && pits.length > 0) {
            let pit = pits[pits.length - 1];
            tt0 = pit.endToken.next;
            if (tt0 !== null && pit.chars.isAllLower && pits.length > 1) {
                tt0 = pit.beginToken;
                pits.splice(pits.length - 1, 1);
            }
        }
        else 
            pits = new Array();
        let coefMult = 1;
        for (; tt0 !== null; tt0 = tt0.next) {
            if (maxChar > 0 && tt0.beginChar > maxChar) 
                break;
            coefMult *= 0.9;
            let pits1 = PersonItemToken.tryAttachList(tt0, PersonItemTokenParseAttr.of((PersonItemTokenParseAttr.NOMINATIVECASE.value()) | (PersonItemTokenParseAttr.SURNAMEPREFIXNOTMERGE.value())), 10);
            if (pits1 !== null && pits.length > 0) {
                pits.splice(pits.length, 0, ...pits1);
                tt0 = pits1[pits1.length - 1].endToken;
            }
        }
        if (pits.length > 15) 
            return;
        if (pits !== null && pits.length > 3) {
            for (let i = 0; i < (pits.length - 3); i++) {
                if (pits[i].value === pits[i + 2].value && pits[i + 1].value === pits[i + 3].value) {
                    pits[i + 1].endToken = pits[i + 3].endToken;
                    pits.splice(i + 3, 1);
                    pits.splice(i + 2, 1);
                    i--;
                }
            }
            for (let i = 0; i < (pits.length - 2); i++) {
                if (pits[i].value === (pits[i + 1].value + "-" + pits[i + 2].value)) {
                    pits[i + 1].beginToken = pits[i].beginToken;
                    pits.splice(i, 1);
                    i--;
                }
            }
            for (let i = 0; i < (pits.length - 2); i++) {
                if (pits[i + 2].value === (pits[i].value + "-" + pits[i + 1].value)) {
                    pits[i + 1].endToken = pits[i + 2].endToken;
                    pits.splice(i + 2, 1);
                    i--;
                }
            }
            for (let i = 0; i < (pits.length - 1); i++) {
                if (pits[i].value === pits[i + 1].value) {
                    pits[i].endToken = pits[i + 1].endToken;
                    pits.splice(i + 1, 1);
                    i--;
                }
            }
        }
        if (pits !== null) {
            let coef = PersonNormalHelper.m_Fio.process(pits);
            let ciof = PersonNormalHelper.m_Iof.process(pits);
            ciof *= 0.9;
            let pn = PersonNormalHelper.m_Fio;
            if (coef < ciof) {
                pn = PersonNormalHelper.m_Iof;
                coef = ciof;
            }
            if (coef > 0.3) {
                pn.createResult(res);
                res.coef = Math.floor((coef * (100) * coefMult));
                res.lastnameAlt = altSurname;
                PersonNormalHelper._corrCoef(ar.firstToken, res, corr);
                res.resTyp = PersonNormalResult.OK;
                if (res.coef < 60) 
                    res.resTyp = PersonNormalResult.MANUAL;
                if (addcorr !== null) {
                    for (const kp of addcorr.entries) {
                        if (!res.corrWords.containsKey(kp.key)) 
                            res.corrWords.put(kp.key, kp.value);
                    }
                }
                return;
            }
        }
        ar = ProcessorService.getStandardProcessor().process(SourceOfAnalysis._new3443(txt, co, false), null, null);
        if (ar !== null) {
            for (let tt = ar.firstToken; tt !== null; tt = tt.next) {
                let r = tt.getReferent();
                if (r !== null && ((r.typeName === "GEO" || r.typeName === "STREET" || r.typeName === "ADDRESS"))) {
                    res.errorMessage = "Похоже на адрес";
                    return;
                }
                if (r !== null && r.typeName === "ORGANIZATION") {
                    res.errorMessage = "Похоже на организацию";
                    return;
                }
                if (r instanceof PersonReferent) {
                    let pr = Utils.as(r, PersonReferent);
                    res.coef = 100;
                    res.resTyp = PersonNormalResult.OK;
                    if ((((res.firstname = pr.getStringValue(PersonReferent.ATTR_FIRSTNAME)))) === null) 
                        res.coef = Math.floor((0.8 * (res.coef)));
                    res.middlename = pr.getStringValue(PersonReferent.ATTR_MIDDLENAME);
                    if ((((res.lastname = pr.getStringValue(PersonReferent.ATTR_LASTNAME)))) === null) 
                        res.coef = Math.floor((0.5 * (res.coef)));
                    for (let tt2 = tt.next; tt2 !== null; tt2 = tt2.next) {
                        if ((tt2 instanceof TextToken) && !tt2.chars.isLetter) {
                        }
                        else 
                            res.coef = Math.floor((0.5 * (res.coef)));
                    }
                    for (let tt2 = tt.previous; tt2 !== null; tt2 = tt2.previous) {
                        if ((tt2 instanceof TextToken) && !tt2.chars.isLetter) {
                        }
                        else 
                            res.coef = Math.floor((0.5 * (res.coef)));
                    }
                    PersonNormalHelper._corrCoef(ar.firstToken, res, corr);
                    if (res.coef < 90) 
                        res.resTyp = PersonNormalResult.MANUAL;
                    return;
                }
            }
        }
    }
    
    static _loadCorrMiddlaTails(txt) {
        PersonNormalHelper.corrMiddnameTails = new Hashtable();
        for (const s of Utils.splitString(txt, '\n', false)) {
            let line = s.trim().toUpperCase();
            let i = line.indexOf(":");
            if (i < 0) 
                i = line.indexOf(';');
            if (i < 0) 
                continue;
            let err = line.substring(0, 0 + i);
            if (err.endsWith("$")) 
                err = err.substring(0, 0 + err.length - 1);
            let ok = line.substring(i + 1);
            if (!PersonNormalHelper.corrMiddnameTails.containsKey(err)) 
                PersonNormalHelper.corrMiddnameTails.put(err, ok);
        }
    }
    
    static _corrCoef(t, r, corr) {
        if (t.kit.correctedTokens !== null) {
            for (const kp of t.kit.correctedTokens.entries) {
                if (kp.key instanceof TextToken) {
                    if (!r.corrWords.containsKey(kp.value)) 
                        r.corrWords.put(kp.value, kp.key.term);
                }
            }
        }
        if (corr !== null) {
            let dic = null;
            let wrapdic3448 = new RefOutArgWrapper();
            let inoutres3449 = corr.tryGetValue("name", wrapdic3448);
            dic = wrapdic3448.value;
            if (r.firstname !== null && inoutres3449) {
                if (dic.containsKey(r.firstname)) {
                    if (!r.corrWords.containsKey(r.firstname)) 
                        r.corrWords.put(r.firstname, dic.get(r.firstname));
                    r.firstname = dic.get(r.firstname);
                    r.coef = Math.floor(((r.coef) * 0.95));
                }
            }
            let wrapdic3446 = new RefOutArgWrapper();
            let inoutres3447 = corr.tryGetValue("midname", wrapdic3446);
            dic = wrapdic3446.value;
            if (r.middlename !== null && inoutres3447) {
                if (dic.containsKey(r.middlename)) {
                    if (!r.corrWords.containsKey(r.middlename)) 
                        r.corrWords.put(r.middlename, dic.get(r.middlename));
                    r.middlename = dic.get(r.middlename);
                    r.coef = Math.floor(((r.coef) * 0.95));
                }
            }
            let wrapdic3444 = new RefOutArgWrapper();
            let inoutres3445 = corr.tryGetValue("lastname", wrapdic3444);
            dic = wrapdic3444.value;
            if (r.lastname !== null && inoutres3445) {
                if (dic.containsKey(r.lastname)) {
                    if (!r.corrWords.containsKey(r.lastname)) 
                        r.corrWords.put(r.lastname, dic.get(r.lastname));
                    r.lastname = dic.get(r.lastname);
                    r.coef = Math.floor(((r.coef) * 0.95));
                }
            }
        }
        if (r.middlename !== null) {
            for (const kp of PersonNormalHelper.corrMiddnameTails.entries) {
                if (r.middlename.endsWith(kp.key)) {
                    let mmm = r.middlename;
                    r.middlename = r.middlename.substring(0, 0 + r.middlename.length - kp.key.length);
                    r.middlename += kp.value;
                    r.coef = Math.floor(((r.coef) * 0.95));
                    if (!r.corrWords.containsKey(mmm)) 
                        r.corrWords.put(mmm, r.middlename);
                    break;
                }
            }
        }
        if (r.firstnameAlt !== null) {
            if (ShortNameHelper.getNamesForShortname(r.firstnameAlt) === null) {
                if (r.firstnameAlt !== "СВЕТА") {
                    if (PersonNormalHelper.m_MaleNames.includes(r.firstname)) {
                        if (!r.corrWords.containsKey(r.firstnameAlt)) 
                            r.corrWords.put(r.firstnameAlt, r.firstname);
                    }
                    else 
                        r.firstname = r.firstnameAlt;
                    r.firstnameAlt = null;
                }
            }
        }
        if (r.firstname !== null) {
            let cc = PersonNormalHelper._corrDublsChars(r.firstname, 1, r.gender);
            if (cc !== null) {
                if (!r.corrWords.containsKey(r.firstname)) 
                    r.corrWords.put(r.firstname, cc);
                r.firstname = cc;
                r.coef = Math.floor(((r.coef) * 0.95));
            }
        }
        if (r.middlename !== null) {
            let cc = PersonNormalHelper._corrDublsChars(r.middlename, 2, r.gender);
            if (cc !== null) {
                if (!r.corrWords.containsKey(r.middlename)) 
                    r.corrWords.put(r.middlename, cc);
                r.middlename = cc;
                r.coef = Math.floor(((r.coef) * 0.95));
            }
            let bb = MorphologyService.getWordBaseInfo(r.middlename, MorphLang.RU, true, true);
            if (!bb._class.isProperSecname && (r.middlename.indexOf('-') < 0)) {
                cc = MorphologyService.correctWord(r.middlename, null);
                if (cc !== null) {
                    if (((r.gender === 1 && PersonNormalHelper.m_MaleSecnames.includes(cc))) || ((r.gender === 2 && PersonNormalHelper.m_FemaleSecnames.includes(cc)))) {
                        if (!r.corrWords.containsKey(r.middlename)) 
                            r.corrWords.put(r.middlename, cc);
                        r.middlename = cc;
                        r.coef = Math.floor(((r.coef) * 0.95));
                    }
                }
            }
        }
        if (r.lastname !== null) {
            let glas = 0;
            for (const ch of r.lastname) {
                if (LanguageHelper.isCyrillicVowel(ch)) 
                    glas++;
            }
            if (glas === 0) 
                r.coef = Math.floor(((r.coef) * 0.8));
            else if (glas > 2 && glas === r.lastname.length) 
                r.coef = Math.floor(((r.coef) * 0.6));
            let cc = PersonNormalHelper._corrDublsChars(r.lastname, 3, r.gender);
            if (cc !== null) {
                if (!r.corrWords.containsKey(r.lastname)) 
                    r.corrWords.put(r.lastname, cc);
                r.lastname = cc;
                r.coef = Math.floor(((r.coef) * 0.95));
            }
        }
    }
    
    static _corrDublsChars(str, typ, gender) {
        if (str.length < 4) 
            return null;
        let cou = 0;
        for (let i = str.length - 2; i > 0; i--) {
            if (str[i] !== str[str.length - 1]) {
                if (cou >= 2) {
                    let res = str.substring(0, 0 + i + 2);
                    let bb = MorphologyService.getWordBaseInfo(res, MorphLang.RU, true, true);
                    if (bb._class.isProper) 
                        return res;
                    let res0 = res.substring(0, 0 + res.length - 1);
                    bb = MorphologyService.getWordBaseInfo(res0, MorphLang.RU, true, true);
                    if (bb._class.isProper) 
                        return res0;
                    return res;
                }
                break;
            }
            else 
                cou++;
        }
        if (typ === 3) 
            return null;
        if (typ === 2) {
            if (gender === 1 && !str.endsWith("ИЧ")) {
                let str1 = str.substring(0, 0 + str.length - 1);
                if (str1.endsWith("ИЧ")) 
                    return str1;
            }
        }
        let bb0 = MorphologyService.getWordBaseInfo(str, MorphLang.RU, true, true);
        if (typ === 1 && LanguageHelper.isCyrillicVowel(str[str.length - 1])) {
            let str1 = str + "Й";
            if (PersonNormalHelper.m_MaleNames.includes(str1)) 
                return str1;
        }
        if (bb0._class.isProper) 
            return null;
        let str0 = str.substring(0, 0 + str.length - 1);
        bb0 = MorphologyService.getWordBaseInfo(str0, MorphLang.RU, true, true);
        if (bb0._class.isProperName && typ === 1 && bb0.number === MorphNumber.SINGULAR) {
            if (str0[str0.length - 1] === str[str.length - 1]) 
                return str0;
        }
        if (bb0._class.isProperSecname && typ === 2 && bb0.number === MorphNumber.SINGULAR) 
            return str0;
        return null;
    }
    
    static initialize() {
        PersonNormalHelper._loadCorrMiddlaTails("слаовна$:славовна\nславона$:славовна\nславоич$:славович\nслаович$:славович\nвнана$:вна\nевана$:евна\nевнва$:евна\nевнаа$:евна\nевнна$:евна\nована$:овна\nовнва$:овна\nовнаа$:овна\nовнна$:овна\nевена$:евна\nевсна$:евна\nевона$:евна\nовена$:овна\nовсна$:овна\nовона$:овна\nовоич$:ович\nевича$:евич\nевичч$:евич\nевивч$:евич\nевиич$:евич\nеваич$:евич\nевнич$:евич\nовича$:ович\nовичч$:ович\nовивч$:ович\nовиич$:ович\nоваич$:ович\nовнич$:ович\nеана$:евна\nенва$:евна\nевнв$:евна\nевне$:евна\nевну$:евна\nевны$:евна\nевеа$:евна\nеван$:евна\nоана$:овна\nонва$:овна\nовнв$:овна\nовне$:овна\nовну$:овна\nовны$:овна\nовеа$:овна\nован$:овна\nевга$:евна\nовга$:овна\nвеич$:евич\nвоич$:ович\nивоч$:ович\nовоч$:ович\nевия$:евич\nевмч$:евич\nеивч$:евич\nеаич$:евич\nивеч$:евич\nевоч$:евич\nовия$:ович\nовмч$:ович\nоивч$:ович\nеаич$:ович\nевн$:евна\nена$:евна\nовн$:овна\nона$:овна\nеич$:евич\nови$:ович\nоич$:ович\nевч$:евич\nеви$:евич\nовч$:ович\nови$:ович\nишна$:ична\nофич$:ович\nефич$:евич\nева$:евна\nова$:овна");
    }
    
    static static_constructor() {
        PersonNormalHelper.corrMiddnameTails = null;
        PersonNormalHelper.m_MaleNames = Array.from(["АНДРЕЙ", "АЛЕКСЕЙ", "АЛЕКСАНДР", "АНАТОЛИЙ", "АРКАДИЙ", "АРТЕМ", "БОРИС", "ВАЛЕНТИН", "ВАЛЕРИЙ", "ВАСИЛИЙ", "ВИКТОР", "ВИТАЛИЙ", "ВЛАДИМИР", "ВЛАДИСЛАВ", "ВСЕВОЛОД", "ГЕННАДИЙ", "ГЕНАДИЙ", "ГЕОРГИЙ", "ГРИГОРИЙ", "ДЕНИС", "ДМИТРИЙ", "ЕВГЕНИЙ", "ЕГОР", "ИВАН", "ИГОРЬ", "КИРИЛЛ", "КОНСТАНТИН", "ЛЕОНИД", "ЛЕВ", "МАКСИМ", "МИХАИЛ", "НИКОЛАЙ", "НИКИТА", "ОЛЕГ", "ПАВЕЛ", "ПЕТР", "РОМАН", "СЕМЕН", "СЕРГЕЙ", "СТАНИСЛАВ", "СТЕПАН", "ФЕДОР", "ЭДУАРД", "ЮРИЙ", "ЯКОВ", "ЯРОСЛАВ"]);
        PersonNormalHelper.m_MaleSecnames = Array.from(["АЛЕКСЕЕВИЧ", "АЛЕКСАНДРОВИЧ", "АНАТОЛЬЕВИЧ", "АЛЬБЕРТОВИЧ", "АНДРЕЕВИЧ", "АРКАДЬЕВИЧ", "АРТЕМОВИЧ", "БОРИСОВИЧ", "ВАЛЕНТИНОВИЧ", "ВАЛЕРЬЕВИЧ", "ВАСИЛЬЕВИЧ", "ВИКТОРОВИЧ", "ВИТАЛЬЕВИЧ", "ВЛАДИМИРОВИЧ", "ВЛАДИСЛАВОВИЧ", "ВСЕВОЛОДОВИЧ", "ГЕННАДИЕВИЧ", "ГЕНАДИЕВИЧ", "ГЕОРГИЕВИЧ", "ГРИГОРЬЕВИЧ", "ДЕНИСОВИЧ", "ДМИТРИЕВИЧ", "ЕВГЕНЬЕВИЧ", "ЕГОРОВИЧ", "ИВАНОВИЧ", "ИГОРЕВИЧ", "ИЛЬИЧ", "КИРИЛЛОВИЧ", "КОНСТАНТИНОВИЧ", "ЛЕОНИДОВИЧ", "ЛЬВОВИЧ", "МАКСИМОВИЧ", "МИХАЙЛОВИЧ", "НИКОЛАЕВИЧ", "НИКИТИЧ", "ОЛЕГОВИЧ", "ПАВЛОВИЧ", "ПЕТРОВИЧ", "РОМАНОВИЧ", "СЕМЕНОВИЧ", "СЕРГЕЕВИЧ", "СТАНИСЛАВОВИЧ", "СТЕПАНОВИЧ", "ФЕДОРОВИЧ", "ЭДУАРДОВИЧ", "ЮРЬЕВИЧ", "ЯКОВЛЕВИЧ", "ЯРОСЛАВОВИЧ"]);
        PersonNormalHelper.m_FemaleSecnames = Array.from(["АЛЕКСЕЕВНА", "АЛЕКСАНДРОВНА", "АНАТОЛЬЕВНА", "АЛЬБЕРТОВНА", "АНДРЕЕВНА", "АРКАДЬЕВНА", "АРТЕМОВНА", "БОРИСОВНА", "ВАЛЕНТИНОВНА", "ВАЛЕРЬЕВНА", "ВАСИЛЬЕВНА", "ВИКТОРОВНА", "ВИТАЛЬЕВНА", "ВЛАДИМИРОВНА", "ВЛАДИСЛАВОВНА", "ВСЕВОЛОДОВНА", "ГЕННАДИЕВНА", "ГЕНАДИЕВНА", "ГЕОРГИЕВНА", "ГРИГОРЬЕВНА", "ДЕНИСОВНА", "ДМИТРИЕВНА", "ЕВГЕНЬЕВНА", "ЕГОРОВНА", "ИВАНОВНА", "ИГОРЕВНА", "ИЛЬИНИЧНА", "КИРИЛЛОВНА", "КОНСТАНТИНОВНА", "ЛЕОНИДОВНА", "ЛЬВОВНА", "МАКСИМОВНА", "МИХАЙЛОВНА", "НИКОЛАЕВНА", "НИКИТИЧНА", "ОЛЕГОВНА", "ПАВЛОВНА", "ПЕТРОВНА", "РОМАНОВНА", "СЕМЕНОВНА", "СЕРГЕЕВНА", "СТАНИСЛАВОВНА", "СТЕПАНОВНА", "ФЕДОРОВНА", "ЭДУАРДОВНА", "ЮРЬЕВНА", "ЯКОВЛЕВНА", "ЯРОСЛАВОВНА"]);
        PersonNormalHelper.m_Fio = new PersonNormalNode(false);
        PersonNormalHelper.m_Iof = new PersonNormalNode(true);
    }
}


PersonNormalHelper.static_constructor();

module.exports = PersonNormalHelper