/*
 * Copyright 2015 Michael Rozumyanskiy
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.michaelrocks.lightsaber.internal;

import io.michaelrocks.lightsaber.ConfigurationException;
import io.michaelrocks.lightsaber.Injector;
import io.michaelrocks.lightsaber.Key;

import javax.inject.Provider;
import java.util.HashMap;
import java.util.Map;

public class LightsaberInjector implements Injector {
    private static final Key<Injector> INJECTOR_KEY = new Key<Injector>(Injector.class);

    private final Injector parentInjector;
    private final Map<Key<?>, Provider<?>> providers = new HashMap<Key<?>, Provider<?>>();

    public LightsaberInjector() {
        this(null);
    }

    public LightsaberInjector(final Injector parentInjector) {
        this.parentInjector = parentInjector;
        registerProvider(INJECTOR_KEY, new InstanceProvider<Injector>(this));
    }

    @Override
    public void injectMembers(final Object target) {
        throw new IllegalStateException(
                "This method must not be called. It must be substituted with a valid injector instead.");
    }

    @Override
    public <T> T getInstance(final Key<? extends T> key) {
        return getProvider(key).get();
    }

    @Override
    public <T> Provider<T> getProvider(final Key<? extends T> key) {
        // noinspection unchecked
        final Provider<T> provider = (Provider<T>) providers.get(key);
        if (provider == null) {
            if (parentInjector == null) {
                throw new ConfigurationException("Provider for " + key + " not found");
            } else {
                return parentInjector.getProvider(key);
            }
        }
        return provider;
    }

    @Override
    public Map<Key<?>, Provider<?>> getAllProviders() {
        return new HashMap<Key<?>, Provider<?>>(providers);
    }

    public <T> void registerProvider(final Key<T> key, final Provider<T> provider) {
        final Provider<?> oldProvider = providers.put(key, provider);
        if (oldProvider != null) {
            throw new ConfigurationException("Provider for " + key + " already registered");
        }
    }
}

@@ -816,16 +816,46 @@
 ovider;%0A
+import java.util.Collections;%0A
 import j
@@ -2330,22 +2330,255 @@
         
-return
+final Map%3CKey%3C?%3E, Provider%3C?%3E%3E parentProviders =%0A                parentInjector == null ? Collections.%3CKey%3C?%3E, Provider%3C?%3E%3EemptyMap() : parentInjector.getAllProviders();%0A        final Map%3CKey%3C?%3E, Provider%3C?%3E%3E allProviders =%0A               
  new Has
@@ -2604,24 +2604,30 @@
 er%3C?%3E%3E(p
+arentP
 roviders
 );%0A    %7D
@@ -2618,17 +2618,158 @@
 roviders
-)
+.size() + providers.size());%0A        allProviders.putAll(parentProviders);%0A        allProviders.putAll(providers);%0A        return allProviders
 ;%0A    %7D%0A
@@ -3048,24 +3048,24 @@
 gistered%22);%0A
-
         %7D%0A  
@@ -3067,11 +3067,90 @@
  %7D%0A    %7D
+%0A%0A    Map%3CKey%3C?%3E, Provider%3C?%3E%3E getProviders() %7B%0A        return providers;%0A    %7D
 %0A%7D%0A

Return own and parent providers when calling getAllProviders() on a LightsaberInjector instance