package org.gradle.incap.m1;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import org.gradle.incap.Annotation1;
import org.gradle.incap.BaseIncrementalAnnotationProcessor;

import static javax.lang.model.SourceVersion.latestSupported;
import static org.gradle.incap.util.APUtil.generateFiles;
import static org.gradle.incap.util.APUtil.getEnclosingClassName;

/**
 * This AP creates 1 target file for 1 source file.
 * This case should be easy to handle as we actually don't need incap at all,
 * the processor is already incremental and the filer will provide the build
 * system information about generated files that should be deleted when their
 * corresponding input file is deleted.
 */
public class M1_OneToOneAP extends BaseIncrementalAnnotationProcessor {

  private boolean isProcessingDone;

  @Override
  public Set<String> getSupportedAnnotationTypes() {
    Set<String> set = new HashSet<>();
    set.add(Annotation1.class.getName());
    return set;
  }

  @Override
  public SourceVersion getSupportedSourceVersion() {
    return latestSupported();
  }

  @Override
  public boolean incrementalProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    for (TypeElement annotation : annotations) {
      System.out.println("Processing annotation:" + annotation);
    }

    if (isProcessingDone) {
      return false;
    }

    // generates a class with a constant that contains the name of all classes containing an annotation.
    Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(Annotation1.class);
    Map<String, Set<? extends Element>> mapGeneratedFileNameToOriginatingElements = processElements(annotatedElements);
    generateFiles(incrementalProcessingEnvironment.getFiler(), mapGeneratedFileNameToOriginatingElements);
    isProcessingDone = true;
    return false;
  }

  private Map<String, Set<? extends Element>> processElements(Set<? extends Element> annotatedElements) {
    final Map<String, Set<? extends Element>> mapGeneratedFileNameToOrginatingElements = new HashMap<>();
    for (Element annotatedElement : annotatedElements) {
      String nameOfClassContainingElement = getEnclosingClassName(annotatedElement);
      final String finalClassName = getClass().getSimpleName() + "_" + nameOfClassContainingElement + "Gen0";
      mapGeneratedFileNameToOrginatingElements.put(finalClassName, Collections.singleton(annotatedElement));
    }
    return mapGeneratedFileNameToOrginatingElements;
  }
}