package triaina.injector;
import java.util.ArrayList;
import java.util.WeakHashMap;
import triaina.commons.exception.CommonRuntimeException;
import triaina.injector.internal.TriainaInjectorImpl;
import roboguice.event.EventManager;
import roboguice.inject.ContextScope;
import roboguice.inject.ContextScopedRoboInjector;
import roboguice.inject.ResourceListener;
import roboguice.inject.ViewListener;
import android.app.Application;
import android.content.Context;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Stage;
import com.google.inject.spi.DefaultElementVisitor;
import com.google.inject.spi.Element;
import com.google.inject.spi.Elements;
import com.google.inject.spi.StaticInjectionRequest;
public class TriainaInjectorFactory {
public static final Stage DEFAULT_STAGE = Stage.PRODUCTION;
protected static WeakHashMap<Application,Injector> sInjectors = new WeakHashMap<Application,Injector>();
protected static WeakHashMap<Application,ResourceListener> sResourceListeners = new WeakHashMap<Application, ResourceListener>();
protected static WeakHashMap<Application,ViewListener> sViewListeners = new WeakHashMap<Application, ViewListener>();
private TriainaInjectorFactory() {}
public static Injector getBaseApplicationInjector(Application application) {
Injector injector = sInjectors.get(application);
if(injector != null )
return injector;
synchronized (TriainaInjectorFactory.class) {
injector = sInjectors.get(application);
if(injector != null)
return injector;
return setBaseApplicationInjector(application, DEFAULT_STAGE);
}
}
public static Injector setBaseApplicationInjector(final Application application, Stage stage, Module... modules) {
for(Element element : Elements.getElements(modules)) {
element.acceptVisitor(new DefaultElementVisitor<Void>() {
@Override
public Void visit(StaticInjectionRequest element) {
getResourceListener(application).requestStaticInjection(element.getType());
return null;
}
});
}
synchronized (TriainaInjectorFactory.class) {
final Injector injector = Guice.createInjector(stage, modules);
sInjectors.put(application, injector);
return injector;
}
}
/**
* Return the cached Injector instance for this application, or create a new one if necessary.
*/
public static Injector setBaseApplicationInjector(Application application, Stage stage) {
synchronized (TriainaInjectorFactory.class) {
final int id = application.getResources().getIdentifier("triaina_modules", "array", application.getPackageName());
final String[] moduleNames = id > 0 ? application.getResources().getStringArray(id) : new String[]{};
final ArrayList<Module> modules = new ArrayList<Module>();
final DefaultTriainaModule defaultRoboModule = newDefaultRoboModule(application);
modules.add(defaultRoboModule);
try {
for (String name : moduleNames) {
final Class<? extends Module> clazz = Class.forName(name).asSubclass(Module.class);
try {
modules.add(clazz.getDeclaredConstructor(Context.class).newInstance(application));
} catch(final NoSuchMethodException noActivityConstructorException) {
modules.add(clazz.newInstance());
}
}
} catch (Exception exp) {
throw new CommonRuntimeException(exp);
}
final Injector injector = setBaseApplicationInjector(application, stage, modules.toArray(new Module[modules.size()]));
sInjectors.put(application, injector);
return injector;
}
}
public static TriainaInjector getInjector(Context context) {
final Application application = (Application)context.getApplicationContext();
return new TriainaInjectorImpl(new ContextScopedRoboInjector(context, getBaseApplicationInjector(application), getViewListener(application)));
}
public static <T> T injectMembers(Context context, T t) {
getInjector(context).injectMembers(t);
return t;
}
public static DefaultTriainaModule newDefaultRoboModule(final Application application) {
return new DefaultTriainaModule(application, new ContextScope(), getViewListener(application), getResourceListener(application));
}
protected static ResourceListener getResourceListener(Application application ) {
ResourceListener resourceListener = sResourceListeners.get(application);
if(resourceListener == null) {
synchronized (TriainaInjectorFactory.class) {
if(resourceListener == null) {
resourceListener = new ResourceListener(application);
sResourceListeners.put(application,resourceListener);
}
}
}
return resourceListener;
}
protected static ViewListener getViewListener(final Application application) {
ViewListener viewListener = sViewListeners.get(application);
if(viewListener == null) {
synchronized (TriainaInjectorFactory.class) {
if(viewListener==null) {
viewListener = new ViewListener();
sViewListeners.put(application,viewListener);
}
}
}
return viewListener;
}
public static void destroyInjector(Context context) {
final TriainaInjector injector = getInjector(context);
injector.getInstance(EventManager.class).destroy();
injector.getInstance(ContextScope.class).destroy(context);
sInjectors.remove(context);
}
}