/*
 * SDK Pullenti Unitext, 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
 */

package com.pullenti.util;

/**
 * Различные утилитки работы с текстами
 */
public class TextHelper {

    /**
     * Преобразовать текст в список слов (разделителем является любой пробельный символ)
     * @param text 
     * @return 
     */
    public static java.util.List<String> getWords(String text) {
        if (text == null) 
            return null;
        java.util.ArrayList<String> res = new java.util.ArrayList<String>();
        for (int i = 0; i < text.length(); i++) {
            if (com.pullenti.unisharp.Utils.isWhitespace(text.charAt(i))) 
                continue;
            int j;
            for (j = i; j < text.length(); j++) {
                if (com.pullenti.unisharp.Utils.isWhitespace(text.charAt(j))) 
                    break;
            }
            res.add(text.substring(i, i + j - i));
            i = j;
        }
        return res;
    }

    /**
     * Получение текста из текстового файла, при этом автоматически определяется 
     * кодировка Windows-1251 или DOS и осуществляется соответствующее преобразование 
     * (английский текст не изменяется). 
     * Также корректируются переходы на новую строку, чтобы везде были бы \r\n .
     * @param fileName имя текстового файла
     * @return результат
     * Корректировка символов перехода на новую строку (одно 0D или 0A преобразуются в 0D0A), 
     * замена nbsp на обычные пробелы
     * @param txt 
     * @return 
     */
    public static String correctWhitespaces(String txt) {
        if (txt == null) 
            return null;
        int i;
        for (i = 0; i < txt.length(); i++) {
            if (((int)txt.charAt(i)) == 0xD) {
                if ((i + 1) >= txt.length()) 
                    break;
                if (((int)txt.charAt(i + 1)) != 0xA) 
                    break;
            }
            else if (((int)txt.charAt(i)) == 0xA) {
                if (i == 0) 
                    break;
                if (((int)txt.charAt(i - 1)) != 0xD) 
                    break;
            }
            else if (((int)txt.charAt(i)) == 0xA0) 
                break;
        }
        if (i >= txt.length()) 
            return txt;
        StringBuilder res = new StringBuilder();
        for (i = 0; i < txt.length(); i++) {
            if (((int)txt.charAt(i)) == 0xD) {
                res.append("\r\n");
                if (((i + 1) < txt.length()) && ((int)txt.charAt(i + 1)) == 0xA) 
                    i++;
            }
            else if (((int)txt.charAt(i)) == 0xA) 
                res.append("\r\n");
            else if (((int)txt.charAt(i)) == 0xA0) 
                res.append(' ');
            else 
                res.append(txt.charAt(i));
        }
        String resTxt = res.toString();
        for (i = 0; i < (resTxt.length() - 1); i++) {
            if (((int)resTxt.charAt(i)) == 0xD && ((int)resTxt.charAt(i + 1)) == 0xD) {
            }
        }
        return resTxt;
    }

    /**
     * Исправиление ситуации, когда текстографический формат для размещения слитного фрагмента текста 
     * разбивает его на строки (например, для PDF). Производится анализ таких ситуаций и замена 
     * переносов на пробелы.
     * @param txt текст
     * @param count вернёт количество исправлений
     * @return исправленный или исходный текст
     */
    public static String correctNewlinesForParagraphs(String txt, com.pullenti.unisharp.Outargwrapper<Integer> count) {
        count.value = 0;
        if (com.pullenti.unisharp.Utils.isNullOrEmpty(txt)) 
            return txt;
        int i;
        int j;
        int cou = 0;
        int totalLen = 0;
        for (i = 0; i < txt.length(); i++) {
            char ch = txt.charAt(i);
            if (((int)ch) != 0xD && ((int)ch) != 0xA && ch != '\f') 
                continue;
            int len = 0;
            char lastChar = ch;
            for (j = i + 1; j < txt.length(); j++) {
                ch = txt.charAt(j);
                if (((int)ch) == 0xD || ((int)ch) == 0xA || ch == '\f') 
                    break;
                else if (((int)ch) == 0x9) 
                    len += 5;
                else {
                    lastChar = ch;
                    len++;
                }
            }
            if (j >= txt.length()) 
                break;
            if (len < 30) 
                continue;
            if (len > 200) 
                return txt;
            if (lastChar != '.' && lastChar != ':' && lastChar != ';') {
                boolean nextIsDig = false;
                for (int k = j + 1; k < txt.length(); k++) {
                    if (!com.pullenti.unisharp.Utils.isWhitespace(txt.charAt(k))) {
                        if (Character.isDigit(txt.charAt(k))) 
                            nextIsDig = true;
                        break;
                    }
                }
                if (!nextIsDig) {
                    cou++;
                    totalLen += len;
                }
            }
            i = j;
        }
        if (cou < 4) 
            return txt;
        totalLen /= cou;
        if ((totalLen < 50) || totalLen > 100) 
            return txt;
        StringBuilder tmp = new StringBuilder(txt);
        for (i = 0; i < tmp.length(); i++) {
            char ch = tmp.charAt(i);
            int jj;
            int len = 0;
            char lastChar = ch;
            for (j = i + 1; j < tmp.length(); j++) {
                ch = tmp.charAt(j);
                if (((int)ch) == 0xD || ((int)ch) == 0xA || ch == '\f') 
                    break;
                else if (((int)ch) == 0x9) 
                    len += 5;
                else {
                    lastChar = ch;
                    len++;
                }
            }
            if (j >= tmp.length()) 
                break;
            for (jj = j - 1; jj >= 0; jj--) {
                if (!com.pullenti.unisharp.Utils.isWhitespace((lastChar = tmp.charAt(jj)))) 
                    break;
            }
            boolean notSingle = false;
            jj = j + 1;
            if ((jj < tmp.length()) && ((int)tmp.charAt(j)) == 0xD && ((int)tmp.charAt(jj)) == 0xA) 
                jj++;
            for (; jj < tmp.length(); jj++) {
                ch = tmp.charAt(jj);
                if (!com.pullenti.unisharp.Utils.isWhitespace(ch)) 
                    break;
                if (((int)ch) == 0xD || ((int)ch) == 0xA || ch == '\f') {
                    notSingle = true;
                    break;
                }
            }
            if (((!notSingle && len > (totalLen - 20) && (len < (totalLen + 10))) && lastChar != '.' && lastChar != ':') && lastChar != ';') {
                tmp.setCharAt(j, ' ');
                count.value++;
                if ((j + 1) < tmp.length()) {
                    ch = tmp.charAt(j + 1);
                    if (((int)ch) == 0xA) {
                        tmp.setCharAt(j + 1, ' ');
                        j++;
                    }
                }
            }
            i = j - 1;
        }
        return tmp.toString();
    }

    /**
     * Считывание текста из текстового файла. 
     * Кодировка файла определяется префиксом. Поддерживаются такие префиксы: 
     * EF BB BF - для UTF8 
     * FF FE или FE FF - для Unicode, младний байт раньше 
     *  
     * Если префикс не задан, то подразумевается Windows-1251
     * @param fileName имя входного файла
     * @return строка или null при отсутствии
     */
    public static String readStringFromFile(String fileName, boolean utf8, boolean donotCorrectWhitespaces) throws Exception, java.io.IOException, InterruptedException {
        if (!((new java.io.File(fileName)).exists() && (new java.io.File(fileName)).isFile())) 
            return null;
        byte[] data = com.pullenti.unitext.internal.uni.UnitextHelper.loadDataFromFile(fileName, 0);
        if (data == null) 
            return null;
        return readStringFromBytes(data, utf8, donotCorrectWhitespaces);
    }

    public static EncodingWrapper checkEncoding(String fileName) throws Exception, java.io.FileNotFoundException, java.io.IOException {
        java.io.File fi = new java.io.File(fileName);
        if (!fi.exists() || fi.length() == (0L)) 
            return null;
        byte[] buf = new byte[(fi.length() > (5000L) ? 5000 : (int)fi.length())];
        try (com.pullenti.unisharp.FileStream f = new com.pullenti.unisharp.FileStream(fileName, "r", "")) {
            f.read(buf, 0, buf.length);
        }
        int i;
        com.pullenti.unisharp.Outargwrapper<Integer> wrapi673 = new com.pullenti.unisharp.Outargwrapper<Integer>();
        EncodingWrapper inoutres674 = EncodingWrapper.checkEncoding(buf, wrapi673);
        i = (wrapi673.value != null ? wrapi673.value : 0);
        return inoutres674;
    }

    public static String readStringFromBytes(byte[] data, boolean utf8, boolean doNotCorrectWhitespaces) {
        if (utf8) 
            return MiscHelper.decodeStringUtf8(data, 0, -1);
        int hlen = 0;
        com.pullenti.unisharp.Outargwrapper<Integer> wraphlen675 = new com.pullenti.unisharp.Outargwrapper<Integer>();
        EncodingWrapper enc = EncodingWrapper.checkEncoding(data, wraphlen675);
        hlen = (wraphlen675.value != null ? wraphlen675.value : 0);
        if (enc == null) 
            return null;
        String txt = enc.getString(data, 0, -1);
        if (!doNotCorrectWhitespaces) 
            return txt;
        return correctWhitespaces(txt);
    }

    /**
     * Сохранение текста в файл. Формат UTF-8, вставляется префикс EF BB BF.
     * @param str 
     * @param fileName 
     */
    public static void writeStringToFile(String str, String fileName) throws Exception, java.io.FileNotFoundException, java.io.IOException {
        if (str == null) 
            str = "";
        byte[] data = MiscHelper.encodeStringUtf8(str, true);
        try (com.pullenti.unisharp.FileStream f = new com.pullenti.unisharp.FileStream(fileName, "rw", "t")) {
            f.write(data, 0, data.length);
        }
    }

    /**
     * Сохранить строку в файле в кодировке Windows-1251
     * @param str 
     * @param fileName 
     */
    public static void writeString1251ToFile(String str, String fileName) throws Exception, java.io.FileNotFoundException, java.io.IOException {
        if (str == null || fileName == null) 
            return;
        try (com.pullenti.unisharp.FileStream f = new com.pullenti.unisharp.FileStream(fileName, "rw", "t")) {
            byte[] data = MiscHelper.encodeString1251(str);
            f.write(data, 0, data.length);
        }
    }

    /**
     * Проверка совпадения строк, пробелы игнорируются
     * @param str1 
     * @param str2 
     * @param ignoreCase игнорировать регистр букв
     * @param ignoreSpecChars игнорировать небуквы и нецифры
     * @return 
     */
    public static ComapreTextsResult compareTexts(String str1, String str2, boolean ignoreCase, boolean ignoreSpecChars) {
        if (str1 == null || str2 == null) 
            return (com.pullenti.unisharp.Utils.stringsEq(str1, str2) ? ComapreTextsResult.EQUALS : ComapreTextsResult.NOTEQUAL);
        int i1 = 0;
        int i2 = 0;
        while (true) {
            for (; i1 < str1.length(); i1++) {
                if (!com.pullenti.unisharp.Utils.isWhitespace(str1.charAt(i1))) {
                    if (ignoreSpecChars) {
                        if (!Character.isLetterOrDigit(str1.charAt(i1))) 
                            continue;
                    }
                    break;
                }
            }
            for (; i2 < str2.length(); i2++) {
                if (!com.pullenti.unisharp.Utils.isWhitespace(str2.charAt(i2))) {
                    if (ignoreSpecChars) {
                        if (!Character.isLetterOrDigit(str2.charAt(i2))) 
                            continue;
                    }
                    break;
                }
            }
            if (i1 >= str1.length()) 
                break;
            if (i2 >= str2.length()) 
                break;
            char ch1 = str1.charAt(i1);
            char ch2 = str2.charAt(i2);
            if (ch1 != ch2 && ignoreCase) {
                ch1 = Character.toUpperCase(ch1);
                ch2 = Character.toUpperCase(ch2);
            }
            if (ch1 == 'ё') 
                ch1 = 'е';
            if (ch2 == 'ё') 
                ch2 = 'е';
            if (ch1 == 'Ё') 
                ch1 = 'Е';
            if (ch2 == 'Ё') 
                ch2 = 'Е';
            if (ch1 != ch2) 
                return ComapreTextsResult.NOTEQUAL;
            i1++;
            i2++;
        }
        M_COMPARETEXTSENDCHAR1 = i1;
        M_COMPARETEXTSENDCHAR2 = i2;
        if (i1 >= str1.length() && i2 >= str2.length()) 
            return ComapreTextsResult.EQUALS;
        if (i1 >= str1.length()) 
            return ComapreTextsResult.SECONDSTARTSWITHFIRST;
        if (i2 >= str2.length()) 
            return ComapreTextsResult.FIRSTSTARTSWITHSECOND;
        return ComapreTextsResult.NOTEQUAL;
    }

    public static int M_COMPARETEXTSENDCHAR1;

    public static int M_COMPARETEXTSENDCHAR2;

    /**
     * Выделить текст из всех форматов, какие только поддерживаются 
     * (кроме архивов)
     * @param fileName имя файла (может быть null)
     * @param content содержимое файла (если null, то fileName есть имя файла в локальной файловой системе)
     * @param unzipArchives при true будет распаковывать архивы и извлекать тексты из файлов, 
     * суммарный текст получается конкатенацией
     * @return плоский текст или null
     */
    public static String extractText(String fileName, byte[] content, boolean unzipArchives) throws Exception, java.io.FileNotFoundException, java.io.IOException {
        com.pullenti.unitext.FileFormat frm = FileFormatsHelper.analizeFileFormat(fileName, content);
        if (frm == com.pullenti.unitext.FileFormat.UNKNOWN) 
            return null;
        com.pullenti.unitext.FileFormatClass frmcl = FileFormatsHelper.getFormatClass(frm);
        if (frmcl == com.pullenti.unitext.FileFormatClass.ARCHIVE && !unzipArchives) 
            return null;
        if (frmcl == com.pullenti.unitext.FileFormatClass.IMAGE) 
            return null;
        com.pullenti.unitext.UnitextDocument doc = com.pullenti.unitext.UnitextService.createDocument(fileName, content, com.pullenti.unitext.CreateDocumentParam._new676(true, !unzipArchives));
        if (doc == null) 
            return null;
        return com.pullenti.unitext.internal.uni.UnitextHelper.getPlaintext(doc, null);
    }

    public static class ComapreTextsResult implements Comparable<ComapreTextsResult> {
    
        public static final ComapreTextsResult NOTEQUAL; // 0
    
        public static final ComapreTextsResult FIRSTSTARTSWITHSECOND; // 1
    
        public static final ComapreTextsResult SECONDSTARTSWITHFIRST; // 2
    
        public static final ComapreTextsResult EQUALS; // 3
    
    
        public int value() { return m_val; }
        private int m_val;
        private String m_str;
        private ComapreTextsResult(int val, String str) { m_val = val; m_str = str; }
        @Override
        public String toString() {
            if(m_str != null) return m_str;
            return ((Integer)m_val).toString();
        }
        @Override
        public int hashCode() {
            return (int)m_val;
        }
        @Override
        public int compareTo(ComapreTextsResult v) {
            if(m_val < v.m_val) return -1;
            if(m_val > v.m_val) return 1;
            return 0;
        }
        private static java.util.HashMap<Integer, ComapreTextsResult> mapIntToEnum; 
        private static java.util.HashMap<String, ComapreTextsResult> mapStringToEnum; 
        private static ComapreTextsResult[] m_Values; 
        private static java.util.Collection<Integer> m_Keys; 
        public static ComapreTextsResult of(int val) {
            if (mapIntToEnum.containsKey(val)) return mapIntToEnum.get(val);
            ComapreTextsResult item = new ComapreTextsResult(val, ((Integer)val).toString());
            mapIntToEnum.put(val, item);
            mapStringToEnum.put(item.m_str.toUpperCase(), item);
            return item; 
        }
        public static ComapreTextsResult of(String str) {
            str = str.toUpperCase(); 
            if (mapStringToEnum.containsKey(str)) return mapStringToEnum.get(str);
            return null; 
        }
        public static boolean isDefined(Object val) {
            if(val instanceof Integer) return m_Keys.contains((Integer)val); 
            return false; 
        }
        public static ComapreTextsResult[] getValues() {
            return m_Values; 
        }
        static {
            mapIntToEnum = new java.util.HashMap<Integer, ComapreTextsResult>();
            mapStringToEnum = new java.util.HashMap<String, ComapreTextsResult>();
            NOTEQUAL = new ComapreTextsResult(0, "NOTEQUAL");
            mapIntToEnum.put(NOTEQUAL.value(), NOTEQUAL);
            mapStringToEnum.put(NOTEQUAL.m_str.toUpperCase(), NOTEQUAL);
            FIRSTSTARTSWITHSECOND = new ComapreTextsResult(1, "FIRSTSTARTSWITHSECOND");
            mapIntToEnum.put(FIRSTSTARTSWITHSECOND.value(), FIRSTSTARTSWITHSECOND);
            mapStringToEnum.put(FIRSTSTARTSWITHSECOND.m_str.toUpperCase(), FIRSTSTARTSWITHSECOND);
            SECONDSTARTSWITHFIRST = new ComapreTextsResult(2, "SECONDSTARTSWITHFIRST");
            mapIntToEnum.put(SECONDSTARTSWITHFIRST.value(), SECONDSTARTSWITHFIRST);
            mapStringToEnum.put(SECONDSTARTSWITHFIRST.m_str.toUpperCase(), SECONDSTARTSWITHFIRST);
            EQUALS = new ComapreTextsResult(3, "EQUALS");
            mapIntToEnum.put(EQUALS.value(), EQUALS);
            mapStringToEnum.put(EQUALS.m_str.toUpperCase(), EQUALS);
            java.util.Collection<ComapreTextsResult> col = mapIntToEnum.values();
            m_Values = new ComapreTextsResult[col.size()];
            col.toArray(m_Values);
            m_Keys = new java.util.ArrayList<Integer>(mapIntToEnum.keySet());
        }
    }

    public TextHelper() {
    }
    public static TextHelper _globalInstance;
    
    static {
        try { _globalInstance = new TextHelper(); } 
        catch(Exception e) { }
    }
}
