package com.wizzardo.http.framework.di;

import com.wizzardo.tools.cache.Cache;
import com.wizzardo.tools.cache.Computable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author: moxa
 * Date: 7/22/13
 */
public class DependencyFactory {

    private List<Class> classes;
    private Map<Class, Class> mapping = new HashMap<Class, Class>();

    @SuppressWarnings("unchecked")
    private Cache<Class, Dependency> dependencies = new Cache<Class, Dependency>(0, new Computable<Class, Dependency>() {
        @Override
        public Dependency compute(Class clazz) {

            Injectable injectable = (Injectable) getAnnotation(clazz, Injectable.class);
            if (injectable != null)
                return injectable.scope().createDependency(clazz);

            if (Modifier.isAbstract(clazz.getModifiers()) || Modifier.isInterface(clazz.getModifiers())) {
                Class implementation = mapping.get(clazz);
                if (implementation == null)
                    for (Class cl : classes) {
                        if (clazz.isAssignableFrom(cl)
                                && !Modifier.isInterface(cl.getModifiers())
                                && !Modifier.isAbstract(cl.getModifiers())
                                && (injectable = (Injectable) getAnnotation(cl, Injectable.class)) != null
                                ) {
                            if (implementation != null) {
                                throw new IllegalStateException("can't resolve dependency '" + clazz + "'. Found more than one implementation: " + implementation + " and " + cl);
                            }
                            implementation = cl;
                        }
                    }
                if (implementation != null) {

                    if (injectable == null)
                        injectable = (Injectable) getAnnotation(implementation, Injectable.class);

                    if (injectable != null)
                        return injectable.scope().createDependency(clazz);
                    else
                        return new PrototypeDependency(implementation);
                }
            }

            if (Service.class.isAssignableFrom(clazz)) {
                return new SingletonDependency(clazz);
            }

            throw new IllegalStateException("can't create dependency-holder for class: " + clazz);
        }
    });

    static Annotation getAnnotation(Class clazz, Class annotation) {
        while (clazz != null) {
            Annotation a = clazz.getAnnotation(annotation);
            if (a != null) {
                return a;
            }
            clazz = clazz.getSuperclass();
        }
        return null;
    }

    private static class DependencyFactoryHolder {
        private static final DependencyFactory instance = new DependencyFactory();
    }

    public static <T> T getDependency(Class<T> clazz) {
        return DependencyFactoryHolder.instance.resolve(clazz);
    }

    public static <T> T get(Class<T> clazz) {
        return DependencyFactoryHolder.instance.resolve(clazz);
    }

    public static DependencyFactory get() {
        return DependencyFactoryHolder.instance;
    }

    @SuppressWarnings("unchecked")
    private <T> T resolve(Class<T> clazz) {
        return (T) dependencies.get(clazz).get();
    }

    public void setClasses(List<Class> classes) {
        this.classes = classes;
    }

    public void bind(Class abstractClass, Class implementation) {
        mapping.put(abstractClass, implementation);
    }

    public <T> void register(Class<T> clazz, Dependency<T> dependency) {
        dependencies.put(clazz, dependency);
    }
}

@@ -1063,32 +1063,34 @@
 ntation == null)
+ %7B
 %0A               
@@ -1826,32 +1826,50 @@
               %7D%0A
+                %7D%0A
                 
@@ -1894,25 +1894,24 @@
  != null) %7B%0A
-%0A
             
@@ -2145,37 +2145,46 @@
 reateDependency(
-clazz
+implementation
 );%0A             

fix di