package common.init;

import java.util.Iterator;
import java.util.Map;

import common.collect.BiMap;
import common.collect.HashBiMap;

public class RegistryNamespaced<K, V> extends RegistrySimple<K, V> implements IObjectIntIterable<V>
{
    protected final ObjectIntIdentityMap<V> underlyingIntegerMap = new ObjectIntIdentityMap();
    protected final Map<V, K> inverseObjectRegistry;

    public RegistryNamespaced()
    {
        this.inverseObjectRegistry = ((BiMap)this.registryObjects).inverse();
    }

    public void register(int id, K key, V value)
    {
        if(this.registryObjects.containsKey(key))
        	throw new IllegalArgumentException("Schlüssel " + String.valueOf(key) + " ist bereits mit ID " + 
        			this.underlyingIntegerMap.get(this.registryObjects.get(key)) + " registriert");
        if(this.underlyingIntegerMap.getByValue(id) != null)
        	throw new IllegalArgumentException("ID " + id + " ist bereits mit Name " + 
        			this.inverseObjectRegistry.get(this.underlyingIntegerMap.getByValue(id)) + " registriert");
        
        this.underlyingIntegerMap.put(value, id);
        this.putObject(key, value);
    }

    protected Map<K, V> createUnderlyingMap()
    {
        return HashBiMap.<K, V>create();
    }

    public V getObject(K name)
    {
        return super.getObject(name);
    }

    /**
     * Gets the name we use to identify the given object.
     */
    public K getNameForObject(V value)
    {
        return (K)this.inverseObjectRegistry.get(value);
    }

    /**
     * Does this registry contain an entry for the given key?
     */
    public boolean containsKey(K key)
    {
        return super.containsKey(key);
    }

    /**
     * Gets the integer ID we use to identify the given object.
     */
    public int getIDForObject(V value)
    {
        return this.underlyingIntegerMap.get(value);
    }

    /**
     * Gets the object identified by the given ID.
     */
    public V getObjectById(int id)
    {
        return (V)this.underlyingIntegerMap.getByValue(id);
    }

    public Iterator<V> iterator()
    {
        return this.underlyingIntegerMap.iterator();
    }
}
