/*
 * 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 SentItemType = require("./SentItemType");
const MetaToken = require("./../../ner/MetaToken");
const TextToken = require("./../../ner/TextToken");
const NGItem = require("./NGItem");
const SentItem = require("./SentItem");
const SemanticService = require("./../SemanticService");
const MorphNumber = require("./../../morph/MorphNumber");
const MorphGender = require("./../../morph/MorphGender");
const MorphCase = require("./../../morph/MorphCase");
const NGLinkType = require("./NGLinkType");
const NGLink = require("./NGLink");

class NGSegmentVariant {
    
    constructor() {
        this.coef = 0;
        this.source = null;
        this.links = new Array();
    }
    
    toString() {
        let res = new StringBuilder();
        res.append(this.coef).append(" = ");
        for (const it of this.links) {
            if (it !== this.links[0]) 
                res.append("; \r\n");
            if (it === null) 
                res.append("<null>");
            else 
                res.append(it.toString());
        }
        return res.toString();
    }
    
    static _compareListItemTails(mt1, mt2) {
        let t1 = Utils.as(mt1.endToken, TextToken);
        let t2 = Utils.as(mt2.endToken, TextToken);
        if (t1 === null || t2 === null) 
            return true;
        let k = 0;
        let i1 = t1.term.length - 1;
        let i2 = t2.term.length - 1;
        for (; i1 > 0 && i2 > 0; i1--,i2--,k++) {
            if (t1.term[i1] !== t2.term[i2]) 
                break;
        }
        if (k >= 2) 
            return true;
        let nn = t2.getNormalCaseText(null, MorphNumber.SINGULAR, MorphGender.UNDEFINED, false);
        if (t1.isValue(nn, null)) 
            return true;
        if (((t1.morph.number.value()) & (t2.morph.number.value())) === (MorphNumber.UNDEFINED.value())) 
            return false;
        if ((MorphCase.ooBitand(t1.morph._case, t2.morph._case)).isUndefined) 
            return false;
        if (t1.morph._class.isVerb !== t2.morph._class.isVerb && t1.morph._class.isAdjective !== t2.morph._class.isAdjective) 
            return false;
        return true;
    }
    
    calcCoef() {
        this.coef = 0;
        for (const it of this.links) {
            if (it !== null) 
                this.coef += it.coef;
        }
        for (let i = 0; i < this.links.length; i++) {
            let li1 = this.links[i];
            if (li1 === null || li1.to === null) 
                continue;
            if (li1.reverce) 
                continue;
            let i0 = li1.to.order;
            if (i0 >= li1.from.order) 
                return this.coef = -1;
            for (let k = i0 + 1; k < i; k++) {
                let li = this.links[k];
                if (li === null) 
                    continue;
                if (li.toVerb !== null) 
                    return this.coef = -1;
                let i1 = li.to.order;
                if ((i1 < i0) || i1 > i) 
                    return this.coef = -1;
                if (li.typ === NGLinkType.LIST && li1.typ === NGLinkType.LIST && i0 === i1) 
                    return this.coef = -1;
            }
        }
        for (let i = 0; i < this.links.length; i++) {
            let list = this.getList(i);
            if (list === null) 
                continue;
            let k = 0;
            for (k = 1; k < (list.length - 1); k++) {
                if (list[k].andBefore) 
                    break;
            }
            if (k >= (list.length - 1) && list[k].andBefore) 
                this.coef += SemanticService.PARAMS.list;
            else {
                let ors = 0;
                let ands = 0;
                for (k = 1; k < list.length; k++) {
                    if (list[k].orBefore) 
                        ors++;
                    else if (list[k].andBefore) 
                        ands++;
                }
                if (ands > 0 && ors > 0) 
                    return this.coef = -1;
                for (k = 1; k < list.length; k++) {
                    if (!list[k].andBefore) 
                        break;
                }
                if (k >= list.length) {
                }
                else 
                    return this.coef = -1;
            }
            let ngli = NGLink._new3817(NGLinkType.LIST);
            for (k = 0; k < (list.length - 2); k++) {
                for (let kk = k + 2; kk < list.length; kk++) {
                    ngli.from = list[kk];
                    ngli.to = list[k];
                    ngli.calcCoef(false);
                    if (ngli.coef < 0) 
                        return this.coef = -1;
                }
            }
            let prepIsNotExiAll = false;
            for (k = 0; k < (list.length - 1); k++) {
                for (let kk = k + 1; kk < list.length; kk++) {
                    if (!NGSegmentVariant._compareListItemTails(list[k].source.source, list[kk].source.source)) 
                        this.coef /= (2);
                    if (Utils.isNullOrEmpty(list[k].source.prep) !== Utils.isNullOrEmpty(list[kk].source.prep)) {
                        let str1 = list[k].source.endToken.getNormalCaseText(null, MorphNumber.SINGULAR, MorphGender.UNDEFINED, false);
                        let str2 = list[kk].source.endToken.getNormalCaseText(null, MorphNumber.SINGULAR, MorphGender.UNDEFINED, false);
                        if (str1 !== str2) 
                            prepIsNotExiAll = true;
                    }
                }
            }
            if (prepIsNotExiAll) 
                this.coef /= (2);
            let last = list[list.length - 1];
            let ok = true;
            let lalink = null;
            for (const ll of this.links) {
                if (ll !== null && ll.typ === NGLinkType.GENETIVE) {
                    if (ll.to === last) 
                        lalink = ll;
                    else if (list.includes(ll.to)) {
                        ok = false;
                        break;
                    }
                }
            }
            if (!ok || lalink === null) 
                continue;
            let test = NGLink._new3818(lalink.from, lalink.typ);
            let j = 0;
            for (j = 0; j < (list.length - 1); j++) {
                test.to = list[j];
                let ord = test.to.order;
                test.to.order = last.order;
                test.calcCoef(false);
                test.to.order = ord;
                if (test.coef < 0) 
                    break;
            }
            if (j >= (list.length - 1)) 
                lalink.toAllListItems = true;
        }
        let befAg = 0;
        let befPac = 0;
        let aftAg = 0;
        let aftPac = 0;
        for (let i = 0; i < this.links.length; i++) {
            let li = this.links[i];
            if (li === null) 
                continue;
            if (li.typ === NGLinkType.LIST) 
                continue;
            if (li.typ === NGLinkType.PARTICIPLE) {
                if (li.from.source.partVerbTyp !== NGLinkType.UNDEFINED) {
                }
            }
            if ((li.typ === NGLinkType.AGENT || li.typ === NGLinkType.PACIENT || li.typ === NGLinkType.GENETIVE) || li.typ === NGLinkType.PARTICIPLE) {
                if (li.plural === 1) {
                    let ok = false;
                    if (li.typ === NGLinkType.PARTICIPLE && li.to !== null && this.getList(li.to.order) !== null) 
                        ok = true;
                    else if (li.typ !== NGLinkType.PARTICIPLE && this.getList(i) !== null) 
                        ok = true;
                    else {
                        let co = li.coef;
                        li.calcCoef(true);
                        if (li.coef > 0) 
                            ok = true;
                        li.coef = co;
                        li.plural = 1;
                    }
                    if (!ok) 
                        return this.coef = -1;
                }
                else if (li.plural === 0) {
                    if (li.typ !== NGLinkType.PARTICIPLE && this.getList(i) !== null) 
                        return this.coef = -1;
                    if (li.typ === NGLinkType.PARTICIPLE && li.to !== null && this.getList(li.to.order) !== null) 
                        return this.coef = -1;
                }
            }
            if (li.typ === NGLinkType.AGENT || li.typ === NGLinkType.PACIENT || li.typ === NGLinkType.ACTANT) {
            }
            else 
                continue;
            if (li.toVerb !== null && li.toVerb === this.source.beforeVerb) {
                if (this.source.afterVerb !== null && !this.source.beforeVerb.firstVerb.isParticiple) {
                    let hasDelim = false;
                    let ind = li.from.order;
                    let list = this.getList(ind);
                    if (list !== null) 
                        ind = list[list.length - 1].order;
                    for (let ii = ind; ii < this.source.items.length; ii++) {
                        if (this.source.items[ii].andAfter || this.source.items[ii].commaAfter) 
                            hasDelim = true;
                    }
                    if (!hasDelim) 
                        return this.coef = -1;
                }
                if (li.typ === NGLinkType.AGENT && li.toVerb.firstVerb.isDeeParticiple) {
                    let hasDelim = false;
                    for (let ii = 0; ii <= li.from.order; ii++) {
                        if (this.source.items[ii].andBefore || this.source.items[ii].commaBefore) 
                            hasDelim = true;
                    }
                    if (!hasDelim) 
                        return this.coef = -1;
                }
                if (li.typ === NGLinkType.AGENT) 
                    befAg++;
                else if (li.typ === NGLinkType.PACIENT) 
                    befPac++;
                if (li.from.source.subSent !== null) 
                    continue;
            }
            else if (li.toVerb !== null && li.toVerb === this.source.afterVerb) {
                if (this.source.beforeVerb !== null && !this.source.beforeVerb.firstVerb.isParticiple) {
                    let hasDelim = false;
                    for (let ii = 0; ii <= li.from.order; ii++) {
                        if (this.source.items[ii].andBefore || this.source.items[ii].commaBefore) 
                            hasDelim = true;
                    }
                    if (!hasDelim) 
                        return this.coef = -1;
                }
                if (li.from.source.subSent !== null) 
                    continue;
                if (li.typ === NGLinkType.AGENT) 
                    aftAg++;
                else if (li.typ === NGLinkType.PACIENT) 
                    aftPac++;
            }
            if (li.typ === NGLinkType.ACTANT) 
                continue;
        }
        if ((befAg > 1 || befPac > 1 || aftAg > 1) || aftPac > 1) 
            return this.coef = -1;
        for (let i = 0; i < this.links.length; i++) {
            let li = this.links[i];
            if (li === null) 
                continue;
            if (li.typ !== NGLinkType.ACTANT || li.toVerb === null) 
                continue;
        }
        for (let i = 0; i < this.links.length; i++) {
            let li = this.links[i];
            if (li === null) 
                continue;
            if (li.typ !== NGLinkType.GENETIVE || li.to === null) 
                continue;
            if (li.from.source.typ === SentItemType.FORMULA) {
                for (const li0 of this.links) {
                    if ((li0 !== null && li0 !== li && li0.typ === NGLinkType.GENETIVE) && li0.from === li.to) 
                        this.coef /= (2);
                }
            }
            if (li.to.source.typ === SentItemType.FORMULA) {
                for (const li0 of this.links) {
                    if ((li0 !== null && li0 !== li && li0.typ === NGLinkType.GENETIVE) && li0.to === li.to) {
                        if (li0.from.order < li.from.order) 
                            this.coef /= (2);
                    }
                }
            }
        }
        return this.coef;
    }
    
    compareTo(other) {
        if (this.coef > other.coef) 
            return -1;
        if (this.coef < other.coef) 
            return 1;
        return 0;
    }
    
    getListByLastItem(it) {
        let res = new Array();
        res.push(it);
        for (let i = this.links.length - 1; i >= 0; i--) {
            if ((this.links[i] !== null && this.links[i].from === it && this.links[i].typ === NGLinkType.LIST) && this.links[i].to !== null) {
                it = this.links[i].to;
                res.splice(0, 0, it);
            }
        }
        if (res.length > 1) 
            return res;
        return null;
    }
    
    getList(ord) {
        if (ord >= this.source.items.length) 
            return null;
        let li = this.links[ord];
        if (li === null) 
            return null;
        let res = null;
        let ngit = this.source.items[ord];
        if (li.typ === NGLinkType.LIST) {
            if (li.toVerb === null) 
                return null;
            res = new Array();
            res.push(NGItem._new3819(new SentItem(li.toVerb), ord - 1));
            res.push(ngit);
        }
        for (let i = ord + 1; i < this.links.length; i++) {
            li = this.links[i];
            if (li === null || li.typ !== NGLinkType.LIST || li.to === null) 
                continue;
            if (li.to === ngit) {
                if (res === null) {
                    res = new Array();
                    res.push(ngit);
                }
                ngit = this.source.items[i];
                res.push(ngit);
            }
        }
        return res;
    }
    
    correctMorph() {
        for (let i = 0; i < this.links.length; i++) {
            let li = this.links[i];
            if (li === null) 
                continue;
            if (li.typ === NGLinkType.AGENT || li.typ === NGLinkType.PACIENT) {
                if (li.plural === 1) {
                    let list = this.getList(i);
                    if (list !== null) 
                        continue;
                    li.from.source.plural = 1;
                }
            }
        }
    }
    
    static _new3816(_arg1) {
        let res = new NGSegmentVariant();
        res.source = _arg1;
        return res;
    }
}


module.exports = NGSegmentVariant