package de.duehl.basics.collections;

/*
 * Copyright 2018 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.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import de.duehl.basics.collections.data.KeyAndValue;

/**
 * Diese Klasse stellt ein Verzeichnis von String-Schlüsseln zugeordneten Elementen dar, welches
 * die Reihenfolge ihrer Erzeugung behält.
 *
 * Besser OrderedNonOverwritingMap verwenden!
 *
 * @version 1.01     2018-10-18
 * @author Christian Dühl
 */

@Deprecated
public class OrderedStringKeyMap<T> implements Iterable<KeyAndValue<T>> {

    private final List<KeyAndValue<T>> list;
    private final Set<String> keys;
    private final Map<String, T> map;

    public OrderedStringKeyMap() {
        list = new ArrayList<>();
        keys = new HashSet<>();
        map = new HashMap<>();
    }

    public int size() {
        internalCheck();
        return list.size();
    }

    private void internalCheck() {
        int size1 = list.size();
        int size2 = keys.size();
        int size3 = map.size();
        if (size1 != size2 || size2 != size3) {
            throw new RuntimeException("Interner Fehler, die Verwaltungsobjekte sind verschieden "
                    + "groß!" + "\n\t"
                    + "list.size() = " + list.size() + "\n\t"
                    + "keys.size() = " + keys.size() + "\n\t"
                    + "map.size() = " + map.size() + "\n");
        }
    }

    public boolean isEmpty() {
        internalCheck();
        return list.isEmpty();
    }

    public boolean containsKey(String key) {
        internalCheck();
        return keys.contains(key);
    }

    public boolean containsValue(T value) {
        internalCheck();

        for (KeyAndValue<T> keyAndValue : list) {
            if (value.equals(keyAndValue.getValue())) {
                return true;
            }
        }

        return false;
    }

    public T get(String key) {
        internalCheck();
        if (!keys.contains(key)) {
            throw new IllegalArgumentException("Der Schlüssel '" + key + "' ist nicht vorhanden.");
        }
        return map.get(key);
    }

    public void put(String key, T value) {
        internalCheck();

        if (keys.contains(key)) {
            throw new IllegalArgumentException("Der Schlüssel '" + key + "' ist bereits vorhanden.");
        }

        keys.add(key);
        map.put(key, value);
        list.add(new KeyAndValue<T>(key, value));

        internalCheck();
    }

    public T remove(String key) {
        internalCheck();

        if (!keys.contains(key)) {
            throw new IllegalArgumentException("Der Schlüssel '" + key + "' ist nicht vorhanden.");
        }

        T removedValue = map.get(key);

        map.remove(key);
        list.remove(new KeyAndValue<T>(key, removedValue));
        keys.remove(key);

        internalCheck();

        return removedValue;
    }

    public void clear() {
        list.clear();
        keys.clear();
        map.clear();
        internalCheck();
    }

    @Override
    public Iterator<KeyAndValue<T>> iterator() {
        internalCheck();
        return list.iterator();
    }

}
