package de.duehl.vocabulary.japanese.logic.translation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import de.duehl.basics.collections.CollectionsHelper;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.data.Vocabulary;
import de.duehl.vocabulary.japanese.logic.translation.data.KanaAndKanji;

/**
 * Diese Klasse kümmert sich um die Übersetzung von Japanisch in Deutsch (für Abfragen die nur
 * Kana, aber nicht Kanji anzeigen, aber auch die mit beiden).
 *
 * In den Vokabularien liegen die Vokabeln von Japanisch nach Deutsch vor. Da auf der Liste der
 * Vokabeln in allen Vokabularen sowohl die Kombination (Kanji, Kana) als auch die Kombination
 * (Kana, erste Übersetzung) eindeutig ist (dies wird beim Startup sichergestellt), ist eine
 * besondere Behandlung nur notwendig, wenn man die Vokabeln abfragt, ohne die Kanji anzuzeigen.
 * Das passiert hier.
 *
 * Aber auch für die beschleunigte Suche nach Vokabeln, die zu der Kombination aus Kana und Kanji
 * ermittelt werden sollen, wird hier ein Verzeichnis aufgebaut.
 *
 * @version 1.01     2024-08-21
 * @author Christian Dühl
 */

public class JapaneseToGermanTranslation {

    private static final boolean PRINT_MULTIPLE_VOCABLE_ONLY_KANA = false;


    /** Die Liste mit den Vokabularien. */
    private final List<Vocabulary> vocabularies;

    /** Das Verzeichnis der zu der Darstellung in Kana passenden Vokabeln. */
    private final Map<String, List<Vocable>> vocablesByKana;

    /** Das Verzeichnis der zu der Darstellung in Kana und Kanji passenden Vokabeln. */
    private final Map<KanaAndKanji, List<Vocable>> vocablesByKanaAndKanji;

    /**
     * Konstruktor.
     *
     * @param vocabularies
     *            Die Liste mit den Vokabularien.
     */
    public JapaneseToGermanTranslation(List<Vocabulary> vocabularies) {
        this.vocabularies = vocabularies;

        vocablesByKana = new HashMap<>();
        vocablesByKanaAndKanji = new HashMap<>();;
        fillHashes();
        printMultipleVocableOnlyKana();
    }

    private void fillHashes() {
        for (Vocabulary vocabulary : vocabularies) {
            fillHashesForVocabulary(vocabulary);
        }
    }

    private void fillHashesForVocabulary(Vocabulary vocabulary) {
        for (Vocable vocable : vocabulary.getVocables()) {
            fillKanaHashForVocable(vocable);
            fillKanaAndKanjiHashForVocable(vocable);
        }
    }

    private void fillKanaHashForVocable(Vocable vocable) {
        String kana = vocable.getKana();

        if (!vocablesByKana.containsKey(kana)) {
            vocablesByKana.put(kana, new ArrayList<>());
        }
        List<Vocable> list = vocablesByKana.get(kana);
        if (!list.contains(vocable)) {
            list.add(vocable);
        }
    }

    private void fillKanaAndKanjiHashForVocable(Vocable vocable) {
        String kana = vocable.getKana();
        String kanji = vocable.getKanji();
        KanaAndKanji kanaAndKanji = new KanaAndKanji(kana, kanji);

        if (!vocablesByKanaAndKanji.containsKey(kanaAndKanji)) {
            vocablesByKanaAndKanji.put(kanaAndKanji, new ArrayList<>());
        }
        List<Vocable> list = vocablesByKanaAndKanji.get(kanaAndKanji);
        if (!list.contains(vocable)) {
            list.add(vocable);
        }
    }

    private void printMultipleVocableOnlyKana() {
        if (PRINT_MULTIPLE_VOCABLE_ONLY_KANA) {
            reallyPrintMultipleVocableOnlyKana();
        }
    }

    private void reallyPrintMultipleVocableOnlyKana() {
        System.out.println("Alle Kana, die zu mehr als einer Vokabel passen:");

        List<String> sortedKana =
                CollectionsHelper.getSortedMapStringIndices(vocablesByKana);
        for (String kana : sortedKana) {
            List<Vocable> vocables = vocablesByKana.get(kana);
            if (vocables.size() > 1) {
                System.out.print(kana);
                for (Vocable vocable : vocables) {
                    System.out.print(""
                            + " - "
                            + vocable.getKanji()
                            + " "
                            + vocable.getKana()
                            + " "
                            + vocable.getTranslations().get(0)
                            );
                }
                System.out.println();
            }
        }
    }

    /** Gibt zur Darstellung in Kana die passenden Vokabeln zurück. */
    public List<Vocable> getMatchingVocablesForKana(String kana) {
        if (vocablesByKana.containsKey(kana)) {
            return vocablesByKana.get(kana);
        }
        else {
            throw new RuntimeException("Zur Darstelung in Kana '" + kana + "' ist keine "
                    + "zugehörige Vokabel bekannt.");
        }
    }

    /** Gibt zur Darstellung in Kana und Kanji die passenden Vokabeln zurück. */
    public List<Vocable> getMatchingVocablesForKanaAndKanji(String kana, String kanji) {
        KanaAndKanji kanaAndKanji = new KanaAndKanji(kana, kanji);

        if (vocablesByKanaAndKanji.containsKey(kanaAndKanji)) {
            return vocablesByKanaAndKanji.get(kanaAndKanji);
        }
        else {
            throw new RuntimeException("Zur Darstelung in Kana '" + kana + "' und Kanji '" + kanji
                    + "'ist keine zugehörige Vokabel bekannt.");
        }
    }

}
