package de.duehl.basics.replacements;

/*
 * Copyright 2022 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 java.util.regex.Matcher;
import java.util.regex.Pattern;

import de.duehl.basics.replacements.data.FoundPlaceholder;
import de.duehl.basics.text.NumberString;

/**
 * Diese Klasse analysiert einen Text, in dem bestimmte Teile durch Platzhalter der Form
 * <<begriff:1>> ersetzt wurden die Struktur dieser Platzhalter.
 *
 * @version 1.01     2022-11-25
 * @author Christian Dühl
 */

public class ReplacementsAnalyser {

    /** Der Text, in dem bestimmte Teile durch Platzhalter der Form <<begriff:1>> ersetzt wurden. */
    private final String text;

    /** Die Liste der gefundenen Platzhalter. */
    private List<FoundPlaceholder> foundPlaceholders;

    /** Das Verzeichnis der gefundenen Platzhalter der Form <<begriff:1>> nach dem Begriff. */
    private Map<String, List<FoundPlaceholder>> placeHoldersByName;

    /**
     * Konstruktor.
     *
     * @param text
     *            Der Text, in dem bestimmte Teile durch Platzhalter der Form <<begriff:1>> ersetzt
     *            wurden.
     */
    public ReplacementsAnalyser(String text) {
        this.text = text;
    }

    /** Führt die Analyse durch. */
    public void analyse() {
        findPlaceholders();
        buildMap();
    }

    /** Das Pattern für einen Platzhalter der Form <<begriff:1>>. */
    private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(
            "<<([-a-z]+):(\\d+)>>");

    private void findPlaceholders() {
        foundPlaceholders = new ArrayList<>();

        Matcher matcher = PLACEHOLDER_PATTERN.matcher(text);
        while (matcher.find()) {
            int index = matcher.start();
            String placeholder = matcher.group();
            String name = matcher.group(1);
            String positionAsString = matcher.group(2);
            int position = NumberString.parseInt(positionAsString);
            FoundPlaceholder foundPlaceholder = new FoundPlaceholder(index, placeholder, name,
                    position);
            foundPlaceholders.add(foundPlaceholder);
        }
    }

    private void buildMap() {
        placeHoldersByName = new HashMap<>();

        for (FoundPlaceholder foundPlaceholder : foundPlaceholders) {
            String name = foundPlaceholder.getName();
            if (!placeHoldersByName.containsKey(name)) {
                placeHoldersByName.put(name, new ArrayList<>());
            }
            List<FoundPlaceholder> list = placeHoldersByName.get(name);
            list.add(foundPlaceholder);
        }
    }

    /**
     * Fügt den ersetzen Text über die übergebene Liste an.
     *
     * @param name
     *            Der Name der zugehörigen Platzhaltern (der Begriff am Anfang in <<begriff:1>>).
     * @param replacedTexts
     *            Die Liste mit den ersetzen Texten in der passenden Reihenfolge. Der Index der
     *            Liste gehört zur Position im Platzhalter (position = index + 1).
     */
    public void addReplacedTexts(String name, List<String> replacedTexts) {
        if (!replacedTexts.isEmpty()) { // Anderenfalls wurde kein Eintrag im Map erzeugt!
            List<FoundPlaceholder> list = placeHoldersByName.get(name);
            for (FoundPlaceholder foundPlaceholder : list) {
                int position = foundPlaceholder.getPosition();
                int index = position - 1;
                String replacedText = replacedTexts.get(index);
                foundPlaceholder.setReplacedText(replacedText);
            }
        }
    }

    /**
     * Hier wird überprüft, ob alle Listen aus der Map nach den Positionen sortiert sind, also ob
     * die Elemente von links nach rechts aufgefunden oder entsprechend sortiert wurden.
     */
    public boolean isEveryMapListIsSortedByPosition() {
        for (String key : placeHoldersByName.keySet()) {
            if (!isListIsSortedByPosition(placeHoldersByName.get(key))) {
                return false;
            }
        }
        return true;
    }

    private boolean isListIsSortedByPosition(List<FoundPlaceholder> list) {
        int lastPosition = 0;
        for (FoundPlaceholder foundPlaceholder : list) {
            int position = foundPlaceholder.getPosition();
            if (lastPosition + 1 != position) {
                return false;
            }
            lastPosition = position;
        }

        return true;
    }

    /** Getter für die Liste der gefundenen Platzhalter. */
    public List<FoundPlaceholder> getFoundPlaceholders() {
        return foundPlaceholders;
    }

    /**
     * Getter für das Verzeichnis der gefundenen Platzhalter der Form <<begriff:1>> nach dem
     * Begriff.
     */
    public Map<String, List<FoundPlaceholder>> getPlaceHoldersByName() {
        return placeHoldersByName;
    }

}
