package de.duehl.swing.text.html;

/*
 * Copyright 2021 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.List;

import de.duehl.basics.collections.CollectionsHelper;

/**
 * Diese Klasse prüft, ob ein Wert "neu" und geeignet ist, hervorgehoben zu werden.
 *
 * @version 1.01     2021-10-15
 * @author Christian Dühl
 */

public class KnownValueHandling {

    /** Text in dem die Begriffe vorkommen könnten. */
    public final String text;

    /** Gibt an ob überprüft wird, ob die neue Variable im Text vorkommt. */
    public boolean checkNewValueIsContainedInText;

    /**
     * Konstruktor.
     *
     * @param text
     *            Text in dem die Begriffe vorkommen könnten.
     */
    public KnownValueHandling(String text) {
        this.text = text;
        checkNewValueIsContainedInText = true;
    }

    /**
     * Veranlasst, dass nicht geprüft wird, ob der neue Wert im Text vorkommt
     *
     * Dies kann sinnvoll sein, wenn SChreibweisenabänderungen erst nach dem KnownValueHandling
     * erfolgen.
     */
    public void skipCheckNewValueIsContainedInText() {
        checkNewValueIsContainedInText = false;
    }

    /**
     * Fügt den übergebenen Wert zur Liste hinzu, wenn er verschieden genug ist und im Text
     * vorkommt.
     *
     * @param value
     *            Eventuell hinzuzufügender Wert.
     * @param values
     *            Liste zu der der Wert hinzugefügt werden soll, falls er nicht zu anderen
     *            Elementen der Liste zu ähnlich ist und weitere Kriterien erfüllt.
     */
    public void perhapsAdd(String value, List<String> values) {
        if (isValueNewAndGood(value, values)) {
            values.add(value);
        }
    }

    /**
     * Fügt den übergebenen Wert zur Liste hinzu, wenn er verschieden genug ist und im Text
     * vorkommt.
     *
     * @param value
     *            Eventuell hinzuzufügender Wert.
     * @param values
     *            Liste zu der der Wert hinzugefügt werden soll, falls er nicht zu anderen
     *            Elementen der Liste zu ähnlich ist und weitere Kriterien erfüllt.
     * @param knownValue
     *            Ein weiterer Wert, gegen die der mögliche neue Wert geprüft werden soll.
     */
    public void perhapsAdd(String value, List<String> values, String knownValue) {
        perhapsAdd(value, values, CollectionsHelper.buildListFrom(knownValue));
    }

    /**
     * Fügt den übergebenen Wert zur Liste hinzu, wenn er verschieden genug ist und im Text
     * vorkommt.
     *
     * @param value
     *            Eventuell hinzuzufügender Wert.
     * @param values
     *            Liste zu der der Wert hinzugefügt werden soll, falls er nicht zu anderen
     *            Elementen der Liste zu ähnlich ist und weitere Kriterien erfüllt.
     * @param knownValues
     *            Liste mit weiteren Werten, gegen die der mögliche neue Wert geprüft werden soll.
     */
    public void perhapsAdd(String value, List<String> values, List<String> knownValues) {
        List<String> allKnownValues = new ArrayList<>();
        allKnownValues.addAll(values);
        allKnownValues.addAll(knownValues);
        if (isValueNewAndGood(value, allKnownValues)) {
            values.add(value);
        }
    }

    /**
     * Prüft ob der Wert "neu" und geeignet ist, hervorgehoben zu werden.
     *
     * @param perhapsNewValue
     *            Zu prüfender Wert.
     * @param knownValues
     *            Liste von bereits als hervorzuheben erkannter Werte.
     * @return Wahrheitswert.
     */
    boolean isValueNewAndGood(String perhapsNewValue, List<String> knownValues) {
        if (knownValues.contains(perhapsNewValue)
                || perhapsNewValue.isBlank()) {
            return false;
        }

        if (checkNewValueIsContainedInText && !text.contains(perhapsNewValue)) {
            return false;
        }

        for (String knownValue : knownValues) {
            if (!isDifferentEnough(knownValue, perhapsNewValue)) {
                return false;
            }
        }

        return true;
    }

    private boolean isDifferentEnough(String knownValue, String perhapsNewValue) {
        if (knownValue.isBlank()) {
            // Wir wissen hier, dass perhapsNewValue nicht blank ist!
            // Der bekannte Wert darf durchaus leer sein, etwa im Insolvenztool ist es
            // ein Wert aus den Adressfeldern, die nicht immer gefüllt sind.
            return true;
        }
        else if (knownValue.equals(perhapsNewValue)) {
            return false;
        }
        else if (checkNewValueIsContainedInText) {
            return !oneContainsTheOther(knownValue, perhapsNewValue);
            /*
             * Wir gehen hier davon aus, dass alle "knownValues" die Methoden dieser Klasse
             * durchlaufen haben, daher prüfen wir hier nicht (erneut) auf
             *     text.contains(knownValue)
             * was sonst Sinn machen würde, wenn sie sich gegenseitig enthalten.
             */
        }
        else {
            return true;
        }
    }

    private boolean oneContainsTheOther(String value, String alternativeValue) {
        return value.contains(alternativeValue)
                || alternativeValue.contains(value);
    }

}
