// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/domains/Graph.java
// 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;
// 	}
// 
// }
// 
// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/domains/Module.java
// 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);
// 		}
// 
// 	}
// 
// }
// 
// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/ModuleAdapterSpec.java
// static TypeSpec getModuleAdapterSpec(Module module, String adapterName) {
// 	List<MethodSpec> methods = getMethods(module.canonicalModuleName, module.provides);
// 	return TypeSpec
// 		.classBuilder(adapterName)
// 		.addModifiers(PUBLIC, FINAL)
// 		.addMethods(methods)
// 		.build();
// }
// 
// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/ModuleMapperSpec.java
// 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)
// 		.addField(ParameterizedTypeName.get(Map.class, Class.class, Integer.class), "keys", PRIVATE, FINAL)
// 		.addFields(getModuleFields(modules, graph))
// 		.addMethod(getConstructor(modules, graph))
// 		.addMethod(getFromModuleMethod(moduleMapperName, modules, graph))
// 		.addMethod(getKeysInitializerMethod(depMapper))
// 		.addMethod(getBinderMethod(modules, graph, depMapper))
// 		.build();
// }


import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import com.wokdsem.kinject.codegen.domains.Graph;
import com.wokdsem.kinject.codegen.domains.Module;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import javax.annotation.Generated;
import javax.annotation.processing.Filer;
import static com.wokdsem.kinject.codegen.ModuleAdapterSpec.getModuleAdapterSpec;
import static com.wokdsem.kinject.codegen.ModuleMapperSpec.getModuleMapperSpec;

	private static void generateModuleAdapters(Collection<Module> modules, Filer filer) throws ProcessorException {
		for (Module module : modules) {
			String adapterName = MapperNames.getSimpleAdapterModuleName(module.canonicalModuleName);
			TypeSpec adapterClass = getModuleAdapterSpec(module, adapterName);
			writeClassFile(getPackageName(module.canonicalModuleName), adapterClass, filer);
		}
	}

	private static void generateModuleMappers(Map<String, Module> modules, Collection<Graph> graphs,
											  Filer filer) throws ProcessorException {
		for (Graph graph : graphs) {
			Module mainModule = modules.get(graph.canonicalModuleName);
			String moduleMapperName = MapperNames.getSimpleMapperModuleName(mainModule.canonicalModuleName);
			TypeSpec moduleMapperClass = getModuleMapperSpec(modules, graph, moduleMapperName);
			writeClassFile(getPackageName(mainModule.canonicalModuleName), moduleMapperClass, filer);
		}
	}

	private static String getPackageName(String baseName) {
		return baseName.substring(0, baseName.lastIndexOf("."));
	}

	private static void writeClassFile(String packageName, TypeSpec classSpec, Filer filer) throws ProcessorException {
		try {
			AnnotationSpec generatedAnnotation = AnnotationSpec.builder(Generated.class)
				.addMember("value", "$S", CODE_GEN)
				.build();
			classSpec = classSpec.toBuilder()
				.addAnnotation(generatedAnnotation)
// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/domains/Graph.java
// 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;
// 	}
// 
// }
// 
// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/domains/Module.java
// 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);
// 		}
// 
// 	}
// 
// }
// 
// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/ModuleAdapterSpec.java
// static TypeSpec getModuleAdapterSpec(Module module, String adapterName) {
// 	List<MethodSpec> methods = getMethods(module.canonicalModuleName, module.provides);
// 	return TypeSpec
// 		.classBuilder(adapterName)
// 		.addModifiers(PUBLIC, FINAL)
// 		.addMethods(methods)
// 		.build();
// }
// 
// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/ModuleMapperSpec.java
// 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)
// 		.addField(ParameterizedTypeName.get(Map.class, Class.class, Integer.class), "keys", PRIVATE, FINAL)
// 		.addFields(getModuleFields(modules, graph))
// 		.addMethod(getConstructor(modules, graph))
// 		.addMethod(getFromModuleMethod(moduleMapperName, modules, graph))
// 		.addMethod(getKeysInitializerMethod(depMapper))
// 		.addMethod(getBinderMethod(modules, graph, depMapper))
// 		.build();
// }


// Path: compiler/src/main/java/com/wokdsem/kinject/codegen/CodeGen.java
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import com.wokdsem.kinject.codegen.domains.Graph;
import com.wokdsem.kinject.codegen.domains.Module;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import javax.annotation.Generated;
import javax.annotation.processing.Filer;
import static com.wokdsem.kinject.codegen.ModuleAdapterSpec.getModuleAdapterSpec;
import static com.wokdsem.kinject.codegen.ModuleMapperSpec.getModuleMapperSpec;


	private static void generateModuleAdapters(Collection<Module> modules, Filer filer) throws ProcessorException {
		for (Module module : modules) {
			String adapterName = MapperNames.getSimpleAdapterModuleName(module.canonicalModuleName);
			TypeSpec adapterClass = getModuleAdapterSpec(module, adapterName);
			writeClassFile(getPackageName(module.canonicalModuleName), adapterClass, filer);
		}
	}

	private static void generateModuleMappers(Map<String, Module> modules, Collection<Graph> graphs,
											  Filer filer) throws ProcessorException {
		for (Graph graph : graphs) {
			Module mainModule = modules.get(graph.canonicalModuleName);
			String moduleMapperName = MapperNames.getSimpleMapperModuleName(mainModule.canonicalModuleName);
			TypeSpec moduleMapperClass = getModuleMapperSpec(modules, graph, moduleMapperName);
			writeClassFile(getPackageName(mainModule.canonicalModuleName), moduleMapperClass, filer);
		}
	}

	private static String getPackageName(String baseName) {
		return baseName.substring(0, baseName.lastIndexOf("."));
	}

	private static void writeClassFile(String packageName, TypeSpec classSpec, Filer filer) throws ProcessorException {
		try {
			AnnotationSpec generatedAnnotation = AnnotationSpec.builder(Generated.class)
				.addMember("value", "$S", CODE_GEN)
				.build();
			classSpec = classSpec.toBuilder()
				.addAnnotation(generatedAnnotation)
				.build();