package de.renew.plugin.di;

import java.lang.reflect.Method;
import java.util.HashMap;

import de.renew.plugin.annotations.Provides;


/**
 * A container is a simple collection of service definitions
 * @author Konstantin Simon Maria Moellers
 * @version 2015-10-11
 */
public class Container implements ServiceContainer {
    private final HashMap<Class<?>, Definition<?>> _definitions;

    /**
     * Creates a new collection of service definitions
     */
    public Container() {
        _definitions = new HashMap<>();
    }

    @Override
    public boolean has(Class<?> service) {
        return _definitions.containsKey(service);
    }

    @Override
    public Object get(Class<?> service) throws MissingDependencyException {
        if (!has(service)) {
            throw new MissingDependencyException(service);
        }

        return _definitions.get(service).create();
    }

    @Override
    public <T> void set(Class<?> service, T singleton) {
        addDefinition(new SingletonDefinition<>(service, singleton));
    }

    @Override
    public void addDefinition(Definition<?> definition) {
        _definitions.put(definition.getService(), definition);
    }

    @Override
    public void unbind(Class<?> service) {
        if (!has(service)) {
            throw new IllegalArgumentException(
                "Service " + service + " is not bound to this service container.");
        }

        _definitions.remove(service);
        unbindAssociatedServices(service);
    }

    private void unbindAssociatedServices(Class<?> service) {
        for (Method method : service.getMethods()) {
            if (method.isAnnotationPresent(Provides.class)) {
                _definitions.remove(method.getReturnType());
            }
        }
    }
}