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

const ConjunctionType = require("./../../ner/core/ConjunctionType");
const NGLinkType = require("./NGLinkType");
const NGLink = require("./NGLink");
const ConjunctionToken = require("./../../ner/core/ConjunctionToken");
const SentItemType = require("./SentItemType");
const NGItem = require("./NGItem");
const VerbPhraseToken = require("./../../ner/core/VerbPhraseToken");
const NGSegmentVariant = require("./NGSegmentVariant");

class NGSegment {
    
    constructor() {
        this.beforeVerb = null;
        this.items = new Array();
        this.afterVerb = null;
        this.variants = new Array();
        this.ind = 0;
    }
    
    toString() {
        let tmp = new StringBuilder();
        if (this.beforeVerb !== null) 
            tmp.append("<").append(this.beforeVerb.toString()).append(">: ");
        for (const it of this.items) {
            if (it !== this.items[0]) 
                tmp.append("; \r\n");
            tmp.append(it.toString());
        }
        if (this.afterVerb !== null) 
            tmp.append(" :<").append(this.afterVerb.toString()).append(">");
        return tmp.toString();
    }
    
    static createSegments(s) {
        let res = new Array();
        for (let i = 0; i < s.items.length; i++) {
            let it = s.items[i];
            if (it.typ === SentItemType.VERB || it.typ === SentItemType.DELIM) 
                continue;
            let seg = new NGSegment();
            let nit = NGItem._new3813(it);
            for (let j = i - 1; j >= 0; j--) {
                it = s.items[j];
                if (it.typ === SentItemType.VERB) {
                    seg.beforeVerb = Utils.as(it.source, VerbPhraseToken);
                    break;
                }
                if (it.typ === SentItemType.DELIM) 
                    break;
                if (it.canBeCommaEnd) {
                    if (it.source.typ === ConjunctionType.COMMA) 
                        nit.commaBefore = true;
                    else {
                        nit.andBefore = true;
                        if (it.source.typ === ConjunctionType.OR) 
                            nit.orBefore = true;
                    }
                }
                if (it.typ === SentItemType.CONJ || it.canBeNoun) 
                    break;
            }
            let comma = false;
            let and = false;
            let or = false;
            for (; i < s.items.length; i++) {
                it = s.items[i];
                if (it.canBeCommaEnd) {
                    comma = false;
                    and = false;
                    or = false;
                    if (it.source.typ === ConjunctionType.COMMA) 
                        comma = true;
                    else {
                        and = true;
                        if (it.source.typ === ConjunctionType.OR) 
                            or = true;
                    }
                    if (seg.items.length > 0) {
                        if (comma) 
                            seg.items[seg.items.length - 1].commaAfter = true;
                        else {
                            seg.items[seg.items.length - 1].andAfter = true;
                            if (or) 
                                seg.items[seg.items.length - 1].orAfter = true;
                        }
                    }
                    continue;
                }
                if (it.canBeNoun || it.typ === SentItemType.ADVERB) {
                    nit = NGItem._new3814(it, comma, and, or);
                    seg.items.push(nit);
                    comma = false;
                    and = false;
                    or = false;
                }
                else if (it.typ === SentItemType.VERB || it.typ === SentItemType.CONJ || it.typ === SentItemType.DELIM) 
                    break;
            }
            for (let j = i; j < s.items.length; j++) {
                it = s.items[j];
                if (it.typ === SentItemType.VERB) {
                    seg.afterVerb = Utils.as(it.source, VerbPhraseToken);
                    break;
                }
                if ((it.typ === SentItemType.CONJ || it.canBeNoun || it.typ === SentItemType.DELIM) || it.typ === SentItemType.ADVERB) 
                    break;
            }
            res.push(seg);
        }
        for (const ss of res) {
            ss.createLinks(false);
        }
        return res;
    }
    
    createLinks(afterPart = false) {
        for (let i = 0; i < this.items.length; i++) {
            this.items[i].order = i;
            this.items[i].prepare();
        }
        let li = null;
        for (let i = 0; i < this.items.length; i++) {
            let it = this.items[i];
            if (it.source.typ === SentItemType.ADVERB) 
                continue;
            let ignoreBefore = false;
            let mult = 1;
            if (it.commaBefore || it.andBefore) {
                for (let j = i - 1; j >= 0; j--) {
                    if (li === null) 
                        li = new NGLink();
                    li.typ = NGLinkType.LIST;
                    li.from = it;
                    li.to = this.items[j];
                    li.toVerb = null;
                    li.calcCoef(false);
                    if (li.coef >= 0) {
                        it.links.push(li);
                        li = null;
                    }
                    if (it.source.typ === SentItemType.PARTBEFORE || it.source.typ === SentItemType.SUBSENT || it.source.typ === SentItemType.DEEPART) {
                        if (it.commaBefore) {
                            if (li === null) 
                                li = new NGLink();
                            li.typ = NGLinkType.PARTICIPLE;
                            li.from = it;
                            li.to = this.items[j];
                            li.toVerb = null;
                            li.calcCoef(false);
                            if (li.coef >= 0) {
                                it.links.push(li);
                                li = null;
                            }
                        }
                    }
                    if ((!it.andBefore && it.source.typ === SentItemType.NOUN && this.items[j].source.typ === SentItemType.NOUN) && this.items[i - 1].source.typ === SentItemType.PARTBEFORE) {
                        let ok = true;
                        for (let jj = j + 1; jj < i; jj++) {
                            if ((this.items[jj].source.typ === SentItemType.DELIM || this.items[jj].source.typ === SentItemType.NOUN || this.items[jj].source.typ === SentItemType.SUBSENT) || this.items[jj].source.typ === SentItemType.PARTBEFORE) {
                            }
                            else {
                                ok = false;
                                break;
                            }
                        }
                        if (ok) {
                            if (li === null) 
                                li = new NGLink();
                            li.typ = NGLinkType.GENETIVE;
                            li.from = it;
                            li.to = this.items[j];
                            li.toVerb = null;
                            li.calcCoef(false);
                            if (li.coef >= 0) {
                                it.links.push(li);
                                li = null;
                            }
                        }
                    }
                }
                ignoreBefore = true;
            }
            else {
                for (let j = i - 1; j >= 0; j--) {
                    if (this.items[j].source.typ === SentItemType.SUBSENT) 
                        continue;
                    if (li === null) 
                        li = new NGLink();
                    li.typ = NGLinkType.GENETIVE;
                    li.from = it;
                    li.to = this.items[j];
                    li.toVerb = null;
                    li.calcCoef(false);
                    if (li.coef >= 0) {
                        it.links.push(li);
                        li = null;
                    }
                    if (li === null) 
                        li = new NGLink();
                    li.typ = NGLinkType.NAME;
                    li.from = it;
                    li.to = this.items[j];
                    li.toVerb = null;
                    li.calcCoef(false);
                    if (li.coef >= 0) {
                        it.links.push(li);
                        li = null;
                    }
                    let nodelim = true;
                    for (let jj = j + 1; jj <= i; jj++) {
                        if (this.items[jj].commaBefore || this.items[jj].andBefore) {
                            nodelim = false;
                            break;
                        }
                    }
                    if (nodelim) {
                        if (li === null) 
                            li = new NGLink();
                        li.typ = NGLinkType.BE;
                        li.from = it;
                        li.to = this.items[j];
                        li.toVerb = null;
                        li.calcCoef(false);
                        if (li.coef >= 0) {
                            it.links.push(li);
                            li = null;
                        }
                    }
                    if (it.source.typ === SentItemType.PARTBEFORE || it.source.typ === SentItemType.SUBSENT || it.source.typ === SentItemType.DEEPART) {
                        let hasDelim = false;
                        for (let jj = i - 1; jj > j; jj--) {
                            if (this.items[jj].source.canBeCommaEnd) {
                                hasDelim = true;
                                break;
                            }
                        }
                        if (hasDelim) {
                            if (li === null) 
                                li = new NGLink();
                            li.typ = NGLinkType.PARTICIPLE;
                            li.from = it;
                            li.to = this.items[j];
                            li.toVerb = null;
                            li.calcCoef(false);
                            if (li.coef >= 0) {
                                it.links.push(li);
                                li = null;
                            }
                        }
                    }
                    if (this.items[j].source.typ === SentItemType.PARTBEFORE) 
                        mult *= 0.5;
                    if (this.items[j].source.typ === SentItemType.VERB) {
                        ignoreBefore = true;
                        break;
                    }
                }
                if (this.beforeVerb !== null && !ignoreBefore && it.source.typ !== SentItemType.DEEPART) {
                    let ok = false;
                    if (li === null) 
                        li = new NGLink();
                    li.typ = NGLinkType.AGENT;
                    li.from = it;
                    li.to = null;
                    li.toVerb = this.beforeVerb;
                    li.calcCoef(false);
                    li.coef *= mult;
                    if (li.coef >= 0) {
                        it.links.push(li);
                        ok = true;
                        li = null;
                    }
                    if (li === null) 
                        li = new NGLink();
                    li.typ = NGLinkType.PACIENT;
                    li.from = it;
                    li.to = null;
                    li.toVerb = this.beforeVerb;
                    li.calcCoef(false);
                    li.coef *= mult;
                    if (li.coef >= 0) {
                        it.links.push(li);
                        ok = true;
                        li = null;
                    }{
                            if (li === null) 
                                li = new NGLink();
                            li.typ = NGLinkType.ACTANT;
                            li.from = it;
                            li.to = null;
                            li.toVerb = this.beforeVerb;
                            li.calcCoef(false);
                            li.coef *= mult;
                            if (ok) 
                                li.coef /= (2);
                            if (li.coef >= 0) {
                                it.links.push(li);
                                ok = true;
                                li = null;
                            }
                        }
                }
            }
            if (this.afterVerb !== null && it.source.typ !== SentItemType.DEEPART) {
                let ok = false;
                if (afterPart && this.beforeVerb !== null) {
                    for (const l of it.links) {
                        if (l.toVerb === this.beforeVerb && ((l.typ === NGLinkType.AGENT || l.typ === NGLinkType.PACIENT))) 
                            ok = true;
                    }
                    if (ok) 
                        continue;
                }
                if (li === null) 
                    li = new NGLink();
                li.typ = NGLinkType.AGENT;
                li.from = it;
                li.to = null;
                li.toVerb = this.afterVerb;
                li.calcCoef(false);
                if (li.coef >= 0) {
                    it.links.push(li);
                    ok = true;
                    li = null;
                }
                if (li === null) 
                    li = new NGLink();
                li.typ = NGLinkType.PACIENT;
                li.from = it;
                li.to = null;
                li.toVerb = this.afterVerb;
                li.calcCoef(false);
                if (li.coef >= 0) {
                    it.links.push(li);
                    ok = true;
                    li = null;
                }
                if (li === null) 
                    li = new NGLink();
                li.typ = NGLinkType.ACTANT;
                li.from = it;
                li.to = null;
                li.toVerb = this.afterVerb;
                li.calcCoef(false);
                if (li.coef >= 0) {
                    it.links.push(li);
                    ok = true;
                    li = null;
                }
            }
        }
        for (let i = 1; i < this.items.length; i++) {
            let it = this.items[i];
            if (it.source.typ !== SentItemType.NOUN) 
                continue;
            let it0 = this.items[i - 1];
            if (it0.source.typ !== SentItemType.NOUN) 
                continue;
            if (it0.links.length > 0) 
                continue;
            li = NGLink._new3815(NGLinkType.GENETIVE, it0, it, true);
            li.calcCoef(true);
            if (li.coef > 0) 
                it0.links.push(li);
        }
    }
    
    createVariants(maxCount = 5) {
        this.variants.splice(0, this.variants.length);
        for (let i = 0; i < this.items.length; i++) {
            this.items[i].ind = 0;
        }
        let _var = null;
        for (let kkk = 0; kkk < 1000; kkk++) {
            if (_var === null) 
                _var = NGSegmentVariant._new3816(this);
            else 
                _var.links.splice(0, _var.links.length);
            for (let i = 0; i < this.items.length; i++) {
                let it = this.items[i];
                if (it.ind < it.links.length) 
                    _var.links.push(it.links[it.ind]);
                else 
                    _var.links.push(null);
            }
            _var.calcCoef();
            if (_var.coef >= 0) {
                this.variants.push(_var);
                _var = null;
                if (this.variants.length > (maxCount * 5)) {
                    NGSegment._sortVars(this.variants);
                    this.variants.splice(maxCount, this.variants.length - maxCount);
                }
            }
            let j = 0;
            for (j = this.items.length - 1; j >= 0; j--) {
                let it = this.items[j];
                if ((++it.ind) >= it.links.length) 
                    it.ind = 0;
                else 
                    break;
            }
            if (j < 0) 
                break;
        }
        NGSegment._sortVars(this.variants);
        if (this.variants.length > maxCount) 
            this.variants.splice(maxCount, this.variants.length - maxCount);
    }
    
    static _sortVars(vars) {
        vars.sort((a, b) => a.compareTo(b));
    }
}


module.exports = NGSegment