/*
 * 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 NGItem = require("./NGItem");
const BracketParseAttr = require("./../../ner/core/BracketParseAttr");
const SemAttributeType = require("./../SemAttributeType");
const MorphNumber = require("./../../morph/MorphNumber");
const AdverbToken = require("./AdverbToken");
const BracketHelper = require("./../../ner/core/BracketHelper");
const SemFraglinkType = require("./../SemFraglinkType");
const SemFragment = require("./../SemFragment");
const SemBlock = require("./../SemBlock");
const SentenceVariant = require("./SentenceVariant");
const Subsent = require("./Subsent");
const VerbPhraseToken = require("./../../ner/core/VerbPhraseToken");
const SentItemType = require("./SentItemType");
const NumbersWithUnitToken = require("./../../ner/measure/internal/NumbersWithUnitToken");
const SemLinkType = require("./../SemLinkType");
const NGLinkType = require("./NGLinkType");
const SentItemSubtype = require("./SentItemSubtype");
const SemObjectType = require("./../SemObjectType");
const NounPhraseToken = require("./../../ner/core/NounPhraseToken");
const MorphWordForm = require("./../../morph/MorphWordForm");
const SemObject = require("./../SemObject");
const CreateHelper = require("./CreateHelper");
const NGLink = require("./NGLink");

class Sentence {
    
    constructor() {
        this.items = new Array();
        this.coef = 0;
        this.bestVar = null;
        this.subs = new Array();
        this.resBlock = null;
        this.lastNounToFirstVerb = NGLinkType.UNDEFINED;
        this.notLastNounToFirstVerb = NGLinkType.UNDEFINED;
        this.lastChar = null;
    }
    
    _createLists(s) {
        for (let i = 0; i < s.links.length; i++) {
            let list = s.getList(i);
            if (list === null) 
                continue;
            if (list[0].source.result === null) 
                continue;
            let root = list[0].source;
            root.resultList = new Array();
            for (const li of list) {
                if (li.source.result !== null) 
                    root.resultList.push(li.source.result);
                if (li !== list[0] && li.orBefore) 
                    root.resultListOr = true;
            }
        }
    }
    
    _setLastAltLinks(fr) {
        if (fr.links.length > 1) {
            let li0 = fr.links[fr.links.length - 2];
            let li1 = fr.links[fr.links.length - 1];
            li0.altLink = li1;
            li1.altLink = li0;
        }
    }
    
    _createLinks(s) {
        for (let i = 0; i < s.links.length; i++) {
            let link0 = s.links[i];
            if (link0 === null) 
                continue;
            if (link0.typ === NGLinkType.LIST) 
                continue;
            for (let k = 0; k < 2; k++) {
                let li = link0;
                if (k === 1) 
                    li = li.altLink;
                if (li === null) 
                    break;
                if (li.from.resObject === null) 
                    continue;
                if (k === 1) {
                }
                let gr = li.from.resObject.graph;
                if (li.to !== null && li.to.resObject !== null) {
                    let link = null;
                    if (li.typ === NGLinkType.PARTICIPLE && li.from.source.subTyp === SentItemSubtype.WICH) {
                        link = gr.addLink(SemLinkType.ANAFOR, li.from.resObject, li.to.resObject, null, false, null);
                        if (k > 0) 
                            this._setLastAltLinks(gr);
                        continue;
                    }
                    if (li.typ === NGLinkType.PARTICIPLE && li.from.source.typ === SentItemType.PARTBEFORE) {
                        link = gr.addLink(SemLinkType.PARTICIPLE, li.to.resObject, li.from.resObject, "какой", false, null);
                        if (k > 0) 
                            this._setLastAltLinks(gr);
                        if (li.from.source.resultList !== null && li.typ === NGLinkType.PARTICIPLE) {
                            link.isOr = li.from.source.resultListOr;
                            for (let ii = 1; ii < li.from.source.resultList.length; ii++) {
                                gr.addLink(link.typ, link.source, li.from.source.resultList[ii], link.question, link.isOr, null);
                            }
                        }
                        continue;
                    }
                    if (li.typ === NGLinkType.BE) {
                        if ((li.from.source.source instanceof NumbersWithUnitToken) && li.to !== null) {
                            gr.addLink(SemLinkType.DETAIL, li.to.resObject, li.from.resObject, "какой", false, li.fromPrep);
                            continue;
                        }
                        let be = SemObject._new3820(gr, SemObjectType.VERB);
                        be.tokens.push(li.from.source.source);
                        be.morph.normalCase = (be.morph.normalFull = "БЫТЬ");
                        gr.objects.push(be);
                        gr.addLink(SemLinkType.AGENT, be, li.to.resObject, null, false, null);
                        gr.addLink(SemLinkType.PACIENT, be, li.from.resObject, null, false, null);
                        continue;
                    }
                    let ty = SemLinkType.UNDEFINED;
                    let ques = null;
                    if (li.typ === NGLinkType.GENETIVE) {
                        if (li.canBePacient) 
                            ty = SemLinkType.PACIENT;
                        else {
                            ty = SemLinkType.DETAIL;
                            ques = "чего";
                        }
                        if (!Utils.isNullOrEmpty(li.fromPrep)) 
                            ques = CreateHelper.createQuestion(li.from);
                    }
                    else if (li.typ === NGLinkType.NAME) 
                        ty = SemLinkType.NAMING;
                    link = gr.addLink(ty, li.to.resObject, li.from.resObject, ques, false, li.fromPrep);
                    if (li.from.source.resultList !== null) {
                        link.isOr = li.from.source.resultListOr;
                        for (let ii = 1; ii < li.from.source.resultList.length; ii++) {
                            let link1 = gr.addLink(ty, link.source, li.from.source.resultList[ii], ques, link.isOr, null);
                            link1.preposition = link.preposition;
                        }
                    }
                    let list = null;
                    if (li.toAllListItems) {
                        list = s.getListByLastItem(li.to);
                        if (list !== null) {
                            let ok = true;
                            for (let j = 0; j < (list.length - 1); j++) {
                                if (list[j].resObject !== null && list[j].resObject.linksFrom.length > 0) {
                                    ok = false;
                                    break;
                                }
                            }
                            if (ok) {
                                for (let j = 0; j < (list.length - 1); j++) {
                                    gr.addLink(link.typ, list[j].resObject, link.target, link.question, false, link.preposition);
                                }
                            }
                        }
                    }
                    if (k > 0) 
                        this._setLastAltLinks(gr);
                }
                if (li.toVerb !== null && li.from.resObject !== null) {
                    let link = null;
                    let vitem = null;
                    for (const iii of this.items) {
                        if (iii.source === li.toVerb) {
                            vitem = iii;
                            break;
                        }
                    }
                    if (li.typ === NGLinkType.AGENT && vitem !== null && vitem.result !== null) {
                        let verb = vitem.result;
                        if (verb.typ === SemObjectType.PARTICIPLE && li.canBeParticiple) 
                            link = gr.addLink(SemLinkType.PARTICIPLE, li.from.resObject, verb, "какой", false, null);
                        else 
                            link = gr.addLink(SemLinkType.AGENT, verb, li.from.resObject, null, false, null);
                        if (k > 0) 
                            this._setLastAltLinks(gr);
                    }
                    else if (((li.typ === NGLinkType.PACIENT || li.typ === NGLinkType.ACTANT)) && vitem !== null && vitem.resultVerbLast !== null) {
                        let verb = vitem.resultVerbLast;
                        let ques = null;
                        if (li.typ === NGLinkType.ACTANT) 
                            ques = CreateHelper.createQuestion(li.from);
                        if (verb.typ === SemObjectType.PARTICIPLE && li.typ === NGLinkType.PACIENT && li.canBeParticiple) 
                            link = gr.addLink(SemLinkType.PARTICIPLE, li.from.resObject, verb, "какой", false, null);
                        else 
                            link = gr.addLink((li.typ === NGLinkType.PACIENT ? SemLinkType.PACIENT : SemLinkType.DETAIL), verb, li.from.resObject, ques, false, li.fromPrep);
                        if (k > 0) 
                            this._setLastAltLinks(gr);
                    }
                    if (link === null) 
                        continue;
                    if (li.from.source.resultList !== null) {
                        link.isOr = li.from.source.resultListOr;
                        for (let jj = 1; jj < li.from.source.resultList.length; jj++) {
                            if (link.typ === SemLinkType.PARTICIPLE) 
                                gr.addLink(link.typ, li.from.source.resultList[jj], link.target, link.question, link.isOr, null);
                            else 
                                gr.addLink(link.typ, link.source, li.from.source.resultList[jj], link.question, link.isOr, null);
                        }
                    }
                }
            }
        }
    }
    
    createResult(blk) {
        if (this.bestVar !== null) {
            for (const s of this.bestVar.segs) {
                if (s !== null) 
                    s.correctMorph();
            }
            this.bestVar.createAltLinks();
        }
        let allItems = new Array();
        for (const it of this.items) {
            if (it.resGraph === null) 
                continue;
            if (it.result === null) {
                if (it.source instanceof NounPhraseToken) {
                    let npt = Utils.as(it.source, NounPhraseToken);
                    if (it.plural === 1 && ((it.source.morph.number.value()) & (MorphNumber.PLURAL.value())) !== (MorphNumber.UNDEFINED.value())) 
                        it.source.morph.removeItems(MorphNumber.PLURAL, false);
                    it.result = CreateHelper.createNounGroup(it.resGraph, npt);
                    if (npt.multiNouns && it.result.quantity === null) {
                        it.resultList = new Array();
                        it.resultList.push(it.result);
                        if (npt.adjectives.length > 0 && ((npt.adjectives[0].beginToken.morph.number.value()) & (MorphNumber.SINGULAR.value())) === (MorphNumber.SINGULAR.value())) {
                            it.result.morph.number = MorphNumber.SINGULAR;
                            if (it.result.morph.normalFull !== null) 
                                it.result.morph.normalCase = it.result.morph.normalFull;
                        }
                        for (let i = 1; i < npt.adjectives.length; i++) {
                            let so = SemObject._new3820(it.resGraph, it.result.typ);
                            so.tokens.push(npt.noun);
                            let wf = new MorphWordForm();
                            wf.copyFromWordForm(it.result.morph);
                            so.morph = wf;
                            for (const a of it.result.attrs) {
                                so.attrs.push(a);
                            }
                            so.concept = it.result.concept;
                            so.not = it.result.not;
                            let asem = CreateHelper.createNptAdj(it.resGraph, npt, npt.adjectives[i]);
                            if (asem !== null) 
                                it.resGraph.addLink(SemLinkType.DETAIL, so, asem, "какой", false, null);
                            it.resultList.push(so);
                            it.resGraph.objects.push(so);
                        }
                    }
                }
                else if (it.source instanceof VerbPhraseToken) {
                    it.result = CreateHelper.createVerbGroup(it.resGraph, Utils.as(it.source, VerbPhraseToken));
                    it.resultVerbLast = Utils.as(it.source.lastVerb.tag, SemObject);
                }
                else if (it.source instanceof NumbersWithUnitToken) 
                    it.result = CreateHelper.createNumber(it.resGraph, Utils.as(it.source, NumbersWithUnitToken));
                if (it.result !== null && it.quant !== null) 
                    it.result.quantity = it.quant;
                if (it.result !== null && it.attrs !== null) {
                    for (const a of it.attrs) {
                        it.result.attrs.push(a.attr);
                        it.result.tokens.push(a.token);
                    }
                }
            }
            if (it.result !== null) {
                if (it.result.graph !== it.resGraph) {
                }
                allItems.push(it);
            }
        }
        if (this.bestVar !== null) {
            for (const s of this.bestVar.segs) {
                if (s !== null) 
                    this._createLists(s);
            }
        }
        if (this.bestVar !== null) {
            for (const s of this.bestVar.segs) {
                if (s !== null) 
                    this._createLinks(s);
            }
        }
        for (let i = 0; i < this.items.length; i++) {
            let it = this.items[i];
            if (it.typ !== SentItemType.ADVERB || it.resGraph === null) 
                continue;
            let adv = Utils.as(it.source, AdverbToken);
            if (adv.typ !== SemAttributeType.UNDEFINED) 
                continue;
            let before = null;
            let after = null;
            for (let ii = i - 1; ii >= 0; ii--) {
                let it0 = this.items[ii];
                if (it0.typ === SentItemType.VERB) {
                    before = it0;
                    break;
                }
                else if (it0.typ === SentItemType.ADVERB || it0.typ === SentItemType.NOUN) {
                }
                else 
                    break;
            }
            if (before === null) {
                for (let ii = i - 1; ii >= 0; ii--) {
                    let it0 = this.items[ii];
                    if (it0.typ === SentItemType.VERB || it0.typ === SentItemType.NOUN) {
                        before = it0;
                        break;
                    }
                    else if (it0.typ === SentItemType.ADVERB) {
                    }
                    else 
                        break;
                }
            }
            let commaAfter = false;
            for (let ii = i + 1; ii < this.items.length; ii++) {
                let it0 = this.items[ii];
                if (it0.typ === SentItemType.VERB || it0.typ === SentItemType.NOUN) {
                    after = it0;
                    break;
                }
                else if (it0.typ === SentItemType.ADVERB) {
                }
                else if (it0.canBeCommaEnd) {
                    if (before !== null && before.typ === SentItemType.VERB) 
                        break;
                    if (((ii + 1) < this.items.length) && ((this.items[ii + 1].typ === SentItemType.ADVERB || this.items[ii + 1].typ === SentItemType.VERB))) {
                    }
                    else 
                        commaAfter = true;
                }
                else 
                    break;
            }
            if (before !== null && after !== null) {
                if (commaAfter) 
                    after = null;
                else if (before.typ === SentItemType.NOUN && after.typ === SentItemType.VERB) 
                    before = null;
                else if (before.typ === SentItemType.VERB && after.typ === SentItemType.NOUN) 
                    after = null;
            }
            it.result = CreateHelper.createAdverb(it.resGraph, adv);
            if (it.attrs !== null) {
                for (const a of it.attrs) {
                    it.result.attrs.push(a.attr);
                    it.result.tokens.push(a.token);
                }
            }
            if (after !== null || before !== null) 
                it.resGraph.addLink(SemLinkType.DETAIL, (after === null ? before.result : after.result), it.result, "как", false, null);
        }
        let preds = new Array();
        let agent = null;
        for (const it of this.items) {
            if (it.result !== null && it.typ === SentItemType.VERB && (it.source instanceof VerbPhraseToken)) {
                if (agent !== null) {
                    let hasPac = false;
                    for (const li of it.resGraph.links) {
                        if (li.typ === SemLinkType.PACIENT && li.source === it.result) {
                            hasPac = true;
                            break;
                        }
                    }
                    if (!hasPac) {
                        let ni0 = NGItem._new3813(agent);
                        let gli0 = NGLink._new3826(ni0, Utils.as(it.source, VerbPhraseToken), NGLinkType.PACIENT);
                        if (agent.resultList !== null) {
                            gli0.fromIsPlural = true;
                            gli0.calcCoef(false);
                            if (gli0.coef > 0 && gli0.plural === 1) {
                                for (const ii of agent.resultList) {
                                    it.resGraph.addLink(SemLinkType.PACIENT, it.result, ii, null, false, null);
                                }
                                this.coef += (1);
                            }
                        }
                        else {
                            gli0.calcCoef(true);
                            if (gli0.coef > 0) {
                                it.resGraph.addLink(SemLinkType.PACIENT, it.result, agent.result, null, false, null);
                                this.coef += (1);
                            }
                        }
                    }
                }
                let ali = null;
                for (const li of it.resGraph.links) {
                    if (li.typ === SemLinkType.AGENT && li.source === it.result) {
                        ali = li;
                        break;
                    }
                }
                if (ali !== null) {
                    agent = this._findItemByRes(ali.target);
                    continue;
                }
                if (agent === null) 
                    continue;
                let ni = NGItem._new3813(agent);
                let gli = NGLink._new3826(ni, Utils.as(it.source, VerbPhraseToken), NGLinkType.AGENT);
                if (agent.resultList !== null) {
                    gli.fromIsPlural = true;
                    gli.calcCoef(false);
                    if (gli.coef > 0 && gli.plural === 1) {
                        for (const ii of agent.resultList) {
                            it.resGraph.addLink(SemLinkType.AGENT, it.result, ii, null, false, null);
                        }
                        this.coef += (1);
                    }
                }
                else {
                    gli.calcCoef(true);
                    if (gli.coef > 0) {
                        it.resGraph.addLink(SemLinkType.AGENT, it.result, agent.result, null, false, null);
                        this.coef += (1);
                    }
                }
            }
        }
        agent = null;
        for (let i = 0; i < this.items.length; i++) {
            let it = this.items[i];
            if (it.result !== null && it.typ === SentItemType.DEEPART) {
            }
            else 
                continue;
            let link = null;
            for (let j = i - 1; j >= 0; j--) {
                let itt = this.items[j];
                if (itt.typ !== SentItemType.NOUN) 
                    continue;
                if (!(itt.source.morph._case.isNominative)) 
                    continue;
                let ispacad = false;
                for (const li of itt.resGraph.links) {
                    if (((li.typ === SemLinkType.AGENT || li.typ === SemLinkType.PACIENT)) && li.target === itt.result) 
                        ispacad = true;
                }
                if (!ispacad) 
                    continue;
                if (link === null) 
                    link = itt.resGraph.addLink(SemLinkType.AGENT, it.result, itt.result, null, false, null);
                else if (link.altLink === null) {
                    link.altLink = itt.resGraph.addLink(SemLinkType.AGENT, it.result, itt.result, null, false, null);
                    link.altLink.altLink = link;
                    break;
                }
            }
            if (link === null) {
                for (let j = i + 1; j < this.items.length; j++) {
                    let itt = this.items[j];
                    if (itt.typ !== SentItemType.NOUN) 
                        continue;
                    if (!(itt.source.morph._case.isNominative)) 
                        continue;
                    let ispacad = false;
                    for (const li of itt.resGraph.links) {
                        if (((li.typ === SemLinkType.AGENT || li.typ === SemLinkType.PACIENT)) && li.target === itt.result) 
                            ispacad = true;
                    }
                    if (!ispacad) 
                        continue;
                    if (link === null) 
                        link = itt.resGraph.addLink(SemLinkType.AGENT, it.result, itt.result, null, false, null);
                    else if (link.altLink === null) {
                        link.altLink = itt.resGraph.addLink(SemLinkType.AGENT, it.result, itt.result, null, false, null);
                        link.altLink.altLink = link;
                        break;
                    }
                }
            }
            if (link !== null) 
                this.coef++;
        }
        for (const fr of this.resBlock.fragments) {
            if (fr.canBeErrorStructure) 
                this.coef /= (2);
        }
        if (this.resBlock.fragments.length > 0 && this.resBlock.fragments[0].graph.objects.length > 0) {
            let it = this.resBlock.fragments[0].graph.objects[0];
            if (this.lastChar !== null && this.lastChar.isChar('?')) {
                if (it.morph.normalFull === "КАКОЙ" || it.morph.normalFull === "СКОЛЬКО") 
                    it.typ = SemObjectType.QUESTION;
            }
        }
    }
    
    _findItemByRes(s) {
        for (const it of this.items) {
            if (it.result === s) 
                return it;
        }
        return null;
    }
    
    toString() {
        let res = new StringBuilder();
        if (this.coef > 0) 
            res.append(this.coef).append(": ");
        for (const it of this.items) {
            if (it !== this.items[0]) 
                res.append("; \r\n");
            res.append(it.toString());
        }
        return res.toString();
    }
    
    addToBlock(blk, gr = null) {
        if (this.resBlock !== null) {
            for (const fr of this.resBlock.fragments) {
                fr.rank = this.coef;
            }
            if (gr === null) 
                blk.addFragments(this.resBlock);
            else 
                for (const fr of this.resBlock.fragments) {
                    gr.objects.splice(gr.objects.length, 0, ...fr.graph.objects);
                    gr.links.splice(gr.links.length, 0, ...fr.graph.links);
                }
        }
        for (const it of this.items) {
            if (it.subSent !== null) 
                it.subSent.addToBlock(blk, (gr != null ? gr : it.resFrag.graph));
        }
    }
    
    addToBlockVariants(blk) {
        if (this.resBlock !== null) {
            for (const fr of this.resBlock.fragments) {
                fr.rank = this.coef;
            }
            blk.addFragmentVariantas(this.resBlock);
        }
    }
    
    static parseVariants(t0, t1, lev, maxCount = 0, regime = SentItemType.UNDEFINED) {
        const SentItem = require("./SentItem");
        if ((t0 === null || t1 === null || t0.endChar > t1.endChar) || lev > 100) 
            return null;
        let res = new Array();
        let sent = new Sentence();
        for (let t = t0; t !== null && t.endChar <= t1.endChar; t = t.next) {
            if (t.isChar('(')) {
                let br = BracketHelper.tryParse(t, BracketParseAttr.NO, 100);
                if (br !== null) {
                    t = br.endToken;
                    continue;
                }
            }
            let _items = SentItem.parseNearItems(t, t1, lev + 1, sent.items);
            if (_items === null || _items.length === 0) 
                continue;
            if (_items.length === 1 || ((maxCount > 0 && res.length > maxCount))) {
                sent.items.push(_items[0]);
                t = _items[0].endToken;
                if (regime !== SentItemType.UNDEFINED) {
                    let it = _items[0];
                    if (it.canBeNoun) {
                    }
                    else if (it.typ === SentItemType.DELIM) 
                        break;
                    else if (it.typ === SentItemType.VERB) {
                        if (regime === SentItemType.PARTBEFORE) 
                            break;
                    }
                }
                continue;
            }
            let m_Nexts = new Hashtable();
            for (const it of _items) {
                let nexts = null;
                let wrapnexts3829 = new RefOutArgWrapper();
                let inoutres3830 = m_Nexts.tryGetValue(it.endToken.endChar, wrapnexts3829);
                nexts = wrapnexts3829.value;
                if (!inoutres3830) {
                    nexts = Sentence.parseVariants(it.endToken.next, t1, lev + 1, maxCount, SentItemType.UNDEFINED);
                    m_Nexts.put(it.endToken.endChar, nexts);
                }
                if (nexts === null || nexts.length === 0) {
                    let se = new Sentence();
                    for (const itt of sent.items) {
                        let itt1 = new SentItem(null);
                        itt1.copyFrom(itt);
                        se.items.push(itt1);
                    }
                    let itt0 = new SentItem(null);
                    itt0.copyFrom(it);
                    se.items.push(itt0);
                    res.push(se);
                }
                else 
                    for (const sn of nexts) {
                        let se = new Sentence();
                        for (const itt of sent.items) {
                            let itt1 = new SentItem(null);
                            itt1.copyFrom(itt);
                            se.items.push(itt1);
                        }
                        let itt0 = new SentItem(null);
                        itt0.copyFrom(it);
                        se.items.push(itt0);
                        for (const itt of sn.items) {
                            let itt1 = new SentItem(null);
                            itt1.copyFrom(itt);
                            se.items.push(itt1);
                        }
                        res.push(se);
                    }
            }
            return res;
        }
        if (sent.items.length === 0) 
            return null;
        res.push(sent);
        return res;
    }
    
    compareTo(other) {
        if (this.coef > other.coef) 
            return -1;
        if (this.coef < other.coef) 
            return 1;
        return 0;
    }
    
    calcCoef(noResult) {
        const NGSegment = require("./NGSegment");
        this.coef = 0;
        for (let i = 0; i < this.items.length; i++) {
            let it = this.items[i];
            if (it.typ !== SentItemType.ADVERB) 
                continue;
            let adv = Utils.as(it.source, AdverbToken);
            if (adv.typ === SemAttributeType.UNDEFINED) 
                continue;
            let before = null;
            let after = null;
            for (let ii = i - 1; ii >= 0; ii--) {
                let it0 = this.items[ii];
                if (it0.typ === SentItemType.VERB) {
                    before = it0;
                    break;
                }
                else if (it0.typ === SentItemType.ADVERB) {
                    if (it0.source.typ === SemAttributeType.UNDEFINED) {
                        before = it0;
                        break;
                    }
                }
                else if (it0.canBeCommaEnd) 
                    break;
                else if (it0.typ === SentItemType.FORMULA && ((adv.typ === SemAttributeType.GREAT || adv.typ === SemAttributeType.LESS))) {
                    before = it0;
                    break;
                }
            }
            let commaAfter = false;
            for (let ii = i + 1; ii < this.items.length; ii++) {
                let it0 = this.items[ii];
                if (it0.typ === SentItemType.VERB) {
                    after = it0;
                    break;
                }
                else if (it0.typ === SentItemType.ADVERB) {
                    if (it0.source.typ === SemAttributeType.UNDEFINED) {
                        after = it0;
                        break;
                    }
                }
                else if (it0.canBeCommaEnd) 
                    commaAfter = true;
                else if (it0.typ === SentItemType.FORMULA && ((adv.typ === SemAttributeType.GREAT || adv.typ === SemAttributeType.LESS))) {
                    before = it0;
                    break;
                }
                else if (it0.typ === SentItemType.NOUN) 
                    commaAfter = true;
                else 
                    break;
            }
            if (before !== null && after !== null) {
                if (before.typ === SentItemType.FORMULA) 
                    after = null;
                else if (after.typ === SentItemType.FORMULA) 
                    before = null;
                else if (commaAfter) 
                    after = null;
            }
            if (after !== null) {
                after.addAttr(adv);
                this.items.splice(i, 1);
                i--;
                continue;
            }
            if (before !== null) {
                before.addAttr(adv);
                this.items.splice(i, 1);
                i--;
                continue;
            }
        }
        let segs = NGSegment.createSegments(this);
        if (this.lastNounToFirstVerb !== NGLinkType.UNDEFINED || this.notLastNounToFirstVerb !== NGLinkType.UNDEFINED) {
            if (segs.length !== 1 || segs[0].items.length === 0) {
                if (this.lastNounToFirstVerb !== NGLinkType.UNDEFINED) {
                    this.coef = -1;
                    return;
                }
            }
            else {
                let last = segs[0].items[segs[0].items.length - 1];
                for (let i = last.links.length - 1; i >= 0; i--) {
                    let li = last.links[i];
                    if (this.lastNounToFirstVerb !== NGLinkType.UNDEFINED) {
                        if (li.typ === this.lastNounToFirstVerb && li.toVerb === segs[0].beforeVerb) 
                            li.canBeParticiple = true;
                        else 
                            last.links.splice(i, 1);
                    }
                    else if (this.notLastNounToFirstVerb !== NGLinkType.UNDEFINED) {
                        if (li.typ === this.notLastNounToFirstVerb && li.toVerb === segs[0].beforeVerb) {
                            last.links.splice(i, 1);
                            break;
                        }
                    }
                }
                if (last.links.length === 0) {
                    this.coef = -1;
                    return;
                }
            }
        }
        for (const seg of segs) {
            seg.ind = 0;
            seg.createVariants(100);
        }
        let svars = new Array();
        let svar = null;
        for (let kkk = 0; kkk < 1000; kkk++) {
            if (svar === null) 
                svar = new SentenceVariant();
            else 
                svar.segs.splice(0, svar.segs.length);
            for (let i = 0; i < segs.length; i++) {
                let it = segs[i];
                if (it.ind < it.variants.length) 
                    svar.segs.push(it.variants[it.ind]);
                else 
                    svar.segs.push(null);
            }
            svar.calcCoef();
            if (svar.coef >= 0) {
                svars.push(svar);
                svar = null;
                if (svars.length > 100) {
                    this._sortVars(svars);
                    svars.splice(10, svars.length - 10);
                }
            }
            let j = 0;
            for (j = segs.length - 1; j >= 0; j--) {
                let it = segs[j];
                if ((++it.ind) >= it.variants.length) 
                    it.ind = 0;
                else 
                    break;
            }
            if (j < 0) 
                break;
        }
        this._sortVars(svars);
        if (svars.length > 0) {
            this.bestVar = svars[0];
            this.coef = this.bestVar.coef;
        }
        else {
        }
        for (const it of this.items) {
            if (it.subSent !== null) 
                this.coef += it.subSent.coef;
        }
        for (const it of this.items) {
            if (it.participleCoef > 0) 
                this.coef *= it.participleCoef;
        }
        this.subs = Subsent.createSubsents(this);
        if (this.items.length === 0) 
            return;
        if (noResult) 
            return;
        this.resBlock = new SemBlock(null);
        for (const sub of this.subs) {
            sub.resFrag = new SemFragment(this.resBlock);
            this.resBlock.fragments.push(sub.resFrag);
            sub.resFrag.isOr = sub.isOr;
            for (const it of sub.items) {
                if (sub.resFrag.beginToken === null) 
                    sub.resFrag.beginToken = it.beginToken;
                sub.resFrag.endToken = it.endToken;
                if (it.resGraph !== null) {
                }
                it.resGraph = sub.resFrag.graph;
                it.resFrag = sub.resFrag;
            }
        }
        for (const sub of this.subs) {
            if (sub.resFrag === null || sub.owner === null || sub.owner.resFrag === null) 
                continue;
            if (sub.typ === SemFraglinkType.UNDEFINED) 
                continue;
            this.resBlock.addLink(sub.typ, sub.resFrag, sub.owner.resFrag, sub.question);
        }
        this.createResult(this.resBlock);
    }
    
    _sortVars(vars) {
        vars.sort((a, b) => a.compareTo(b));
    }
    
    truncOborot(isParticiple) {
        if (this.bestVar === null || this.bestVar.segs.length === 0) {
            if (this.items.length > 1) {
                this.items.splice(1, this.items.length - 1);
                return true;
            }
            return false;
        }
        let ret = false;
        let ind = 0;
        if (this.bestVar.segs[0] === null && !isParticiple) {
            for (ind = 1; ind < this.items.length; ind++) {
                if (this.items[ind].canBeCommaEnd) 
                    break;
            }
        }
        else 
            for (const seg of this.bestVar.segs) {
                if (seg === null) 
                    break;
                for (const li of seg.links) {
                    if (li === null) 
                        continue;
                    ret = true;
                    let ii = this.items.indexOf(li.from.source);
                    if (ii < 0) 
                        continue;
                    if (li.toVerb !== null) {
                        if (li.toVerb === seg.source.beforeVerb) 
                            ind = ii + 1;
                        else if (!isParticiple && seg === this.bestVar.segs[0] && li.toVerb === seg.source.afterVerb) {
                            for (ii = ind; ii < this.items.length; ii++) {
                                if (this.items[ii].source === li.toVerb) {
                                    ind = ii + 1;
                                    break;
                                }
                            }
                        }
                        else 
                            break;
                    }
                    else {
                        let jj = this.items.indexOf(li.to.source);
                        if (jj < 0) 
                            continue;
                        if (jj < ii) 
                            ind = ii + 1;
                        else 
                            break;
                    }
                }
                if (!isParticiple && seg === this.bestVar.segs[0]) {
                }
                else 
                    break;
            }
        if (!ret && ind === 0) {
            for (ind = 1; ind < this.items.length; ind++) {
                if (this.items[ind].canBeCommaEnd) 
                    break;
            }
        }
        if (ind > 0 && (ind < (this.items.length - 1))) 
            this.items.splice(ind, this.items.length - ind);
        return ret;
    }
    
    static _new3843(_arg1) {
        let res = new Sentence();
        res.lastNounToFirstVerb = _arg1;
        return res;
    }
}


module.exports = Sentence