/*
 * 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 MetaToken = require("./../../ner/MetaToken");
const MorphCase = require("./../../morph/MorphCase");
const SemLinkType = require("./../SemLinkType");
const SemQuantity = require("./../SemQuantity");
const MeasureReferent = require("./../../ner/measure/MeasureReferent");
const SemAttributeType = require("./../SemAttributeType");
const MorphNumber = require("./../../morph/MorphNumber");
const MorphAspect = require("./../../morph/MorphAspect");
const MorphGender = require("./../../morph/MorphGender");
const LanguageHelper = require("./../../morph/LanguageHelper");
const AdverbToken = require("./AdverbToken");
const SemAttribute = require("./../SemAttribute");
const MorphClass = require("./../../morph/MorphClass");
const MorphBaseInfo = require("./../../morph/MorphBaseInfo");
const MorphWordForm = require("./../../morph/MorphWordForm");
const TextToken = require("./../../ner/TextToken");
const SemObject = require("./../SemObject");
const NumberToken = require("./../../ner/NumberToken");
const ReferentToken = require("./../../ner/ReferentToken");
const DerivateService = require("./../utils/DerivateService");
const SemObjectType = require("./../SemObjectType");
const NumberHelper = require("./../../ner/core/NumberHelper");

class CreateHelper {
    
    static _setMorph(obj, wf) {
        if (wf === null) 
            return;
        obj.morph.normalCase = wf.normalCase;
        obj.morph.normalFull = (wf.normalFull != null ? wf.normalFull : wf.normalCase);
        obj.morph.number = wf.number;
        obj.morph.gender = wf.gender;
        obj.morph.misc = wf.misc;
    }
    
    static _setMorph0(obj, bi) {
        obj.morph.number = bi.number;
        obj.morph.gender = bi.gender;
    }
    
    static createNounGroup(gr, npt) {
        let noun = npt.noun.beginToken;
        let sem = new SemObject(gr);
        sem.tokens.push(npt.noun);
        sem.typ = SemObjectType.NOUN;
        if (npt.noun.morph._class.isPersonalPronoun) 
            sem.typ = SemObjectType.PERSONALPRONOUN;
        else if (npt.noun.morph._class.isPronoun) 
            sem.typ = SemObjectType.PRONOUN;
        if (npt.noun.beginToken !== npt.noun.endToken) {
            sem.morph.normalCase = npt.noun.getNormalCaseText(null, MorphNumber.UNDEFINED, MorphGender.UNDEFINED, false);
            sem.morph.normalFull = npt.noun.getNormalCaseText(null, MorphNumber.SINGULAR, MorphGender.UNDEFINED, false);
            sem.morph._class = MorphClass.NOUN;
            sem.morph.number = npt.morph.number;
            sem.morph.gender = npt.morph.gender;
            sem.morph._case = npt.morph._case;
        }
        else if (noun instanceof TextToken) {
            for (const wf of noun.morph.items) {
                if (wf.checkAccord(npt.morph, false, false) && (wf instanceof MorphWordForm)) {
                    CreateHelper._setMorph(sem, Utils.as(wf, MorphWordForm));
                    break;
                }
            }
            if (sem.morph.normalCase === null) {
                sem.morph.normalCase = noun.getNormalCaseText(null, MorphNumber.UNDEFINED, MorphGender.UNDEFINED, false);
                sem.morph.normalFull = noun.getNormalCaseText(null, MorphNumber.SINGULAR, MorphGender.UNDEFINED, false);
            }
            let grs = DerivateService.findDerivates(sem.morph.normalFull, true, null);
            if (grs !== null && grs.length > 0) 
                sem.concept = grs[0];
        }
        else if (noun instanceof ReferentToken) {
            let r = noun.referent;
            if (r === null) 
                return null;
            sem.morph.normalFull = (sem.morph.normalCase = r.toString());
            sem.concept = r;
        }
        else if (noun instanceof NumberToken) {
            let num = Utils.as(noun, NumberToken);
            sem.morph.gender = noun.morph.gender;
            sem.morph.number = noun.morph.number;
            if (num.intValue !== null) {
                sem.morph.normalCase = NumberHelper.getNumberAdjective(num.intValue, noun.morph.gender, noun.morph.number);
                sem.morph.normalFull = NumberHelper.getNumberAdjective(num.intValue, MorphGender.MASCULINE, MorphNumber.SINGULAR);
            }
            else 
                sem.morph.normalFull = (sem.morph.normalCase = noun.getSourceText().toUpperCase());
        }
        noun.tag = sem;
        if (npt.adjectives.length > 0) {
            for (const a of npt.adjectives) {
                if (npt.multiNouns && a !== npt.adjectives[0]) 
                    break;
                let asem = CreateHelper.createNptAdj(gr, npt, a);
                if (asem !== null) 
                    gr.addLink(SemLinkType.DETAIL, sem, asem, "какой", false, null);
            }
        }
        if (npt.internalNoun !== null) {
            let intsem = CreateHelper.createNounGroup(gr, npt.internalNoun);
            if (intsem !== null) 
                gr.addLink(SemLinkType.DETAIL, sem, intsem, null, false, null);
        }
        gr.objects.push(sem);
        return sem;
    }
    
    static createNumber(gr, num) {
        let rs = num.createRefenetsTokensWithRegister(null, null, false);
        if (rs === null || rs.length === 0) 
            return null;
        let mr = Utils.as(rs[rs.length - 1].referent, MeasureReferent);
        let sem = new SemObject(gr);
        gr.objects.push(sem);
        sem.tokens.push(num);
        sem.morph.normalFull = (sem.morph.normalCase = mr.toStringEx(true, null, 0));
        sem.typ = SemObjectType.NOUN;
        sem.measure = mr.kind;
        for (let i = 0; i < sem.morph.normalCase.length; i++) {
            let ch = sem.morph.normalCase[i];
            if (Utils.isDigit(ch) || Utils.isWhitespace(ch) || "[].+-".indexOf(ch) >= 0) 
                continue;
            sem.quantity = new SemQuantity(sem.morph.normalCase.substring(0, 0 + i).trim(), num.beginToken, num.endToken);
            sem.morph.normalCase = sem.morph.normalCase.substring(i).trim();
            if (num.units.length === 1 && num.units[0].unit !== null) {
                sem.morph.normalFull = num.units[0].unit.fullnameCyr;
                if (sem.morph.normalFull === "%") 
                    sem.morph.normalFull = "процент";
            }
            break;
        }
        sem.concept = mr;
        return sem;
    }
    
    static createAdverb(gr, adv) {
        let res = new SemObject(gr);
        gr.objects.push(res);
        res.tokens.push(adv);
        res.typ = SemObjectType.ADVERB;
        res.not = adv.not;
        res.morph.normalCase = (res.morph.normalFull = adv.spelling);
        let grs = DerivateService.findDerivates(res.morph.normalFull, true, null);
        if (grs !== null && grs.length > 0) 
            res.concept = grs[0];
        return res;
    }
    
    static createNptAdj(gr, npt, a) {
        if (a.morph._class.isPronoun) {
            let asem = new SemObject(gr);
            gr.objects.push(asem);
            asem.tokens.push(a);
            asem.typ = (a.beginToken.morph._class.isPersonalPronoun ? SemObjectType.PERSONALPRONOUN : SemObjectType.PRONOUN);
            for (const it of a.beginToken.morph.items) {
                let wf = Utils.as(it, MorphWordForm);
                if (wf === null) 
                    continue;
                if (!npt.morph._case.isUndefined) {
                    if ((MorphCase.ooBitand(npt.morph._case, wf._case)).isUndefined) 
                        continue;
                }
                CreateHelper._setMorph(asem, wf);
                if (asem.morph.normalFull === "КАКОВ") 
                    asem.morph.normalFull = "КАКОЙ";
                break;
            }
            if (asem.morph.normalFull === null) 
                asem.morph.normalFull = (asem.morph.normalCase = a.getNormalCaseText(null, MorphNumber.UNDEFINED, MorphGender.UNDEFINED, false));
            return asem;
        }
        if (!a.morph._class.isVerb) {
            let asem = new SemObject(gr);
            gr.objects.push(asem);
            asem.tokens.push(a);
            asem.typ = SemObjectType.ADJECTIVE;
            for (const wf of a.beginToken.morph.items) {
                if (wf.checkAccord(npt.morph, false, false) && wf._class.isAdjective && (wf instanceof MorphWordForm)) {
                    CreateHelper._setMorph(asem, Utils.as(wf, MorphWordForm));
                    break;
                }
            }
            if (asem.morph.normalCase === null) {
                asem.morph.normalCase = a.getNormalCaseText(MorphClass.ADJECTIVE, MorphNumber.UNDEFINED, MorphGender.UNDEFINED, false);
                asem.morph.normalFull = a.getNormalCaseText(MorphClass.ADJECTIVE, MorphNumber.SINGULAR, MorphGender.MASCULINE, false);
                CreateHelper._setMorph0(asem, a.beginToken.morph);
            }
            let grs = DerivateService.findDerivates(asem.morph.normalFull, true, null);
            if (grs !== null && grs.length > 0) 
                asem.concept = grs[0];
            return asem;
        }
        return null;
    }
    
    static createVerbGroup(gr, vpt) {
        let sems = new Array();
        let attrs = new Array();
        let adverbs = new Array();
        for (let i = 0; i < vpt.items.length; i++) {
            let v = vpt.items[i];
            if (v.isAdverb) {
                let adv = AdverbToken.tryParse(v.beginToken);
                if (adv === null) 
                    continue;
                if (adv.typ !== SemAttributeType.UNDEFINED) {
                    attrs.push(SemAttribute._new3799(adv.not, adv.typ, adv.spelling));
                    continue;
                }
                let adverb = CreateHelper.createAdverb(gr, adv);
                if (attrs.length > 0) {
                    adverb.attrs.splice(adverb.attrs.length, 0, ...attrs);
                    attrs.splice(0, attrs.length);
                }
                adverbs.push(adverb);
                continue;
            }
            if (v.normal === "БЫТЬ") {
                let j = 0;
                for (j = i + 1; j < vpt.items.length; j++) {
                    if (!vpt.items[j].isAdverb) 
                        break;
                }
                if (j < vpt.items.length) 
                    continue;
            }
            let sem = new SemObject(gr);
            gr.objects.push(sem);
            sem.tokens.push(v);
            v.tag = sem;
            CreateHelper._setMorph(sem, v.verbMorph);
            sem.morph.normalCase = (sem.morph.normalFull = v.normal);
            if (v.isParticiple || v.isDeeParticiple) {
                sem.typ = SemObjectType.PARTICIPLE;
                sem.morph.normalFull = Utils.notNull(v.endToken.getNormalCaseText(MorphClass.VERB, MorphNumber.UNDEFINED, MorphGender.UNDEFINED, false), (sem !== null && sem.morph !== null ? sem.morph.normalCase : null));
                sem.morph.normalCase = v.endToken.getNormalCaseText(MorphClass.ADJECTIVE, MorphNumber.UNDEFINED, MorphGender.UNDEFINED, false);
                if (sem.morph.normalCase === sem.morph.normalFull && v.normal.endsWith("Й")) {
                    let grs2 = DerivateService.findDerivates(v.normal, true, null);
                    if (grs2 !== null) {
                        for (const g of grs2) {
                            for (const w of g.words) {
                                if (w.lang.equals(v.endToken.morph.language) && w._class.isVerb && !w._class.isAdjective) {
                                    sem.morph.normalFull = w.spelling;
                                    break;
                                }
                            }
                        }
                    }
                }
                else if (sem.morph.normalCase === sem.morph.normalFull && v.isParticiple && sem.morph.normalFull.endsWith("Ь")) {
                    for (const it of v.endToken.morph.items) {
                        let wf = Utils.as(it, MorphWordForm);
                        if (wf === null) 
                            continue;
                        if (wf.normalCase.endsWith("Й") || ((wf.normalFull !== null && wf.normalFull.endsWith("Й")))) {
                            sem.morph.normalCase = (wf.normalFull != null ? wf.normalFull : wf.normalCase);
                            break;
                        }
                    }
                    if (sem.morph.normalCase === sem.morph.normalFull) {
                        let grs2 = DerivateService.findDerivates(sem.morph.normalCase, true, null);
                        if (grs2 !== null) {
                            for (const g of grs2) {
                                for (const w of g.words) {
                                    if (w.lang.equals(v.endToken.morph.language) && w._class.isVerb && w._class.isAdjective) {
                                        sem.morph.normalCase = w.spelling;
                                        break;
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            }
            else 
                sem.typ = SemObjectType.VERB;
            if (v.verbMorph !== null && v.verbMorph.containsAttr("возвр.", null)) {
                if (sem.morph.normalFull.endsWith("СЯ") || sem.morph.normalFull.endsWith("СЬ")) 
                    sem.morph.normalFull = sem.morph.normalFull.substring(0, 0 + sem.morph.normalFull.length - 2);
            }
            let grs = DerivateService.findDerivates(sem.morph.normalFull, true, null);
            if (grs !== null && grs.length > 0) {
                sem.concept = grs[0];
                if (v.verbMorph !== null && v.verbMorph.misc.aspect === MorphAspect.IMPERFECTIVE) {
                    for (const w of grs[0].words) {
                        if (w._class.isVerb && !w._class.isAdjective) {
                            if (w.aspect === MorphAspect.PERFECTIVE) {
                                sem.morph.normalFull = w.spelling;
                                break;
                            }
                        }
                    }
                }
            }
            sem.not = v.not;
            sems.push(sem);
            if (attrs.length > 0) {
                sem.attrs.splice(sem.attrs.length, 0, ...attrs);
                attrs.splice(0, attrs.length);
            }
            if (adverbs.length > 0) {
                for (const a of adverbs) {
                    gr.addLink(SemLinkType.DETAIL, sem, a, "как", false, null);
                }
            }
            adverbs.splice(0, adverbs.length);
        }
        if (sems.length === 0) 
            return null;
        if (attrs.length > 0) 
            sems[sems.length - 1].attrs.splice(sems[sems.length - 1].attrs.length, 0, ...attrs);
        if (adverbs.length > 0) {
            let sem = sems[sems.length - 1];
            for (const a of adverbs) {
                gr.addLink(SemLinkType.DETAIL, sem, a, "как", false, null);
            }
        }
        for (let i = sems.length - 1; i > 0; i--) {
            gr.addLink(SemLinkType.DETAIL, sems[i - 1], sems[i], "что делать", false, null);
        }
        return sems[0];
    }
    
    static createQuestion(li) {
        let res = ((li.source.prep != null ? li.source.prep : "")).toLowerCase();
        if (res.length > 0) 
            res += " ";
        let cas = li.source.source.morph._case;
        if (!Utils.isNullOrEmpty(li.source.prep)) {
            let cas1 = LanguageHelper.getCaseAfterPreposition(li.source.prep);
            if (!cas1.isUndefined) {
                if (!(MorphCase.ooBitand(cas1, cas)).isUndefined) 
                    cas = MorphCase.ooBitand(cas, cas1);
            }
        }
        if (cas.isGenitive) 
            res += "чего";
        else if (cas.isInstrumental) 
            res += "чем";
        else if (cas.isDative) 
            res += "чему";
        else if (cas.isAccusative) 
            res += "что";
        else if (cas.isPrepositional) 
            res += "чём";
        return res;
    }
}


module.exports = CreateHelper