package de.renew.net;

import java.util.ConcurrentModificationException;
import java.util.Set;
import java.util.WeakHashMap;


/**
 * The net instance list class keeps track of all well known net instances.
 * Nets are configured to register their instance automatically during
 * creation confirmation.
 * <p>
 * Currently, no special structure is given to this list.
 * <p>
 * Accesses to the net list are synchronized to forbid concurrent updates.
 * No special actions must be taken on the caller side.
 * No deadlocks are possible.
 */
public class NetInstanceList {
    private static final WeakHashMap<NetInstance, Object> NET_INSTANCES = new WeakHashMap<>();

    /**
     * This is an entirely static class.
     * No instance creation is allowed.
     */
    private NetInstanceList() {}

    /**
     * Register a net instance. If the net instance has already
     * been registered, ignore.
     *
     * @param instance the net instance to be registered
     */
    public static synchronized void add(NetInstance instance) {
        NET_INSTANCES.put(instance, null);
    }

    /**
     * Create a snapshot of the list of registered net instances.
     * The net instances are returned in a arbitrary order.
     *
     * @return an array that references all well-known net instances
     */
    public static synchronized NetInstance[] getAll() {
        while (true) {
            try {
                Set<NetInstance> keySet = NET_INSTANCES.keySet();
                NetInstance[] result = new NetInstance[keySet.size()];
                int index = 0;

                for (NetInstance instance : keySet) {
                    result[index++] = instance;
                }

                return result;
            } catch (ConcurrentModificationException e) {
                // The net instances have changed due to garbage collection.
                // Rebuild the list.
            }
        }
    }

    /**
     * Looks for a netInstance with the given Id.
     *
     * @param netInstanceId the Id for the netInstance, for example "agent[123]"
     *
     * @return a NetInstance Object, if this netInstances still exist, "null" if there is (no longer) a NetInstance
     */
    public static synchronized NetInstance getNetInstance(String netInstanceId) {
        while (true) {
            try {
                for (NetInstance netInstance : NET_INSTANCES.keySet()) {
                    if (netInstance.getID().equals(netInstanceId)) {
                        return netInstance;
                    }
                }
                return null; // Not found
            } catch (ConcurrentModificationException e) {
                // The net instances have changed due to garbage collection.
                // Rebuild the list.
            }
        }
    }
}