/*
 * 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("./../pullenti/unisharp/Utils");
const Stopwatch = require("./../pullenti/unisharp/Stopwatch");

const ReferentToken = require("./../pullenti/ner/ReferentToken");
const NounPhraseParseAttr = require("./../pullenti/ner/core/NounPhraseParseAttr");
const KeywordReferent = require("./../pullenti/ner/keyword/KeywordReferent");
const MorphNumber = require("./../pullenti/morph/MorphNumber");
const GetTextAttr = require("./../pullenti/ner/core/GetTextAttr");
const MorphGender = require("./../pullenti/morph/MorphGender");
const MetaToken = require("./../pullenti/ner/MetaToken");
const SourceOfAnalysis = require("./../pullenti/ner/SourceOfAnalysis");
const ReferentsEqualType = require("./../pullenti/ner/core/ReferentsEqualType");
const MiscHelper = require("./../pullenti/ner/core/MiscHelper");
const NounPhraseHelper = require("./../pullenti/ner/core/NounPhraseHelper");
const ProcessorService = require("./../pullenti/ner/ProcessorService");
const ServerService = require("./../pullenti/ner/ServerService");
const KeywordAnalyzer = require("./../pullenti/ner/keyword/KeywordAnalyzer");
const Sdk = require("./../pullenti/Sdk");

class Program {
    
    static main(args) {
        let vers = ServerService.getServerVersion(null);
        if (vers !== null) {
            process.stdout.write("Server version = " + vers);
            if (vers === ProcessorService.getVersion()) 
                process.stdout.write(" (equal with current SDK)" + "\r\n");
            else 
                process.stdout.write(" (but version of current SDK " + ProcessorService.getVersion() + ")!" + "\r\n");
            let sres = ServerService.processOnServer(null, null, "В США прядь волос третьего президента Соединенных Штатов Томаса\nДжефферсона продали на аукционе в Техасе за 6,9 тысячи долларов,\nпередает Life. Локоны бывшего лидера США ушли с молотка почти\nчерез 190 лет после его смерти. Их покупатель пожелал остаться\nнеизвестным. Перед началом аукциона волосы Джефферсона оценивали\nв 3 тысячи долларов. В январе 2015 года прядь волос 16-го президента\nСША Авраама Линкольна продали за 25 тысяч долларов на аукционе в Далласе.", null);
            process.stdout.write("Server result: " + sres.toString() + "\r\n");
        }
        let sw = new Stopwatch();
        // инициализация - необходимо проводить один раз до обработки текстов
        process.stdout.write("Initializing SDK Pullenti ver " + Sdk.getVersion() + " (" + Sdk.getVersionDate() + ") ... ");
        // инициализируются движок и все имеющиеся анализаторы
        Sdk.initializeAll();
        sw.stop();
        process.stdout.write("OK (by " + (sw.elapsedMilliseconds) + " ms), version " + ProcessorService.getVersion() + "\r\n");
        // посмотрим, какие анализаторы доступны
        for (const a of ProcessorService.getAnalyzers()) {
            process.stdout.write("   " + (a.isSpecific ? "Specific analyzer" : "Common analyzer") + " " + a.name + " \"" + a.caption + "\"" + "\r\n");
        }
        // анализируемый текст
        let txt = "Система разрабатывается с 2011 года российским программистом Михаилом Жуковым, проживающим в Москве на Красной площади в доме номер один на втором этаже. Конкурентов у него много: Abbyy, Yandex, ООО \"Russian Context Optimizer\" (RCO) и другие компании. Он планирует продать SDK за 1.120.000.001,99 (миллиард сто двадцать миллионов один рубль 99 копеек) рублей, без НДС.";
        process.stdout.write("Text: " + txt + "\r\n");
        // запускаем обработку на пустом процессоре (без анализаторов NER)
        let are = ProcessorService.getEmptyProcessor().process(new SourceOfAnalysis(txt), null, null);
        process.stdout.write("Noun groups: ");
        // перебираем токены
        for (let t = are.firstToken; t !== null; t = t.next) {
            // выделяем именную группу с текущего токена
            let npt = NounPhraseHelper.tryParse(t, NounPhraseParseAttr.NO, 0, null);
            // не получилось
            if (npt === null) 
                continue;
            // получилось, выводим в нормализованном виде
            process.stdout.write("[" + npt.getSourceText() + "=>" + npt.getNormalCaseText(null, MorphNumber.SINGULAR, MorphGender.UNDEFINED, false) + "] ");
            // указатель на последний токен именной группы
            t = npt.endToken;
        }
        let proc = null;
        proc = ProcessorService.createProcessor(); 
        try {
            // анализируем текст
            let ar = proc.process(new SourceOfAnalysis(txt), null, null);
            // результирующие сущности
            process.stdout.write("\r\n==========================================\r\nEntities: " + "\r\n");
            for (const e of ar.entities) {
                process.stdout.write(e.typeName + ": " + e.toString() + "\r\n");
                for (const s of e.slots) {
                    process.stdout.write("   " + s.typeName + ": " + s.value + "\r\n");
                }
            }
            // пример выделения именных групп
            process.stdout.write("\r\n==========================================\r\nNoun groups: " + "\r\n");
            for (let t = ar.firstToken; t !== null; t = t.next) {
                // токены с сущностями игнорируем
                if (t.getReferent() !== null) 
                    continue;
                // пробуем создать именную группу
                let npt = NounPhraseHelper.tryParse(t, NounPhraseParseAttr.ADJECTIVECANBELAST, 0, null);
                // не получилось
                if (npt === null) 
                    continue;
                process.stdout.write(String(npt) + "\r\n");
                // указатель перемещаем на последний токен группы
                t = npt.endToken;
            }
            // попробуем проанализировать через сервер (если он запущен, естественно)
            let serverAddress = "http://localhost:1111";
            let serverSdkVersion = ServerService.getServerVersion(serverAddress);
            if (serverSdkVersion === null) 
                process.stdout.write("Server not exists on " + serverAddress + ", OK" + "\r\n");
            else {
                process.stdout.write("Server SDK Version: " + serverSdkVersion + "\r\n");
                // желательно проверить тождественность версий, а то мало ли...
                if (serverSdkVersion !== ProcessorService.getVersion()) 
                    process.stdout.write("Server version " + serverSdkVersion + " not equals current SDK version " + ProcessorService.getVersion() + "\r\n");
                else 
                    try {
                        // по идее, должны получить абсолютно эквивалентный результат, что и в ar
                        let ar2 = ServerService.processOnServer(serverAddress, proc, txt, null);
                        if (ar2 === null) 
                            process.stdout.write("Server execution ERROR! " + "\r\n");
                        else if (ar2.entities.length !== ar.entities.length) 
                            process.stdout.write("Entities on server = " + ar2.entities.length + ", but on local = " + ar.entities.length + "\r\n");
                        else {
                            let eq = true;
                            for (let i = 0; i < ar2.entities.length; i++) {
                                if (!ar2.entities[i].canBeEquals(ar.entities[i], ReferentsEqualType.WITHINONETEXT)) {
                                    process.stdout.write("Server entity '" + ar2.entities[i] + "' not equal local entity '" + ar.entities[i] + "'" + "\r\n");
                                    eq = false;
                                }
                            }
                            if (eq) 
                                process.stdout.write("Process on server equals local process!" + "\r\n");
                        }
                    } catch (ex) {
                        process.stdout.write("Process on server error: " + ex.message + "\r\n");
                    }
            }
        }
        finally {
            proc.close();
        }
        proc = ProcessorService.createSpecificProcessor(KeywordAnalyzer.ANALYZER_NAME); 
        try {
            let ar = proc.process(new SourceOfAnalysis(txt), null, null);
            process.stdout.write("\r\n==========================================\r\nKeywords1: " + "\r\n");
            for (const e of ar.entities) {
                if (e instanceof KeywordReferent) 
                    process.stdout.write(String(e) + "\r\n");
            }
            process.stdout.write("\r\n==========================================\r\nKeywords2: " + "\r\n");
            for (let t = ar.firstToken; t !== null; t = t.next) {
                if (t instanceof ReferentToken) {
                    let kw = Utils.as(t.getReferent(), KeywordReferent);
                    if (kw === null) 
                        continue;
                    let kwstr = MiscHelper.getTextValueOfMetaToken(Utils.as(t, ReferentToken), GetTextAttr.of((GetTextAttr.FIRSTNOUNGROUPTONOMINATIVESINGLE.value()) | (GetTextAttr.KEEPREGISTER.value())));
                    process.stdout.write(kwstr + " = " + kw + "\r\n");
                }
            }
        }
        finally {
            proc.close();
        }
        process.stdout.write("Over!" + "\r\n");
    }
}


module.exports = Program