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

const ConjunctionType = require("./../../ner/core/ConjunctionType");
const SentItemType = require("./SentItemType");
const NGLinkType = require("./NGLinkType");
const ConjunctionToken = require("./../../ner/core/ConjunctionToken");
const SemFraglinkType = require("./../SemFraglinkType");
const DelimType = require("./DelimType");
const DelimToken = require("./DelimToken");

class Subsent {
    
    constructor() {
        this.owner = null;
        this.items = new Array();
        this.delims = new Array();
        this.resFrag = null;
        this.isOr = false;
        this.question = null;
        this.isThenElseRoot = false;
        this.typ = SemFraglinkType.UNDEFINED;
    }
    
    get ownerRoot() {
        let k = 0;
        for (let s = this.owner; s !== null && (k < 100); s = this.owner,k++) {
            if (s.owner === null) 
                return s;
        }
        return null;
    }
    
    check(_typ) {
        for (const d of this.delims) {
            if ((d instanceof DelimToken) && (((d.typ.value()) & (_typ.value()))) !== (DelimType.UNDEFINED.value())) 
                return true;
            else if ((d instanceof ConjunctionToken) && _typ === DelimType.AND) 
                return true;
        }
        return false;
    }
    
    checkOr() {
        for (const d of this.delims) {
            if ((d instanceof ConjunctionToken) && d.typ === ConjunctionType.OR) 
                return true;
        }
        return false;
    }
    
    onlyConj() {
        for (const d of this.delims) {
            if (d instanceof DelimToken) 
                return false;
        }
        return true;
    }
    
    canBeNextInList(next) {
        if (next.delims.length === 0) 
            return true;
        for (const d of next.delims) {
            if (d instanceof DelimToken) {
                if (!this.check(d.typ)) 
                    return false;
            }
        }
        return true;
    }
    
    toString() {
        let tmp = new StringBuilder();
        if (this.isOr) 
            tmp.append("OR ");
        if (this.question !== null) 
            tmp.append("(").append(this.question).append("?) ");
        for (const it of this.delims) {
            tmp.append("<").append(it).append("> ");
        }
        tmp.append('[');
        for (const it of this.items) {
            if (it !== this.items[0]) 
                tmp.append(", ");
            tmp.append(it);
        }
        tmp.append("]");
        if (this.owner !== null) 
            tmp.append(" -> ").append(this.owner);
        return tmp.toString();
    }
    
    hasCommaAnd(b, e) {
        for (const it of this.items) {
            if (it.typ === SentItemType.CONJ) {
                if (it.source.beginToken.beginChar >= b && it.source.endToken.endChar <= e) 
                    return true;
            }
        }
        return false;
    }
    
    static createSubsents(sent) {
        if (sent.items.length === 0) 
            return null;
        let res = new Array();
        let begin = sent.items[0].beginToken.beginChar;
        let end = sent.items[sent.items.length - 1].endToken.endChar;
        let map = new Uint8Array((end + 1) - begin);
        if (sent.bestVar !== null) {
            for (const seg of sent.bestVar.segs) {
                if (seg !== null) {
                    for (const li of seg.links) {
                        if (li !== null && li.typ === NGLinkType.LIST) {
                            for (let i = (li.to === null ? li.toVerb.beginChar : li.to.source.beginToken.beginChar); i <= li.from.source.endToken.endChar; i++) {
                                let po = i - begin;
                                if (po >= 0 && (po < map.length)) 
                                    map[po] = 1;
                            }
                        }
                    }
                }
            }
        }
        let ss = new Subsent();
        let hasVerb = false;
        for (let i = 0; i < sent.items.length; i++) {
            let it = sent.items[i];
            let delim = false;
            if (it.typ === SentItemType.DELIM) 
                delim = true;
            else if (it.typ === SentItemType.CONJ && map[it.beginToken.beginChar - begin] === (0)) {
                delim = true;
                if (it.source.typ === ConjunctionType.COMMA) {
                    if (!hasVerb) 
                        delim = false;
                }
            }
            if (!delim) {
                if (it.typ === SentItemType.VERB) 
                    hasVerb = true;
                ss.items.push(it);
                continue;
            }
            if (ss.items.length === 0) {
                ss.delims.push(it.source);
                continue;
            }
            if (ss.items.length > 0) 
                res.push(ss);
            ss = new Subsent();
            hasVerb = false;
            ss.delims.push(it.source);
        }
        if (ss.items.length > 0) 
            res.push(ss);
        for (let i = 0; i < res.length; i++) {
            let r = res[i];
            let j = 0;
            if (r.check(DelimType.IF)) {
                let hasThen = false;
                let hasElse = false;
                for (j = i + 1; j < res.length; j++) {
                    if (res[j].check(DelimType.THEN)) {
                        if (hasThen) 
                            break;
                        res[j].owner = r;
                        res[j].question = "если";
                        res[j].typ = SemFraglinkType.IFTHEN;
                        hasThen = true;
                        r.isThenElseRoot = true;
                    }
                    else if (res[j].check(DelimType.ELSE)) {
                        if (hasElse) 
                            break;
                        res[j].owner = r;
                        res[j].question = "иначе";
                        res[j].typ = SemFraglinkType.IFELSE;
                        hasElse = true;
                        r.isThenElseRoot = true;
                    }
                    else if (res[j].check(DelimType.IF)) {
                        if (res[j].check(DelimType.AND)) 
                            res[j].owner = r;
                        else 
                            break;
                    }
                }
                if (!hasThen && i > 0) {
                    if (res[0].owner === null && res[0].onlyConj()) {
                        res[0].owner = r;
                        res[0].question = "если";
                        r.isThenElseRoot = true;
                        res[0].typ = SemFraglinkType.IFTHEN;
                    }
                    else if (res[0].owner !== null) {
                        r.owner = res[0];
                        r.question = "если";
                        r.typ = SemFraglinkType.IFTHEN;
                    }
                }
                continue;
            }
            if (r.check(DelimType.BECAUSE)) {
                let hasThen = false;
                for (j = i + 1; j < res.length; j++) {
                    if (res[j].check(DelimType.THEN)) {
                        if (hasThen) 
                            break;
                        res[j].owner = r;
                        res[j].question = "по причине";
                        res[j].typ = SemFraglinkType.BECAUSE;
                        hasThen = true;
                        r.isThenElseRoot = true;
                    }
                }
                if (!hasThen && i > 0) {
                    if (res[0].owner === null && res[0].onlyConj()) {
                        res[0].owner = r;
                        res[0].question = "по причине";
                        r.isThenElseRoot = true;
                        res[0].typ = SemFraglinkType.BECAUSE;
                        continue;
                    }
                }
                if (!hasThen && ((i + 1) < res.length)) {
                    if (res[i + 1].owner === null && res[i + 1].onlyConj()) {
                        res[i + 1].owner = r;
                        res[i + 1].question = "по причине";
                        r.isThenElseRoot = true;
                        res[i + 1].typ = SemFraglinkType.BECAUSE;
                        continue;
                    }
                }
                continue;
            }
            if (r.check(DelimType.BUT)) {
                if (i > 0) {
                    if (res[i - 1].owner === null && res[i - 1].onlyConj()) {
                        res[i - 1].owner = r;
                        res[i - 1].question = "но";
                        r.isThenElseRoot = true;
                        res[i - 1].typ = SemFraglinkType.BUT;
                        continue;
                    }
                }
            }
            if (r.check(DelimType.WHAT)) {
                if (i > 0) {
                    if (res[i - 1].owner === null && res[i - 1].onlyConj()) {
                        res[i - 1].owner = r;
                        res[i - 1].question = "что";
                        r.isThenElseRoot = true;
                        res[i - 1].typ = SemFraglinkType.WHAT;
                        continue;
                    }
                }
            }
            if (r.check(DelimType.FOR)) {
                if ((i + 1) < res.length) {
                    if (res[i + 1].owner === null && res[i + 1].onlyConj()) {
                        res[i + 1].owner = r;
                        res[i + 1].question = "чтобы";
                        r.isThenElseRoot = true;
                        res[i + 1].typ = SemFraglinkType.FOR;
                        continue;
                    }
                }
                if (i > 0) {
                    if (res[i - 1].owner === null && res[i - 1].onlyConj()) {
                        res[i - 1].owner = r;
                        res[i - 1].question = "чтобы";
                        r.isThenElseRoot = true;
                        res[i - 1].typ = SemFraglinkType.FOR;
                        continue;
                    }
                }
            }
        }
        for (let i = 1; i < res.length; i++) {
            let r = res[i];
            if (!r.check(DelimType.AND) || r.owner !== null) 
                continue;
            for (let j = i - 1; j >= 0; j--) {
                let rr = res[j];
                if (rr.canBeNextInList(r) && ((rr.owner === null || ((rr.ownerRoot !== null && rr.ownerRoot.canBeNextInList(r)))))) {
                    if (r.checkOr()) 
                        rr.isOr = true;
                    rr.items.splice(rr.items.length, 0, ...r.items);
                    res.splice(i, 1);
                    i--;
                    break;
                }
            }
        }
        return res;
    }
}


module.exports = Subsent