package de.duehl.basics.text;

/*
 * Copyright 2024 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

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.basics.io.textfile.dictionary.Dictionary;
import de.duehl.basics.io.textfile.dictionary.DictionaryEntry;

/**
 * Diese Klasse verbessert allgemeine Tipp- und Rechtschreibfehler oder sonstige Umsetzungen in
 * Texten.
 *
 * Damit die Reihenfolge von langen und kurzen falschen Begriffen im Verzeichnis keine Rolle
 * spielt, wird hier ein gewisser Aufwand betrieben.
 *
 * @version 1.01     2024-05-16
 * @author Christian Dühl
 */

public class SpellingErrorCorrector {

    /**
     * Die Liste mit allen falsch geschriebenen Worten aus dem Verzeichnis mit den richtigen und
     * zugehörigen falschen Schreibweisen.
     */
    private final List<String> mispelledPhrases;

    /** Das Verzeichnis mit den Falsch geschriebenen Worten zur richtig geschriebenen Variante. */
    private final Map<String, String> mispelledToCorrectWords;

    /**
     * Konstruktor.
     *
     * @param spellingErrorsDictionary
     *            Verzeichnis mit den richtigen und zugehörigen falschen Schreibweisen.
     */
    public SpellingErrorCorrector(Dictionary spellingErrorsDictionary) {
        mispelledPhrases = new ArrayList<>();
        mispelledToCorrectWords = new HashMap<>();

        initListAndMapWithDictionary(spellingErrorsDictionary);
        sortMispelledPhrasesByLengthDescanding();
    }

    private void initListAndMapWithDictionary(Dictionary spellingErrorsDictionary) {
        for (DictionaryEntry dictionaryEntry : spellingErrorsDictionary) {
            initListAndMapWithDictionaryList(dictionaryEntry);
        }
    }

    private void initListAndMapWithDictionaryList(DictionaryEntry dictionaryEntry) {
        String correctSpelledPhrase = dictionaryEntry.getMainWord();
        List<String> mispelledAlternatives = dictionaryEntry.getAlternatives();

        if (mispelledAlternatives.isEmpty()) {
            throw new RuntimeException("Eine Liste im Dictionary enthält nur ein richtig "
                    + "geschriebenes Wort, aber keine falsch geschriebenen: '"
                    + correctSpelledPhrase + "'.");
        }

        for (String mispelledPhrase : mispelledAlternatives) {
            if (mispelledPhrases.contains(mispelledPhrase)) {
                throw new RuntimeException("Falschgeschriebener Begriff ist doppelt "
                        + "vorhanden: '" + mispelledPhrase + "'.");
            }
            mispelledPhrases.add(mispelledPhrase);
            mispelledToCorrectWords.put(mispelledPhrase, correctSpelledPhrase);
        }
    }

    private void sortMispelledPhrasesByLengthDescanding() {
        CollectionsHelper.sortStringListByLengthDescanding(mispelledPhrases);
    }

    /** Korrigiert einen einzelnen String. */
    public String correct(String originalText) {
        String text = originalText;

        for (String mispelledPhrase : mispelledPhrases) {
            String correctPhrase = mispelledToCorrectWords.get(mispelledPhrase);
            text = text.replace(mispelledPhrase, correctPhrase);
        }

        return text;
    }

    /** Korrigiert eine ganze Liste von String, die Inhalte der Liste werden dabei verändert. */
    public void correct(List<String> texts) {
        for (int index = 0; index < texts.size(); ++index) {
            String text = texts.get(index);
            String correctedText = correct(text);
            if (!text.equals(correctedText)) {
                texts.set(index, correctedText);
            }
        }
    }

    /**
     * Getter für die Liste mit allen falsch geschriebenen Worten aus dem Verzeichnis mit den
     * richtigen und zugehörigen falschen Schreibweisen.
     */
    public List<String> getMispelledPhrases() {
        return mispelledPhrases;
    }

}
