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

import java.util.List;

import de.duehl.basics.text.Text;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.tools.VocabularyTools;

/**
 * Diese Klasse berechnet zu einer Vokabel aus einer Liste von nach bestimmten Suchkriterien
 * gefundenen Vokabeln anhand eines Suchbegriffs die Relevanz (je kleiner, desto besser).
 *
 * @version 1.01     2024-11-20
 * @author Christian Dühl
 */

public class VocableRelevanceWeightingCalculator {

    /*
     * TODO
     *
     * Die Sortierung könnte man noch um kleingeschriebene Varianten erweitern, siehe
     * KanjiRelevanceWeightingCalculator, aber das reicht erstmal so...
     */

    private static final int WEIGHTENING_KANA_EQUALS_SEARCH = 1;
    private static final int WEIGHTENING_KANJI_EQUALS_SEARCH = 2;
    private static final int WEIGHTENING_ROMAJI_EQUALS_SEARCH = 3;
    private static final int WEIGHTENING_PRONOUNCIATION_EQUALS_SEARCH = 4;
    private static final int WEIGHTENING_TRANSLATION_EQUALS_SEARCH = 5;
    private static final int WEIGHTENING_COMMENT_EQUALS_SEARCH = 6;
    private static final int WEIGHTENING_SEARCH_WORD_EQUALS_SEARCH = 7;
    private static final int WEIGHTENING_PART_OF_SPEACH_EQUALS_SEARCH = 8;

    private static final int WEIGHTENING_COMMENT_IN_JAPANESE_BRACES_SEARCH = 9;
    private static final int WEIGHTENING_ROMAJI_EQUALS_IGNORE_CASE_SENSIVITY_SEARCH = 10;
    private static final int WEIGHTENING_PRONOUNCIATION_EQUALS_IGNORE_CASE_SENSIVITY_SEARCH = 11;
    private static final int WEIGHTENING_TRANSLATION_EQUALS_IGNORE_CASE_SENSIVITY_SEARCH = 12;

    private static final int WEIGHTENING_COMPARE_KANA_EQUALS_COMPARE_SEARCH = 15;
    private static final int WEIGHTENING_COMPARE_KANJI_EQUALS_COMPARE_SEARCH = 16;
    private static final int WEIGHTENING_COMPARE_ROMAJI_EQUALS_COMPARE_SEARCH = 17;
    private static final int WEIGHTENING_COMPARE_TRANSLATION_EQUALS_COMPARE_SEARCH = 18;

    private static final int WEIGHTENING_KANA_STARTS_WITH_SEARCH = 21;
    private static final int WEIGHTENING_KANJI_STARTS_WITH_SEARCH = 22;
    private static final int WEIGHTENING_ROMAJI_STARTS_WITH_SEARCH = 23;
    private static final int WEIGHTENING_PRONOUNCIATION_STARTS_WITH_SEARCH = 24;
    private static final int WEIGHTENING_TRANSLATION_STARTS_WITH_SEARCH = 25;
    private static final int WEIGHTENING_COMMENT_STARTS_WITH_SEARCH = 26;
    private static final int WEIGHTENING_SEARCH_WORD_STARTS_WITH_SEARCH = 27;
    private static final int WEIGHTENING_PART_OF_SPEACH_STARTS_WITH_SEARCH = 28;

    private static final int WEIGHTENING_KANA_ENDS_WITH_SEARCH = 41;
    private static final int WEIGHTENING_KANJI_ENDS_WITH_SEARCH = 42;
    private static final int WEIGHTENING_ROMAJI_ENDS_WITH_SEARCH = 43;
    private static final int WEIGHTENING_PRONOUNCIATION_ENDS_WITH_SEARCH = 44;
    private static final int WEIGHTENING_TRANSLATION_ENDS_WITH_SEARCH = 45;
    private static final int WEIGHTENING_COMMENT_ENDS_WITH_SEARCH = 46;
    private static final int WEIGHTENING_SEARCH_WORD_ENDS_WITH_SEARCH = 47;
    private static final int WEIGHTENING_PART_OF_SPEACH_ENDS_WITH_SEARCH = 48;

    private static final int WEIGHTENING_KANA_CONTAINS_SEARCH_AS_SINGLE_WORD = 61;
    private static final int WEIGHTENING_KANJI_CONTAINS_SEARCH_AS_SINGLE_WORD = 62;
    private static final int WEIGHTENING_ROMAJI_CONTAINS_SEARCH_AS_SINGLE_WORD = 63;
    private static final int WEIGHTENING_PRONOUNCIATION_CONTAINS_SEARCH_AS_SINGLE_WORD = 64;
    private static final int WEIGHTENING_TRANSLATION_CONTAINS_SEARCH_AS_SINGLE_WORD = 65;
    private static final int WEIGHTENING_COMMENT_CONTAINS_SEARCH_AS_SINGLE_WORD = 66;
    private static final int WEIGHTENING_SEARCH_WORD_CONTAINS_SEARCH_AS_SINGLE_WORD = 67;
    private static final int WEIGHTENING_PART_OF_SPEACH_CONTAINS_SEARCH_AS_SINGLE_WORD = 68;

    private static final int NO_SPECIAL_WEIGHTENING = 999;


    /** Die Vokabel, deren Relevanz berechnet werden soll. */
    private final Vocable vocable;

    /** Der Suchbegriff, nach dem die Vokabel nach Relevanz bewertet werden soll. */
    private final String search;

    /**
     * Der Suchbegriff, nach dem die Vokabel nach Relevanz bewertet werden soll in Kleinbuchstaben.
     */
    private String loweredCaseSearch;

    /**
     * Der Suchbegriff, nach dem die Vokabel nach Relevanz bewertet werden soll in auf gleiche
     * Weise vorbereitet wie bei der Suche nach Suchbegriffen für den Vergleich mit den
     * Benutzereingaben.
     */
    private final String compareSearch;

    /**
     * Die Bewertung der Relevanz der Vokabel.
     *
     * Eine höhere Relevanz drückt sich in einer kleineren Zahl aus.
     */
    private int weighting;

    /** Gibt an, ob die Gewichtung bereits gefunden wurde. */
    private boolean weighteningFound;

    /**
     * Konstruktor.
     *
     * @param vocable
     *            Die Vokabel, deren Relevanz berechnet werden soll.
     * @param search
     *            Der Suchbegriff, nach dem die Vokabel nach Relevanz bewertet werden soll.
     */
    public VocableRelevanceWeightingCalculator(Vocable vocable, String search) {
        this.vocable = vocable;
        this.search = search;
        loweredCaseSearch = Text.toLowerCase(search);
        compareSearch = VocabularyTools.createCompareTranslation(search);
    }

    /** Berechnet die Relevanz */
    public void calculate() {
        init();

        checkIfEqualsSearch();
        checkIfSearchFulfillsSpecialConditions();
        checkIfSearchAgainstCompare();
        checkIfStartsWithSearch();
        checkIfEndsWithSearch();
        checkIfContainsSearchAsSingleWord();
    }

    private void init() {
        weighteningFound = false;
        weighting = NO_SPECIAL_WEIGHTENING;
    }

    private void checkIfEqualsSearch() {
        if (!weighteningFound) checkIfKanaEqualsSearch();
        if (!weighteningFound) checkIfKanjiEqualsSearch();
        if (!weighteningFound) checkIfRomajiEqualsSearch();
        if (!weighteningFound) checkIfPronunciationEqualsSearch();
        if (!weighteningFound) checkIfTranslationEqualsSearch();
        if (!weighteningFound) checkIfCommentEqualsSearch();
        if (!weighteningFound) checkIfSearchWordEqualsSearch();
        if (!weighteningFound) checkIfPartOfSpeachEqualsSearch();
    }

    private void checkIfKanaEqualsSearch() {
        checkIfEqualsSearch(vocable.getKana(), WEIGHTENING_KANA_EQUALS_SEARCH);
    }

    private void checkIfKanjiEqualsSearch() {
        checkIfEqualsSearch(vocable.getKanji(), WEIGHTENING_KANJI_EQUALS_SEARCH);
    }

    private void checkIfRomajiEqualsSearch() {
        checkIfEqualsSearch(vocable.getRomaji(), WEIGHTENING_ROMAJI_EQUALS_SEARCH);
    }

    private void checkIfPronunciationEqualsSearch() {
        checkIfEqualsSearch(vocable.getPronunciation(), WEIGHTENING_PRONOUNCIATION_EQUALS_SEARCH);
    }

    private void checkIfTranslationEqualsSearch() {
        checkIfAnyElementEqualsSearch(vocable.getTranslations(),
                WEIGHTENING_TRANSLATION_EQUALS_SEARCH);
    }

    private void checkIfCommentEqualsSearch() {
        checkIfEqualsSearch(vocable.getComment(), WEIGHTENING_COMMENT_EQUALS_SEARCH);
    }

    private void checkIfSearchWordEqualsSearch() {
        checkIfAnyElementEqualsSearch(vocable.getSearchWords(),
                WEIGHTENING_SEARCH_WORD_EQUALS_SEARCH);
    }

    private void checkIfPartOfSpeachEqualsSearch() {
        checkIfAnyElementEqualsSearch(vocable.getPartsOfSpeech(),
                WEIGHTENING_PART_OF_SPEACH_EQUALS_SEARCH);
    }

    private void checkIfAnyElementEqualsSearch(List<String> list, int weighteningToSet) {
        for (String member : list) {
            checkIfEqualsSearch(member, weighteningToSet);
            if (weighteningFound) {
                return;
            }
        }
    }

    private void checkIfEqualsSearch(String fieldContent, int weighteningToSet) {
        if (fieldContent.equals(search)) {
            weighteningFound = true;
            weighting = weighteningToSet;
        }
    }

    private void checkIfSearchFulfillsSpecialConditions() {
        if (!weighteningFound) checkIfCommentContainesSearchInJapaneseBraces();
        if (!weighteningFound) checkIfRomajiEqualsIgnoreCaseSearch();
        if (!weighteningFound) checkIfPronunciationEqualsIgnoreCaseSearch();
        if (!weighteningFound) checkIfTranslationEqualsIgnoreCaseSearch();
    }

    private void checkIfCommentContainesSearchInJapaneseBraces() {
        String comment = vocable.getComment();
        if (comment.contains("「" + search + "」")) {
            weighteningFound = true;
            weighting = WEIGHTENING_COMMENT_IN_JAPANESE_BRACES_SEARCH;
        }
    }

    private void checkIfRomajiEqualsIgnoreCaseSearch() {
        checkIfEqualsIgnoreCaseSearch(vocable.getRomaji(),
                WEIGHTENING_ROMAJI_EQUALS_IGNORE_CASE_SENSIVITY_SEARCH);

    }

    private void checkIfPronunciationEqualsIgnoreCaseSearch() {
        checkIfEqualsIgnoreCaseSearch(vocable.getPronunciation(),
                WEIGHTENING_PRONOUNCIATION_EQUALS_IGNORE_CASE_SENSIVITY_SEARCH);
    }

    private void checkIfTranslationEqualsIgnoreCaseSearch() {
        checkIfAnyElementEqualsIgnoreCaseSearch(vocable.getCompareTranslations(),
                WEIGHTENING_TRANSLATION_EQUALS_IGNORE_CASE_SENSIVITY_SEARCH);
    }

    private void checkIfAnyElementEqualsIgnoreCaseSearch(List<String> list, int weighteningToSet) {
        for (String member : list) {
            checkIfEqualsIgnoreCaseSearch(member, weighteningToSet);
            if (weighteningFound) {
                return;
            }
        }
    }

    private void checkIfEqualsIgnoreCaseSearch(String fieldContent, int weighteningToSet) {
        if (fieldContent.equals(loweredCaseSearch)) {
            weighteningFound = true;
            weighting = weighteningToSet;
        }
    }

    private void checkIfSearchAgainstCompare() {
        if (!weighteningFound) checkIfCompareKanaEqualsCompareSearch();
        if (!weighteningFound) checkIfCompareKanjiEqualsCompareSearch();
        if (!weighteningFound) checkIfCompareRomajiEqualsCompareSearch();
        if (!weighteningFound) checkIfCompareTranslationEqualsCompareSearch();
    }

    private void checkIfCompareKanaEqualsCompareSearch() {
        checkIfCompareEqualsCompareSearch(vocable.getCompareKana(),
                WEIGHTENING_COMPARE_KANA_EQUALS_COMPARE_SEARCH);
    }

    private void checkIfCompareKanjiEqualsCompareSearch() {
        checkIfCompareEqualsCompareSearch(vocable.getCompareKanji(),
                WEIGHTENING_COMPARE_KANJI_EQUALS_COMPARE_SEARCH);

    }

    private void checkIfCompareRomajiEqualsCompareSearch() {
        checkIfCompareEqualsCompareSearch(vocable.getCompareRomaji(),
                WEIGHTENING_COMPARE_ROMAJI_EQUALS_COMPARE_SEARCH);
    }

    private void checkIfCompareTranslationEqualsCompareSearch() {
        checkIfAnyCompareElementEqualsCompareSearch(vocable.getCompareTranslations(),
                WEIGHTENING_COMPARE_TRANSLATION_EQUALS_COMPARE_SEARCH);

    }

    private void checkIfAnyCompareElementEqualsCompareSearch(List<String> list,
            int weighteningToSet) {
        for (String member : list) {
            checkIfCompareEqualsCompareSearch(member, weighteningToSet);
            if (weighteningFound) {
                return;
            }
        }
    }

    private void checkIfCompareEqualsCompareSearch(String fieldContent, int weighteningToSet) {
        if (fieldContent.equals(compareSearch)) {
            weighteningFound = true;
            weighting = weighteningToSet;
        }
    }

    private void checkIfStartsWithSearch() {
        if (!weighteningFound) checkIfKanaStartsWithSearch();
        if (!weighteningFound) checkIfKanjiStartsWithSearch();
        if (!weighteningFound) checkIfRomajiStartsWithSearch();
        if (!weighteningFound) checkIfPronunciationStartsWithSearch();
        if (!weighteningFound) checkIfTranslationStartsWithSearch();
        if (!weighteningFound) checkIfCommentStartsWithSearch();
        if (!weighteningFound) checkIfSearchWordStartsWithSearch();
        if (!weighteningFound) checkIfPartOfSpeachStartsWithSearch();
    }

    private void checkIfKanaStartsWithSearch() {
        checkIfStartsWithSearch(vocable.getKana(), WEIGHTENING_KANA_STARTS_WITH_SEARCH);
    }

    private void checkIfKanjiStartsWithSearch() {
        checkIfStartsWithSearch(vocable.getKanji(), WEIGHTENING_KANJI_STARTS_WITH_SEARCH);
    }

    private void checkIfRomajiStartsWithSearch() {
        checkIfStartsWithSearch(vocable.getRomaji(), WEIGHTENING_ROMAJI_STARTS_WITH_SEARCH);
    }

    private void checkIfPronunciationStartsWithSearch() {
        checkIfStartsWithSearch(vocable.getPronunciation(),
                WEIGHTENING_PRONOUNCIATION_STARTS_WITH_SEARCH);
    }

    private void checkIfTranslationStartsWithSearch() {
        checkIfAnyElementStartsWithSearch(vocable.getTranslations(),
                WEIGHTENING_TRANSLATION_STARTS_WITH_SEARCH);
    }

    private void checkIfCommentStartsWithSearch() {
        checkIfStartsWithSearch(vocable.getComment(), WEIGHTENING_COMMENT_STARTS_WITH_SEARCH);
    }

    private void checkIfSearchWordStartsWithSearch() {
        checkIfAnyElementStartsWithSearch(vocable.getSearchWords(),
                WEIGHTENING_SEARCH_WORD_STARTS_WITH_SEARCH);
    }

    private void checkIfPartOfSpeachStartsWithSearch() {
        checkIfAnyElementStartsWithSearch(vocable.getPartsOfSpeech(),
                WEIGHTENING_PART_OF_SPEACH_STARTS_WITH_SEARCH);
    }

    private void checkIfAnyElementStartsWithSearch(List<String> list, int weighteningToSet) {
        for (String member : list) {
            checkIfStartsWithSearch(member, weighteningToSet);
            if (weighteningFound) {
                return;
            }
        }
    }

    private void checkIfStartsWithSearch(String fieldContent, int weighteningToSet) {
        if (fieldContent.startsWith(search)) {
            weighteningFound = true;
            weighting = weighteningToSet;
        }
    }

    private void checkIfEndsWithSearch() {
        if (!weighteningFound) checkIfKanaEndsWithSearch();
        if (!weighteningFound) checkIfKanjiEndsWithSearch();
        if (!weighteningFound) checkIfRomajiEndsWithSearch();
        if (!weighteningFound) checkIfPronunciationEndsWithSearch();
        if (!weighteningFound) checkIfTranslationEndsWithSearch();
        if (!weighteningFound) checkIfCommentEndsWithSearch();
        if (!weighteningFound) checkIfSearchWordEndsWithSearch();
        if (!weighteningFound) checkIfPartOfSpeachEndsWithSearch();
    }

    private void checkIfKanaEndsWithSearch() {
        checkIfEndsWithSearch(vocable.getKana(), WEIGHTENING_KANA_ENDS_WITH_SEARCH);
    }

    private void checkIfKanjiEndsWithSearch() {
        checkIfEndsWithSearch(vocable.getKanji(), WEIGHTENING_KANJI_ENDS_WITH_SEARCH);
    }

    private void checkIfRomajiEndsWithSearch() {
        checkIfEndsWithSearch(vocable.getRomaji(), WEIGHTENING_ROMAJI_ENDS_WITH_SEARCH);
    }

    private void checkIfPronunciationEndsWithSearch() {
        checkIfEndsWithSearch(vocable.getPronunciation(),
                WEIGHTENING_PRONOUNCIATION_ENDS_WITH_SEARCH);
    }

    private void checkIfTranslationEndsWithSearch() {
        checkIfAnyElementEndsWithSearch(vocable.getTranslations(),
                WEIGHTENING_TRANSLATION_ENDS_WITH_SEARCH);
    }

    private void checkIfCommentEndsWithSearch() {
        checkIfEndsWithSearch(vocable.getComment(), WEIGHTENING_COMMENT_ENDS_WITH_SEARCH);
    }

    private void checkIfSearchWordEndsWithSearch() {
        checkIfAnyElementEndsWithSearch(vocable.getSearchWords(),
                WEIGHTENING_SEARCH_WORD_ENDS_WITH_SEARCH);
    }

    private void checkIfPartOfSpeachEndsWithSearch() {
        checkIfAnyElementEndsWithSearch(vocable.getPartsOfSpeech(),
                WEIGHTENING_PART_OF_SPEACH_ENDS_WITH_SEARCH);
    }

    private void checkIfAnyElementEndsWithSearch(List<String> list, int weighteningToSet) {
        for (String member : list) {
            checkIfEndsWithSearch(member, weighteningToSet);
            if (weighteningFound) {
                return;
            }
        }
    }

    private void checkIfEndsWithSearch(String fieldContent, int weighteningToSet) {
        if (fieldContent.endsWith(search)) {
            weighteningFound = true;
            weighting = weighteningToSet;
        }
    }

    private void checkIfContainsSearchAsSingleWord() {
        if (!weighteningFound) checkIfKanaContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfKanjiContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfRomajiContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfPronunciationContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfTranslationContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfCommentContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfSearchWordContainsSearchAsSingleWord();
        if (!weighteningFound) checkIfPartOfSpeachContainsSearchAsSingleWord();
    }

    private void checkIfKanaContainsSearchAsSingleWord() {
        checkIfContainsSearchAsSingleWord(vocable.getKana(),
                WEIGHTENING_KANA_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfKanjiContainsSearchAsSingleWord() {
        checkIfContainsSearchAsSingleWord(vocable.getKanji(),
                WEIGHTENING_KANJI_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfRomajiContainsSearchAsSingleWord() {
        checkIfContainsSearchAsSingleWord(vocable.getRomaji(),
                WEIGHTENING_ROMAJI_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfPronunciationContainsSearchAsSingleWord() {
        checkIfContainsSearchAsSingleWord(vocable.getPronunciation(),
                WEIGHTENING_PRONOUNCIATION_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfTranslationContainsSearchAsSingleWord() {
        checkIfAnyElementContainsSearchAsSingleWord(vocable.getTranslations(),
                WEIGHTENING_TRANSLATION_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfCommentContainsSearchAsSingleWord() {
        checkIfContainsSearchAsSingleWord(vocable.getComment(),
                WEIGHTENING_COMMENT_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfSearchWordContainsSearchAsSingleWord() {
        checkIfAnyElementContainsSearchAsSingleWord(vocable.getSearchWords(),
                WEIGHTENING_SEARCH_WORD_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfPartOfSpeachContainsSearchAsSingleWord() {
        checkIfAnyElementContainsSearchAsSingleWord(vocable.getPartsOfSpeech(),
                WEIGHTENING_PART_OF_SPEACH_CONTAINS_SEARCH_AS_SINGLE_WORD);
    }

    private void checkIfAnyElementContainsSearchAsSingleWord(List<String> list,
            int weighteningToSet) {
        for (String member : list) {
            checkIfContainsSearchAsSingleWord(member, weighteningToSet);
            if (weighteningFound) {
                return;
            }
        }
    }

    private void checkIfContainsSearchAsSingleWord(String fieldContent, int weighteningToSet) {
        if (fieldContent.contains(" " + search + " ")) {
            weighteningFound = true;
            weighting = weighteningToSet;
        }
    }

    /**
     * Getter für die Relevanz der Vokabel.
     *
     * Eine höhere Relevanz drückt sich in einer kleineren Zahl aus.
     */
    public int getWeighting() {
        return weighting;
    }

}
