package com.yatatsu.autobundle.processor;


import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.util.List;

import javax.annotation.processing.Filer;
import javax.lang.model.element.Modifier;

public class AutoBundleBinderWriter {

  private final List<AutoBundleBindingClass> bindingClasses;
  private static final String TARGET_CLASS_NAME = "AutoBundleBindingDispatcher";
  private static final String TARGET_PACKAGE_NAME = "com.yatatsu.autobundle";
  private static final ClassName CLASS_BUNDLE = ClassName.get("android.os", "Bundle");
  private static final ClassName CLASS_INTENT = ClassName.get("android.content", "Intent");

  public AutoBundleBinderWriter(List<AutoBundleBindingClass> bindingClasses) {
    this.bindingClasses = bindingClasses;
  }

  public void write(Filer filer) throws IOException {
    TypeSpec clazz = TypeSpec.classBuilder(TARGET_CLASS_NAME)
        .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
        .addMethod(createBindWithArgsMethod(bindingClasses))
        .addMethod(createBindWithIntentMethod(bindingClasses))
        .addMethod(createBindFragmentMethod(bindingClasses))
        .addMethod(createPackMethod(bindingClasses))
        .build();
    JavaFile.builder(TARGET_PACKAGE_NAME, clazz)
        .build()
        .writeTo(filer);
  }

  private static MethodSpec createBindWithArgsMethod(List<AutoBundleBindingClass> classes) {
    MethodSpec.Builder builder = MethodSpec.methodBuilder("bind")
        .addModifiers(Modifier.PUBLIC)
        .addParameter(Object.class, "target")
        .addParameter(CLASS_BUNDLE, "args")
        .returns(void.class);

    builder.addStatement("final String className = target.getClass().getCanonicalName()");
    for (AutoBundleBindingClass bindingClass : classes) {
      TypeName type = bindingClass.getTargetType();
      ClassName bindClassType =
          ClassName.get(bindingClass.getPackageName(), bindingClass.getHelperClassName());
      builder.beginControlFlow("if (className.equals($T.class.getName()))", type)
          .addStatement("$T.bind(($T)target, args)", bindClassType, type)
          .addStatement("return")
          .endControlFlow();
    }
    return builder.build();
  }

  private static MethodSpec createBindWithIntentMethod(List<AutoBundleBindingClass> classes) {
    MethodSpec.Builder builder = MethodSpec.methodBuilder("bind")
        .addModifiers(Modifier.PUBLIC)
        .addParameter(Object.class, "target")
        .addParameter(CLASS_INTENT, "intent")
        .returns(void.class);

    builder.addStatement("final String className = target.getClass().getCanonicalName()");
    for (AutoBundleBindingClass bindingClass : classes) {
      if (bindingClass.getBuilderType() != AutoBundleBindingClass.BuilderType.Intent) {
        continue;
      }
      TypeName type = bindingClass.getTargetType();
      ClassName bindClassType =
          ClassName.get(bindingClass.getPackageName(), bindingClass.getHelperClassName());
      builder.beginControlFlow("if (className.equals($T.class.getName()))", type)
          .addStatement("$T.bind(($T)target, intent)", bindClassType, type)
          .addStatement("return")
          .endControlFlow();
    }
    return builder.build();
  }

  private static MethodSpec createBindFragmentMethod(List<AutoBundleBindingClass> classes) {
    MethodSpec.Builder builder = MethodSpec.methodBuilder("bind")
        .addModifiers(Modifier.PUBLIC)
        .addParameter(Object.class, "target")
        .returns(void.class);

    builder.addStatement("final String className = target.getClass().getCanonicalName()");
    for (AutoBundleBindingClass bindingClass : classes) {
      if (bindingClass.getBuilderType() != AutoBundleBindingClass.BuilderType.Fragment) {
        continue;
      }
      TypeName type = bindingClass.getTargetType();
      ClassName bindClassType =
          ClassName.get(bindingClass.getPackageName(), bindingClass.getHelperClassName());
      builder.beginControlFlow("if (className.equals($T.class.getName()))", type)
          .addStatement("$T.bind(($T)target)", bindClassType, type)
          .addStatement("return")
          .endControlFlow();
    }
    return builder.build();
  }

  private static MethodSpec createPackMethod(List<AutoBundleBindingClass> classes) {
    MethodSpec.Builder builder = MethodSpec.methodBuilder("pack")
        .addModifiers(Modifier.PUBLIC)
        .addParameter(Object.class, "target")
        .addParameter(CLASS_BUNDLE, "args")
        .returns(void.class);

    builder.addStatement("final String className = target.getClass().getCanonicalName()");
    for (AutoBundleBindingClass bindingClass : classes) {
      TypeName type = bindingClass.getTargetType();
      ClassName bindClassType =
          ClassName.get(bindingClass.getPackageName(), bindingClass.getHelperClassName());
      builder.beginControlFlow("if (className.equals($T.class.getName()))", type)
          .addStatement("$T.pack(($T)target, args)", bindClassType, type)
          .addStatement("return")
          .endControlFlow();
    }
    return builder.build();
  }
}
@@ -1784,99 +1784,8 @@
 );%0A%0A
-    builder.addStatement(%22final String className = target.getClass().getCanonicalName()%22);%0A
     
@@ -1830,32 +1830,32 @@
 ss : classes) %7B%0A
+
       TypeName t
@@ -2053,44 +2053,28 @@
 if (
-className.equals($T.class.getName())
+target instanceof $T
 )%22, 
@@ -2582,99 +2582,8 @@
 );%0A%0A
-    builder.addStatement(%22final String className = target.getClass().getCanonicalName()%22);%0A
     
@@ -2965,44 +2965,28 @@
 if (
-className.equals($T.class.getName())
+target instanceof $T
 )%22, 
@@ -3448,99 +3448,8 @@
 );%0A%0A
-    builder.addStatement(%22final String className = target.getClass().getCanonicalName()%22);%0A
     
@@ -3833,44 +3833,28 @@
 if (
-className.equals($T.class.getName())
+target instanceof $T
 )%22, 
@@ -4344,99 +4344,8 @@
 );%0A%0A
-    builder.addStatement(%22final String className = target.getClass().getCanonicalName()%22);%0A
     
@@ -4613,44 +4613,28 @@
 if (
-className.equals($T.class.getName())
+target instanceof $T
 )%22, 

Replace name comparison to instanceof operator