package org.gradle.test;

import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ModuleNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.control.messages.SimpleMessage;
import org.codehaus.groovy.transform.ASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;

import java.util.List;

/**
 * Searches through all classes to be compiled for a field named
 * "groovycVersion". If such a field is found, a field initializer is added
 * and the search ends. The initializer sets the field to a String containing
 * the groovyc version detected (currently "1.6"). Any existing initializer
 * is overriden. If the field's type is not compatible with String, a compile-
 * time or runtime error will occur.
 * Because transforms have only been introduced in Groovy 1.6, this transform
 * will have no effect on classes compiled with earlier Groovy versions.
 */
@SuppressWarnings("unchecked")
@GroovyASTTransformation(phase = CompilePhase.CONVERSION)
public class DetectorTransform implements ASTTransformation {
  private static final String VERSION_FIELD_NAME = "groovycVersion";

  public void visit(ASTNode[] nodes, SourceUnit source) {
    if (nodes.length == 0 || !(nodes[0] instanceof ModuleNode)) {
      source.getErrorCollector().addError(new SimpleMessage(
        "internal error in DetectorTransform", source));
      return;
    }
    ModuleNode module = (ModuleNode)nodes[0];
    for (ClassNode clazz : (List<ClassNode>)module.getClasses()) {
      FieldNode field = clazz.getField(VERSION_FIELD_NAME);
      if (field != null) {
        field.setInitialValueExpression(new ConstantExpression("1.6"));
        break;
      }
    }
  }
}