package de.duehl.vocabulary.japanese.data.symbol;

import java.util.ArrayList;
import java.util.List;

import de.duehl.basics.collections.CollectionsHelper;
import de.duehl.basics.text.Text;

/**
 * Diese Klasse stellt die Zeichen der Schrift Katakana (in UTF-Zeichen) dar.
 *
 * Sie beinhaltet auch Methoden rund darum, um zu fragen, ob eine Zeichenkette ausschließlich
 * aus diesen Zeichen besteht oder wo das erste bzw. letzte dieser Zeichen zu finden ist.
 *
 * @version 1.01     2025-11-23
 * @author Christian Dühl
 */

public enum Katakana {

    A("ア", "a", KanaSubType.STANDARD),
    I("イ", "i", KanaSubType.STANDARD),
    U("ウ", "u", KanaSubType.STANDARD),
    E("エ", "e", KanaSubType.STANDARD),
    O("オ", "o", KanaSubType.STANDARD),

    KA("カ", "ka", KanaSubType.STANDARD),
    KI("キ", "ki", KanaSubType.STANDARD),
    KU("ク", "ku", KanaSubType.STANDARD),
    KE("ケ", "ke", KanaSubType.STANDARD),
    KO("コ", "ko", KanaSubType.STANDARD),

    SA("サ", "sa", KanaSubType.STANDARD),
    SHI("シ", "shi", KanaSubType.STANDARD),
    SU("ス", "su", KanaSubType.STANDARD),
    SE("セ", "se", KanaSubType.STANDARD),
    SO("ソ", "so", KanaSubType.STANDARD),

    TA("タ", "ta", KanaSubType.STANDARD),
    CHI("チ", "chi", KanaSubType.STANDARD),
    TSU("ツ", "tsu", KanaSubType.STANDARD),
    TE("テ", "te", KanaSubType.STANDARD),
    TO("ト", "to", KanaSubType.STANDARD),

    NA("ナ", "na", KanaSubType.STANDARD),
    NI("ニ", "ni", KanaSubType.STANDARD),
    NU("ヌ", "nu", KanaSubType.STANDARD),
    NE("ネ", "ne", KanaSubType.STANDARD),
    NO("ノ", "no", KanaSubType.STANDARD),

    HA("ハ", "ha", KanaSubType.STANDARD),
    HI("ヒ", "hi", KanaSubType.STANDARD),
    FU("フ", "fu", KanaSubType.STANDARD),
    HE("ヘ", "he", KanaSubType.STANDARD),
    HO("ホ", "ho", KanaSubType.STANDARD),

    MA("マ", "ma", KanaSubType.STANDARD),
    MI("ミ", "mi", KanaSubType.STANDARD),
    MU("ム", "mu", KanaSubType.STANDARD),
    ME("メ", "me", KanaSubType.STANDARD),
    MO("モ", "mo", KanaSubType.STANDARD),

    YA("ヤ", "ya", KanaSubType.STANDARD),
    YU("ユ", "yu", KanaSubType.STANDARD),
    YO("ヨ", "yo", KanaSubType.STANDARD),

    SMALL_YA("ャ", "kleines ya", KanaSubType.SMALL),
    SMALL_YU("ュ", "kleines yu", KanaSubType.SMALL),
    SMALL_YO("ョ", "kleines yo", KanaSubType.SMALL),

    RA("ラ", "ra", KanaSubType.STANDARD),
    RI("リ", "ri", KanaSubType.STANDARD),
    RU("ル", "ru", KanaSubType.STANDARD),
    RE("レ", "re", KanaSubType.STANDARD),
    RO("ロ", "ro", KanaSubType.STANDARD),

    WA("ワ", "wa", KanaSubType.STANDARD),
    WO("ヲ", "wo", KanaSubType.STANDARD),

    N("ン", "n", KanaSubType.STANDARD),

    GA("ガ", "ga", KanaSubType.WITH_DAKUTEN),
    GI("ギ", "gi", KanaSubType.WITH_DAKUTEN),
    GU("グ", "gu", KanaSubType.WITH_DAKUTEN),
    GE("ゲ", "ge", KanaSubType.WITH_DAKUTEN),
    GO("ゴ", "go", KanaSubType.WITH_DAKUTEN),

    ZA("ザ", "za", KanaSubType.WITH_DAKUTEN),
    JI1("ジ", "ji", KanaSubType.WITH_DAKUTEN),
    ZU1("ズ", "zu", KanaSubType.WITH_DAKUTEN),
    ZE("ゼ", "ze", KanaSubType.WITH_DAKUTEN),
    ZO("ゾ", "zo", KanaSubType.WITH_DAKUTEN),

    DA("ダ", "da", KanaSubType.WITH_DAKUTEN),
    JI2("ヂ", "ji", KanaSubType.WITH_DAKUTEN),
    ZU2("ヅ", "zu", KanaSubType.WITH_DAKUTEN),
    DE("デ", "de", KanaSubType.WITH_DAKUTEN),
    DO("ド", "do", KanaSubType.WITH_DAKUTEN),

    BA("バ", "ba", KanaSubType.WITH_DAKUTEN),
    BI("ビ", "bi", KanaSubType.WITH_DAKUTEN),
    BU("ブ", "bu", KanaSubType.WITH_DAKUTEN),
    BE("ベ", "be", KanaSubType.WITH_DAKUTEN),
    BO("ボ", "bo", KanaSubType.WITH_DAKUTEN),

    PA("パ", "pa", KanaSubType.WITH_HANDAKUTEN),
    PI("ピ", "pi", KanaSubType.WITH_HANDAKUTEN),
    PU("プ", "pu", KanaSubType.WITH_HANDAKUTEN),
    PE("ペ", "pe", KanaSubType.WITH_HANDAKUTEN),
    PO("ポ", "po", KanaSubType.WITH_HANDAKUTEN),

    KYA("キャ", "kya", KanaSubType.COMPOUND),
    KYU("キュ", "kyu", KanaSubType.COMPOUND),
    KYO("キョ", "kyo", KanaSubType.COMPOUND),

    SHA("シャ", "sha", KanaSubType.COMPOUND),
    SHU("シュ", "shu", KanaSubType.COMPOUND),
    SHO("ショ", "sho", KanaSubType.COMPOUND),

    CHA("チャ", "cha", KanaSubType.COMPOUND),
    CHU("チュ", "chu", KanaSubType.COMPOUND),
    CHO("チョ", "cho", KanaSubType.COMPOUND),

    NYA("ニャ", "nya", KanaSubType.COMPOUND),
    NYU("ニュ", "nyu", KanaSubType.COMPOUND),
    NYO("ニョ", "nyo", KanaSubType.COMPOUND),

    HYA("ヒャ", "hya", KanaSubType.COMPOUND),
    HYU("ヒュ", "hyu", KanaSubType.COMPOUND),
    HYO("ヒョ", "hyo", KanaSubType.COMPOUND),

    MYA("ミャ", "mya", KanaSubType.COMPOUND),
    MYU("ミュ", "myu", KanaSubType.COMPOUND),
    MYO("ミョ", "myo", KanaSubType.COMPOUND),

    RYA("リャ", "rya", KanaSubType.COMPOUND),
    RYU("リュ", "ryu", KanaSubType.COMPOUND),
    RYO("リョ", "ryo", KanaSubType.COMPOUND),

    GYA("ギャ", "gya", KanaSubType.COMPOUND_WITH_DAKUTEN),
    GYU("ギュ", "gyu", KanaSubType.COMPOUND_WITH_DAKUTEN),
    GYO("ギョ", "gyo", KanaSubType.COMPOUND_WITH_DAKUTEN),

    JA1("ジャ", "ja", KanaSubType.COMPOUND_WITH_DAKUTEN),
    JU1("ジュ", "ju", KanaSubType.COMPOUND_WITH_DAKUTEN),
    JO1("ジョ", "jo", KanaSubType.COMPOUND_WITH_DAKUTEN),

    JA2("ヂャ", "ja", KanaSubType.COMPOUND_WITH_DAKUTEN),
    JU2("ヂュ", "ju", KanaSubType.COMPOUND_WITH_DAKUTEN),
    JO2("ヂョ", "jo", KanaSubType.COMPOUND_WITH_DAKUTEN),

    BYA("ビャ", "bya", KanaSubType.COMPOUND_WITH_DAKUTEN),
    BYU("ビュ", "byu", KanaSubType.COMPOUND_WITH_DAKUTEN),
    BYO("ビョ", "byo", KanaSubType.COMPOUND_WITH_DAKUTEN),

    PYA("ピャ", "pya", KanaSubType.COMPOUND_WITH_HANDAKUTEN),
    PYU("ピュ", "pyu", KanaSubType.COMPOUND_WITH_HANDAKUTEN),
    PYO("ピョ", "pyo", KanaSubType.COMPOUND_WITH_HANDAKUTEN),

    LEHNWORT_F1("フォ", "fo", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_F2("フェ", "fe", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_F3("フィ", "fi", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_F4("ファ", "fa", KanaSubType.FOR_FOREIGN_WORDS),

    LEHNWORT_W1("ヴォ", "wo", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_W2("ヴェ", "we", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_W3("ヴ", "w", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_W4("ヴィ", "wi", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_W5("ヴァ", "wa", KanaSubType.FOR_FOREIGN_WORDS),

    LEHNWORT_TI("ティ", "ti", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_DI("ディ", "di", KanaSubType.FOR_FOREIGN_WORDS),

    LEHNWORT_TU("テュ", "tu", KanaSubType.FOR_FOREIGN_WORDS),
    LEHNWORT_DU("デュ", "du", KanaSubType.FOR_FOREIGN_WORDS),


    SMALL_TSU("ッ", "kleines tsu", KanaSubType.SMALL),
    ;

    /** Das Zeichen in UTF-8 Darstellung. */
    private final String character;

    /** Die Hepburn-Darstellung in lateinischen Buchstaben. */
    private final String hepburn;

    /** Die Unterart des Katakana-Zeichens. */
    private final KanaSubType subType;

    /**
     * Konstruktor.
     *
     * @param character
     *            Das Zeichen in UTF-8 Darstellung.
     * @param hepburn
     *            Die Hepburn-Darstellung in lateinischen Buchstaben.
     * @param subType
     *            Die Unterart des Katakana-Zeichens.
     */
    private Katakana(String character, String hepburn, KanaSubType subType) {
        this.character = character;
        this.hepburn = hepburn;
        this.subType = subType;
    }

    /** Getter für das Zeichen in UTF-8 Darstellung. */
    public String getCharacter() {
        return character;
    }

    /** Getter für die Hepburn-Darstellung in lateinischen Buchstaben. */
    public String getHepburn() {
        return hepburn;
    }

    /** Getter für die Unterart des Hiragana-Zeichens. */
    public KanaSubType getSubType() {
        return subType;
    }

    /** Gibt das Katakana-Zeichen als Kana-Objekt zurück. */
    public Kana toKana() {
        Kana kana = new Kana(character, hepburn);
        return kana;
    }

    /** Gibt eine Liste mit den Zeichen der Schrift Katakana (in UTF-Zeichen) zurück. */
    public static List<String> getAllKatakanaAsStringList() {
        List<String> katakanaList = new ArrayList<>();

        for (Katakana katakana : Katakana.values()) {
            katakanaList.add(katakana.getCharacter());
        }

        return katakanaList;
    }

    /** Gibt an, ob in dem Text ein Katakana-Zeichen vorkommt. */
    public static boolean containsKatakana(String text) {
        return Text.contains(text, getAllKatakanaAsStringList());
    }

    /** Gibt an, ob der Text ausschließlich aus Katakana-Zeichen besteht. */
    public static boolean containsOnlyKatakana(String text) {
        if (text.isEmpty()) {
            return false;
        }
        else {
            List<String> katakana = getAllKatakanaAsStringList();
            for (String textCharacter : Text.textToCharactersList(text)) {
                if (!katakana.contains(textCharacter)) {
                    return false;
                }
            }

            return true;
        }
    }

    /**
     * Gibt den Index des ersten Katakana-Zeichen im Text zurück. Gibt es kein solches, wird -1
     * zurückgegeben.
     */
    public static int firstIndexOfKatakana(String text) {
        List<String> katakana = getAllKatakanaAsStringList();
        List<String> textCharacters = Text.textToCharactersList(text);

        for (int index = 0; index < textCharacters.size(); ++index) {
            String textCharacter = textCharacters.get(index);
            if (katakana.contains(textCharacter )) {
                return index;
            }
        }

        return -1;
    }

    /**
     * Gibt den Index des letzten Katakana-Zeichen im Text zurück. Gibt es kein solches, wird -1
     * zurückgegeben.
     */
    public static int lastIndexOfKatakana(String text) {
        List<String> katakana = getAllKatakanaAsStringList();
        List<String> textCharacters = Text.textToCharactersList(text);

        for (int index = textCharacters.size() - 1; index >= 0; --index) {
            String textCharacter = textCharacters.get(index);
            if (katakana.contains(textCharacter )) {
                return index;
            }
        }

        return -1;
    }

    /**
     * Gibt eine Liste mit allen Katakana zurück, die die gewünschten Unterarten haben.
     *
     * @param kanaSubTypes
     *            Die gewünschten Unterarten.
     * @return Die Liste mit allen Katakana zurück, die die gewünschten Unterarten haben.
     */
    public static List<Katakana> getKanasWithSubtypes(KanaSubType ... kanaSubTypes) {
        return getKanasWithSubtypes(CollectionsHelper.arrayToList(kanaSubTypes));
    }

    /**
     * Gibt eine Liste mit allen Katakana zurück, die die gewünschten Unterarten haben.
     *
     * @param kanaSubTypes
     *            Die gewünschten Unterarten.
     * @return Die Liste mit allen Katakana zurück, die die gewünschten Unterarten haben.
     */
    public static List<Katakana> getKanasWithSubtypes(List<KanaSubType> kanaSubTypes) {
        List<Katakana> list = new ArrayList<>();

        for (Katakana katakana : values()) {
            KanaSubType actualSubType = katakana.getSubType();
            if (kanaSubTypes.contains(actualSubType)) {
                list.add(katakana);
            }
        }

        return list;
    }

    /** Gibt die Anzahl der bekannten Katakana zurück. */
    public static int getNumberOfKnownKatakana() {
        return values().length;
    }

    /** Gibt die Anzahl der bekannten Katakana in Standard-Form zurück. */
    public static int getNumberOfKnownStandardKatakana() {
        List<Katakana> getKanasWithSubtypes = getKanasWithSubtypes(KanaSubType.STANDARD);
        return getKanasWithSubtypes.size();
    }

}
