package proton.inject.binding;

import java.lang.annotation.Annotation;

import javax.inject.Provider;

import android.os.Build;

import proton.inject.ConfigurationException;
import proton.inject.scope.ApplicationScoped;
import proton.inject.scope.ContextScoped;
import proton.inject.scope.Dependent;
import proton.inject.util.InjectorUtils;

public class BindingBuilderImpl<T> implements BindingBuilder<T> {
	private final Binding<T> mBinding;
	private final Bindings mBindings;

	public BindingBuilderImpl(Class<T> clazz, Bindings bindings) {
		mBinding = new Binding<T>(clazz);
		mBindings = bindings;

		mBindings.register(mBinding);

		if (!InjectorUtils.isAbstract(clazz)) {
			setScope(clazz);
			validateAnnotation(clazz);
		}
	}

	@Override
	public ScopedBuilder to(Class<? extends T> to) {
		mBinding.setToClass(checkNotNull(to, "to"));
		setScope(to);
		validateAnnotation(to);
		return this;
	}

	@Override
	public ScopedBuilder toProvider(Class<? extends Provider<T>> provider) {
		mBinding.setProviderClass(checkNotNull(provider, "provider"));
		setScope(InjectorUtils.toActualClass(provider));
		validateAnnotation(provider);
		return this;
	}

	@Override
	public void toProvider(Provider<T> provider) {
		mBinding.setProvider(checkNotNull(provider, "provider"));
		mBinding.setScope(ApplicationScoped.class);
		validateAnnotation(provider.getClass());
	}

	@Override
	public void in(Class<? extends Annotation> scope) {
		mBinding.setScope(checkNotNull(scope, "scope"));
	}

	private void setScope(Class<?> clazz) {
		Annotation ann;
		if ((ann = clazz.getAnnotation(ApplicationScoped.class)) != null
				|| (ann = clazz.getAnnotation(Dependent.class)) != null
				|| (ann = clazz.getAnnotation(ContextScoped.class)) != null)
			mBinding.setScope(ann.annotationType());
	}

	private void validateAnnotation(Class<?> clazz) {
		AndroidVersion version = clazz.getAnnotation(AndroidVersion.class);
		if (version != null && Build.VERSION.SDK_INT < version.value())
			mBindings.unregister(mBinding);

		DeviceModel model = clazz.getAnnotation(DeviceModel.class);
		if (model != null && !Build.MODEL.equals(model.value()))
			mBindings.unregister(mBinding);
	}

	private <I> I checkNotNull(I obj, String msg) {
		if (obj == null)
			throw new ConfigurationException(msg);
		return obj;
	}
}

@@ -1541,24 +1541,15 @@
 tion
+%5B%5D
  ann
-;%0A%09%09if ((ann
+s
  = c
@@ -1570,168 +1570,173 @@
 tion
-(ApplicationScoped.class)) != null%0A%09%09%09%09%7C%7C (ann = clazz.getAnnotation(Dependent.class)) != null%0A%09%09%09%09%7C%7C (ann = clazz.getAnnotation(ContextScoped.class)) != null)%0A
+s();%0A%09%09for (Annotation ann : anns) %7B%0A%09%09%09if (ApplicationScoped.class.isInstance(ann) %7C%7C Dependent.class.isInstance(ann)%0A%09%09%09%09%09%7C%7C ContextScoped.class.isInstance(ann))%0A%09
 %09%09%09m
@@ -1771,24 +1771,28 @@
 ionType());%0A
+%09%09%7D%0A
 %09%7D%0A%0A%09private

Improve binding builder