public class Graph {

	public final String canonicalModuleName;
	public final Collection<Include> includes;
	public final Collection<Provide> provides;

	public Graph(String canonicalModuleName, Collection<Include> includes, Collection<Provide> provides) {
		this.canonicalModuleName = canonicalModuleName;
		this.includes = includes;
		this.provides = provides;
	}

} public class Include {

	public final String canonicalModuleName;
	public final Reference reference;

	public Include(String canonicalModuleName, Reference reference) {
		this.canonicalModuleName = canonicalModuleName;
		this.reference = reference;
	}

} public class Module {

	public final String canonicalModuleName;
	public final List<Provide> provides;
	public final List<Include> includes;
	public final boolean isCompleted;

	private Module(ModuleBuilder builder) {
		this.canonicalModuleName = builder.canonicalModuleName;
		this.provides = builder.provides;
		this.includes = builder.includes;
		this.isCompleted = builder.isCompleted;
	}

	public static class ModuleBuilder {

		private final String canonicalModuleName;
		private final List<Provide> provides;
		private final List<Include> includes;
		private boolean isCompleted;

		public ModuleBuilder(String canonicalModuleName) {
			this.canonicalModuleName = canonicalModuleName;
			this.provides = new LinkedList<>();
			this.includes = new LinkedList<>();
		}

		public ModuleBuilder setProvides(Collection<Provide> provides) {
			this.provides.clear();
			this.provides.addAll(provides);
			return this;
		}

		public ModuleBuilder setIncludes(Collection<Include> includes) {
			this.includes.clear();
			this.includes.addAll(includes);
			return this;
		}

		public ModuleBuilder setIsCompleted(boolean isCompleted) {
			this.isCompleted = isCompleted;
			return this;
		}

		public Module build() {
			return new Module(this);
		}

	}

} public class Provide {
	
	public final String canonicalProvideClassName;
	public final String named;
	public final Reference reference;
	public final List<Dependency> dependencies;
	public final Provides.Scope scope;
	
	private Provide(ProvideBuilder builder) {
		this.canonicalProvideClassName = builder.canonicalProvideClassName;
		this.named = builder.named;
		this.reference = builder.reference;
		this.dependencies = builder.dependencies;
		this.scope = builder.scope;
	}
	
	@Override
	public boolean equals(Object o) {
		if (o instanceof Provide) {
			Provide otherProvide = (Provide) o;
			boolean equalNamed = named.equals(otherProvide.named);
			return equalNamed && canonicalProvideClassName.equals(otherProvide.canonicalProvideClassName);
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		int result = canonicalProvideClassName.hashCode();
		result = 31 * result + named.hashCode();
		return result;
	}
	
	public static class ProvideBuilder {
		
		private final String canonicalProvideClassName;
		private final String named;
		private final Reference reference;
		private final List<Dependency> dependencies;
		private Provides.Scope scope;
		
		public ProvideBuilder(String canonicalProvideClassName, String named, Reference reference) {
			this.canonicalProvideClassName = canonicalProvideClassName;
			this.named = named;
			this.reference = reference;
			this.dependencies = new LinkedList<>();
		}
		
		public ProvideBuilder setDependencies(Collection<Dependency> dependencies) {
			this.dependencies.clear();
			this.dependencies.addAll(dependencies);
			return this;
		}
		
		public ProvideBuilder setScope(Provides.Scope scope) {
			this.scope = scope;
			return this;
		}
		
		public Provide build() {
			return new Provide(this);
		}
		
	}
	
} public class Reference {

	public final String canonicalModuleName;
	public final String method;

	public Reference(String canonicalModuleName, String method) {
		this.canonicalModuleName = canonicalModuleName;
		this.method = method;
	}

} public interface Injector {

	<T> T inject(Class<T> tClass, String named);

} public interface ModuleMapper {

	Binder buildBinder(Class tClass, String named, Injector injector);

} public interface Binder<T> {

	T bind();

} static String getBindMethodName(String className, String named) {
	return String.format(PROVIDE_ADAPTER, adaptClassName(className), capitalize(named));
} static String getCanonicalAdapterModuleName(String className) {
	return String.format(MODULE_ADAPTER, className);
} static String getFieldName(String className) {
	return unCapitalize(adaptClassName(className));
}
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import com.wokdsem.kinject.codegen.domains.Graph;
import com.wokdsem.kinject.codegen.domains.Include;
import com.wokdsem.kinject.codegen.domains.Module;
import com.wokdsem.kinject.codegen.domains.Provide;
import com.wokdsem.kinject.codegen.domains.Reference;
import com.wokdsem.kinject.core.Injector;
import com.wokdsem.kinject.core.ModuleMapper;
import com.wokdsem.kinject.core.binder.Binder;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import static com.wokdsem.kinject.codegen.MapperNames.getBindMethodName;
import static com.wokdsem.kinject.codegen.MapperNames.getCanonicalAdapterModuleName;
import static com.wokdsem.kinject.codegen.MapperNames.getFieldName;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
package com.wokdsem.kinject.codegen;




class ModuleMapperSpec {

	static TypeSpec getModuleMapperSpec(Map<String, Module> modules, Graph graph, String moduleMapperName) {
		Map<String, Integer> depMapper = getDepMapper(graph);
		return TypeSpec.classBuilder(moduleMapperName)
			.addModifiers(PUBLIC, FINAL)
			.addSuperinterface(ModuleMapper.class)