/*
 * 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# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;

namespace Pullenti.Morph
{
    /// <summary>
    /// Сервис морфологического анализа текстов (POS-tagger).
    /// </summary>
    public static class MorphologyService
    {
        /// <summary>
        /// Инициализация внутренних словарей. 
        /// Можно не вызывать, но тогда будет автоматически вызвано при первом обращении к морфологии, 
        /// и соответственно первый разбор отработает на несколько секунд дольше. 
        /// Если используете Sdk.Initialize() или ProcessorService.Initialize(), то тогда эту функцию вызывать не нужно, 
        /// так как там внутри это делается.
        /// </summary>
        /// <param name="langs">по умолчанию, русский и английский</param>
        public static void Initialize(MorphLang langs = null)
        {
            if (m_Initialized) 
                return;
            Pullenti.Morph.Internal.UnicodeInfo.Initialize();
            if (langs == null || langs.IsUndefined) 
                langs = MorphLang.RU | MorphLang.EN;
            m_Morph.LoadLanguages(langs, LazyLoad);
            m_Initialized = true;
        }
        static bool m_Initialized = false;
        /// <summary>
        /// Языки, морфологические словари для которых загружены в память
        /// </summary>
        public static MorphLang LoadedLanguages
        {
            get
            {
                return m_Morph.LoadedLanguages;
            }
        }
        /// <summary>
        /// Загрузить язык(и), если они ещё не загружены
        /// </summary>
        /// <param name="langs">загружаемые языки</param>
        public static void LoadLanguages(MorphLang langs)
        {
            m_Morph.LoadLanguages(langs, LazyLoad);
        }
        /// <summary>
        /// Выгрузить язык(и), если они больше не нужны
        /// </summary>
        /// <param name="langs">выгружаемые языки</param>
        public static void UnloadLanguages(MorphLang langs)
        {
            m_Morph.UnloadLanguages(langs);
        }
        static List<MorphWordForm> m_EmptyWordForms = new List<MorphWordForm>();
        static MorphMiscInfo m_EmptyMisc = new MorphMiscInfo();
        /// <summary>
        /// Произвести чистую токенизацию без формирования морф-вариантов
        /// </summary>
        /// <param name="text">исходный текст</param>
        /// <return>последовательность результирующих лексем</return>
        public static List<MorphToken> Tokenize(string text)
        {
            if (string.IsNullOrEmpty(text)) 
                return null;
            List<MorphToken> res = m_Morph.Run(text, true, MorphLang.Unknown, false, null);
            if (res != null) 
            {
                foreach (MorphToken r in res) 
                {
                    if (r.WordForms == null) 
                        r.WordForms = m_EmptyWordForms;
                    foreach (MorphWordForm wf in r.WordForms) 
                    {
                        if (wf.Misc == null) 
                            wf.Misc = m_EmptyMisc;
                    }
                }
            }
            return res;
        }
        /// <summary>
        /// Произвести морфологический анализ текста. Если используете морфологию в составе лингвистического процессора из 
        /// ProcessorService, то эту функцию явно вызывать не придётся.
        /// </summary>
        /// <param name="text">исходный текст</param>
        /// <param name="lang">базовый язык (если null, то будет определён автоматически)</param>
        /// <param name="progress">это для бегунка</param>
        /// <return>последовательность результирующих лексем MorphToken</return>
        public static List<MorphToken> Process(string text, MorphLang lang = null, ProgressChangedEventHandler progress = null)
        {
            if (string.IsNullOrEmpty(text)) 
                return null;
            if (!m_Initialized) 
                throw new Exception("Pullenti Morphology Service not initialized");
            List<MorphToken> res = m_Morph.Run(text, false, lang, false, progress);
            if (res != null) 
            {
                foreach (MorphToken r in res) 
                {
                    if (r.WordForms == null) 
                        r.WordForms = m_EmptyWordForms;
                    foreach (MorphWordForm wf in r.WordForms) 
                    {
                        if (wf.Misc == null) 
                            wf.Misc = m_EmptyMisc;
                    }
                }
            }
            return res;
        }
        /// <summary>
        /// Получить все варианты словоформ для нормальной формы слова
        /// </summary>
        /// <param name="word">нормальная форма слова (лемма), в верхнем регистре</param>
        /// <param name="lang">язык (по умолчанию, русский)</param>
        /// <return>список словоформ MorphWordForm</return>
        public static List<MorphWordForm> GetAllWordforms(string word, MorphLang lang = null)
        {
            if (word == null) 
                return null;
            if (!m_Initialized) 
                throw new Exception("Pullenti Morphology Service not initialized");
            foreach (char ch in word) 
            {
                if (char.IsLower(ch)) 
                {
                    word = word.ToUpper();
                    break;
                }
            }
            List<MorphWordForm> res = m_Morph.GetAllWordforms(word, lang);
            if (res != null) 
            {
                foreach (MorphWordForm r in res) 
                {
                    if (r.Misc == null) 
                        r.Misc = m_EmptyMisc;
                }
            }
            return res;
        }
        /// <summary>
        /// Извлечь из встроенных словарей вообще все словоформы заданного типа (в именительном падеже единственном числе)
        /// </summary>
        /// <param name="cla">части речи</param>
        /// <param name="lang">языки (по умолчанию, все)</param>
        /// <return>список словоформ</return>
        public static List<MorphWordForm> GetAllWordsByClass(MorphClass cla, MorphLang lang = null)
        {
            if (!m_Initialized) 
                throw new Exception("Pullenti Morphology Service not initialized");
            List<MorphWordForm> res = m_Morph.GetAllWordsByClass(cla, lang);
            return res;
        }
        /// <summary>
        /// Получить вариант написания словоформы
        /// </summary>
        /// <param name="word">слово</param>
        /// <param name="morphInfo">морфологическая информация</param>
        /// <return>вариант написания</return>
        public static string GetWordform(string word, MorphBaseInfo morphInfo)
        {
            if (morphInfo == null || string.IsNullOrEmpty(word)) 
                return word;
            if (!m_Initialized) 
                throw new Exception("Pullenti Morphology Service not initialized");
            int ii = word.IndexOf('-');
            if (ii > 0) 
            {
                string s1 = word.Substring(0, ii).Trim();
                MorphWordForm bi = GetWordBaseInfo(s1, null, false, false);
                if (bi.Class.IsAdverb || ((bi.Misc != null && bi.Misc.Attrs.Contains("к.ф.")))) 
                {
                }
                else 
                {
                    string p1 = GetWordform(s1, morphInfo);
                    string p2 = GetWordform(word.Substring(ii + 1).Trim(), morphInfo);
                    if (p1 == null || p1 == null) 
                        return word;
                    return string.Format("{0}-{1}", p1, p2);
                }
            }
            MorphClass cla = morphInfo.Class;
            if (cla.IsUndefined) 
            {
                try 
                {
                    MorphWordForm mi0 = GetWordBaseInfo(word, null, false, false);
                    if (mi0 != null) 
                        cla = mi0.Class;
                }
                catch(Exception ex37) 
                {
                }
            }
            string word1 = word;
            foreach (char ch in word) 
            {
                if (char.IsLower(ch)) 
                {
                    word1 = word.ToUpper();
                    break;
                }
            }
            MorphWordForm wf = morphInfo as MorphWordForm;
            string res = m_Morph.GetWordform(word1, cla, morphInfo.Gender, morphInfo.Case, morphInfo.Number, morphInfo.Language, wf);
            if (string.IsNullOrEmpty(res)) 
                return word;
            return res;
        }
        /// <summary>
        /// Получить для словоформы род\число\падеж
        /// </summary>
        /// <param name="word">словоформа</param>
        /// <param name="lang">возможный язык</param>
        /// <param name="isCaseNominative">исходное слово в именительном падеже (иначе считается падеж любым)</param>
        /// <param name="inDictOnly">при true не строить гипотезы для несловарных слов</param>
        /// <return>базовая морфологическая информация</return>
        public static MorphWordForm GetWordBaseInfo(string word, MorphLang lang = null, bool isCaseNominative = false, bool inDictOnly = false)
        {
            if (!m_Initialized) 
                throw new Exception("Pullenti Morphology Service not initialized");
            List<MorphToken> mt = m_Morph.Run(word, false, lang, false, null);
            MorphWordForm bi = new MorphWordForm();
            MorphClass cla = new MorphClass();
            if (mt != null && mt.Count > 0) 
            {
                for (int k = 0; k < 2; k++) 
                {
                    bool ok = false;
                    foreach (MorphWordForm wf in mt[0].WordForms) 
                    {
                        if (k == 0) 
                        {
                            if (!wf.IsInDictionary) 
                                continue;
                        }
                        else if (wf.IsInDictionary) 
                            continue;
                        if (isCaseNominative) 
                        {
                            if (!wf.Case.IsNominative && !wf.Case.IsUndefined) 
                                continue;
                        }
                        cla.Value |= wf.Class.Value;
                        bi.Gender |= wf.Gender;
                        bi.Case |= wf.Case;
                        bi.Number |= wf.Number;
                        if (wf.Misc != null && bi.Misc == null) 
                            bi.Misc = wf.Misc;
                        ok = true;
                    }
                    if (ok || inDictOnly) 
                        break;
                }
            }
            bi.Class = cla;
            return bi;
        }
        /// <summary>
        /// Попробовать откорректировать одну букву словоформы, чтобы получилось словарное слово. 
        /// Делается изменение одной буквы, удаление одной буквы и вставка одной буквы. 
        /// Если получается несколько вариантов, то возвращается null. Для получение всех вариантов используйте CorrectWordEx.
        /// </summary>
        /// <param name="word">искаженное слово</param>
        /// <param name="lang">возможный язык</param>
        /// <return>откорректированное слово или null при невозможности</return>
        public static string CorrectWord(string word, MorphLang lang = null)
        {
            List<string> vars = m_Morph.CorrectWordByMorph(word, lang, true);
            if (vars == null || vars.Count != 1) 
                return null;
            return vars[0];
        }
        /// <summary>
        /// Попробовать откорректировать одну букву словоформы, чтобы получилось словарное слово. 
        /// Делается изменение одной буквы, удаление одной буквы и вставка одной буквы.
        /// </summary>
        /// <param name="word">искаженное слово</param>
        /// <param name="lang">возможный язык</param>
        /// <return>"правильные" варианты или null</return>
        public static List<string> CorrectWordEx(string word, MorphLang lang = null)
        {
            return m_Morph.CorrectWordByMorph(word, lang, false);
        }
        /// <summary>
        /// Преобразовать наречие в прилагательное (это пока только для русского языка)
        /// </summary>
        /// <param name="adverb">наречие</param>
        /// <param name="bi">род число падеж</param>
        /// <return>прилагательное</return>
        public static string ConvertAdverbToAdjective(string adverb, MorphBaseInfo bi)
        {
            if (adverb == null || (adverb.Length < 4)) 
                return null;
            char last = adverb[adverb.Length - 1];
            if (last != 'О' && last != 'Е') 
                return adverb;
            string var1 = adverb.Substring(0, adverb.Length - 1) + "ИЙ";
            string var2 = adverb.Substring(0, adverb.Length - 1) + "ЫЙ";
            try 
            {
                MorphWordForm bi1 = GetWordBaseInfo(var1, null, false, false);
                MorphWordForm bi2 = GetWordBaseInfo(var2, null, false, false);
                string var = var1;
                if (!bi1.Class.IsAdjective && bi2.Class.IsAdjective) 
                    var = var2;
                if (bi == null) 
                    return var;
                return m_Morph.GetWordform(var, MorphClass.Adjective, bi.Gender, bi.Case, bi.Number, MorphLang.Unknown, null) ?? var;
            }
            catch(Exception ex38) 
            {
            }
            return var1;
        }
        // При и нициализации не грузить всю морфологиюю сразу в память, а подгружать по мере необходимости.
        // Сильно экономит время (при инициализации) и память.
        public static bool LazyLoad = true;
        static Pullenti.Morph.Internal.InnerMorphology m_Morph = new Pullenti.Morph.Internal.InnerMorphology();
    }
}