package de.duehl.basics.io.textfile.data;

/*
 * 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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Diese Klasse stellt eine Menge von Definitionen bestehend aus Schlüssel und Wert dar.
 *
 * @version 1.01     2021-03-01
 * @author Christian Dühl
 */

public class Definitions implements Iterable<Definition> {

    /** Liste mit den Definitionen. */
    private final List<Definition> definitions;

    /** Redundante Datenhaltung für schnellere Abfrage. */
    private final Map<String, String> keyToValue;

    /** Konstruktor. */
    public Definitions() {
        definitions = new ArrayList<>();
        keyToValue = new HashMap<>();
    }

    /** Fügt die übergebene Definition hinzu. */
    public void add(Definition definition) {
        if (containsKey(definition)) {
            throw new RuntimeException("Der Schlüssel ist bereits bekannt: " + definition);
        }
        else {
            definitions.add(definition);
            keyToValue.put(definition.getKey(), definition.getValue());
        }
    }

    /** Gibt an, ob der Schlüssel der übergebenen Definition bereits bekannt ist. */
    boolean containsKeySlow(Definition definition) {
        for (Definition knownDefinition : definitions) {
            if (knownDefinition.hasSameKey(definition)) {
                return true;
            }
        }

        return false;
    }

    /** Gibt an, ob der übergebene Schlüssel bereits bekannt ist. */
    boolean containsKeySlow(String key) {
        for (Definition knownDefinition : definitions) {
            if (knownDefinition.getKey().equals(key)) {
                return true;
            }
        }

        return false;
    }

    /** Gibt an, ob der Schlüssel der übergebenen Definition bereits bekannt ist. */
    public boolean containsKey(Definition definition) {
        return keyToValue.containsKey(definition.getKey());
    }

    /** Gibt an, ob der übergebene Schlüssel bereits bekannt ist. */
    public boolean containsKey(String key) {
        return keyToValue.containsKey(key);
    }

    /** Gibt den Wert zum angegebenen Schlüssel zurück. */
    public String getValueByKey(String key) {
        if (!containsKey(key)) {
            throw new RuntimeException("Unbekannter Schlüssel '" + key + "'!");
        }
        else {
            return keyToValue.get(key);
        }
    }

    /** Gibt die Anzahl der Definitionen zurück. */
    public int size() {
        return definitions.size();
    }

    /** Erzeugt eine Liste mit den Schlüsseln. */
    public List<String> getKeys() {
        List<String> keys = new ArrayList<>();

        for (Definition knownDefinition : definitions) {
            keys.add(knownDefinition.getKey());
        }

        return keys;
    }

    @Override
    public Iterator<Definition> iterator() {
        return definitions.iterator();
    }

    @Override
    public String toString() {
        return "Definitions : " + definitions;
        //return "Definitions [definitions=" + definitions + "]";
    }

}
