/*
 * Copyright 2008 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.dev.javac;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.asm.ClassReader;
import com.google.gwt.dev.asm.Opcodes;
import com.google.gwt.dev.asm.commons.EmptyVisitor;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.util.DiskCache;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.collect.HashMap;

import org.eclipse.jdt.core.compiler.CategorizedProblem;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * Encapsulates the state of a single active compilation unit in a particular
 * module. State is accumulated throughout the life cycle of the containing
 * module and may be invalidated at certain times and recomputed.
 */
public abstract class CompilationUnit implements Serializable {

  /**
   * Encapsulates the functionality to find all nested classes of this class
   * that have compiler-generated names. All class bytes are loaded from the
   * disk and then analyzed using ASM.
   */
  static class GeneratedClassnameFinder {
    private static class AnonymousClassVisitor extends EmptyVisitor {
      /*
       * array of classNames of inner clases that aren't synthetic classes.
       */
      List<String> classNames = new ArrayList<String>();

      int expectCode;
      int sawCode;

      public List<String> getInnerClassNames() {
        return classNames;
      }

      /**
       * Return whether or not the class file visited was well-formed.
       * Currently, this only checks that all non-abstract, non-native methods
       * have a Code attribute.
       */
      public boolean isWellFormed() {
        return expectCode == sawCode;
      }

      @Override
      public void visitInnerClass(String name, String outerName, String innerName, int access) {
        if ((access & Opcodes.ACC_SYNTHETIC) == 0) {
          classNames.add(name);
        }
      }

      @Override
      public AnonymousClassVisitor visitMethod(int access, String name, String desc, String signature,
          String[] exceptions) {
        if ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) == 0) {
          ++expectCode;
        }
        return this;
      }

      @Override
      public void visitCode() {
        ++sawCode;
      }
    }

    private final List<String> classesToScan;
    private final TreeLogger logger;
    private final String mainClass;
    private String mainUrlBase = null;

    GeneratedClassnameFinder(TreeLogger logger, String mainClass) {
      assert mainClass != null;
      this.mainClass = mainClass;
      classesToScan = new ArrayList<String>();
      classesToScan.add(mainClass);
      this.logger = logger;
    }

    List<String> getClassNames() {
      // using a list because presumably there will not be many generated
      // classes
      List<String> allGeneratedClasses = new ArrayList<String>();
      for (int i = 0; i < classesToScan.size(); i++) {
        String lookupName = classesToScan.get(i);
        byte classBytes[] = getClassBytes(lookupName);
        if (classBytes == null) {
          /*
           * Weird case: javac might generate a name and reference the class in
           * the bytecode but decide later that the class is unnecessary. In the
           * bytecode, a null is passed for the class.
           */
          continue;
        }

        AnonymousClassVisitor cv = new AnonymousClassVisitor();
        new ClassReader(classBytes).accept(cv, 0);
        if (!cv.isWellFormed()) {
          /*
           * Weird case #2: As of OpenJDK 7, javac in the above case now does
           * generate a class file, but an incomplete one that fails to load
           * with a ClassFormatError "Absent Code attribute in method that
           * is not native or abstract in class file" error.
           */
          continue;
        }

        /*
         * Add the class to the list only if it can be loaded to get around the
         * javac weirdness issue where javac refers a class but does not
         * generate it.
         */
        if (isClassnameGenerated(lookupName) && !allGeneratedClasses.contains(lookupName)) {
          allGeneratedClasses.add(lookupName);
        }
        List<String> innerClasses = cv.getInnerClassNames();
        for (String innerClass : innerClasses) {
          // The innerClass has to be an inner class of the lookupName
          if (!innerClass.startsWith(mainClass + "$")) {
            continue;
          }
          /*
           * TODO (amitmanjhi): consider making this a Set if necessary for
           * performance
           */
          // add the class to classes
          if (!classesToScan.contains(innerClass)) {
            classesToScan.add(innerClass);
          }
        }
      }
      Collections.sort(allGeneratedClasses, new GeneratedClassnameComparator());
      return allGeneratedClasses;
    }

    /*
     * Load classBytes from disk. Check if the classBytes are loaded from the
     * same location as the location of the mainClass.
     */
    private byte[] getClassBytes(String slashedName) {
      URL url = Thread.currentThread().getContextClassLoader().getResource(slashedName + ".class");
      if (url == null) {
        if (logger.isLoggable(TreeLogger.DEBUG)) {
          logger.log(TreeLogger.DEBUG, "Unable to find " + slashedName + " on the classPath");
        }
        return null;
      }
      String urlStr = url.toExternalForm();
      if (slashedName.equals(mainClass)) {
        // initialize the mainUrlBase for later use.
        mainUrlBase = urlStr.substring(0, urlStr.lastIndexOf('/'));
      } else {
        assert mainUrlBase != null;
        if (!mainUrlBase.equals(urlStr.substring(0, urlStr.lastIndexOf('/')))) {
          if (logger.isLoggable(TreeLogger.DEBUG)) {
            logger.log(TreeLogger.DEBUG, "Found " + slashedName + " at " + urlStr
                + " The base location is different from  that of " + mainUrlBase + " Not loading");
          }
          return null;
        }
      }

      // url != null, we found it on the class path.
      try {
        URLConnection conn = url.openConnection();
        return Util.readURLConnectionAsBytes(conn);
      } catch (IOException ignored) {
        if (logger.isLoggable(TreeLogger.DEBUG)) {
          logger.log(TreeLogger.DEBUG, "Unable to load " + urlStr + ", in trying to load "
              + slashedName);
        }
        // Fall through.
      }
      return null;
    }
  }

  protected static final DiskCache diskCache = DiskCache.INSTANCE;

  public static final Comparator<CompilationUnit> COMPARATOR = new Comparator<CompilationUnit>() {
    @Override
    public int compare(CompilationUnit o1, CompilationUnit o2) {
      return o1.getResourcePath().compareTo(o2.getResourcePath());
    }
  };

  private static final Pattern GENERATED_CLASSNAME_PATTERN = Pattern.compile(".+\\$\\d.*");

  /**
   * Checks if the class names is generated. Accepts any classes whose names
   * match .+$\d.* (handling named classes within anonymous classes and multiple
   * named classes of the same name in a class, but in different methods).
   * Checks if the class or any of its enclosing classes are anonymous or
   * synthetic.
   * <p>
   * If new compilers have different conventions for anonymous and synthetic
   * classes, this code needs to be updated.
   * </p>
   * 
   * @param className name of the class to be checked.
   * @return true iff class or any of its enclosing classes are anonymous or
   *         synthetic.
   */
  @Deprecated
  public static boolean isClassnameGenerated(String className) {
    return GENERATED_CLASSNAME_PATTERN.matcher(className).matches();
  }

  /**
   * Map from the className in javac to the className in jdt. String represents
   * the part of className after the compilation unit name. Emma-specific.
   */
  private transient Map<String, String> anonymousClassMap = null;

  /**
   * Returns the unit as an instance of {@link CachedCompilationUnit}, making a
   * copy if necessary.
   */
  public abstract CachedCompilationUnit asCachedCompilationUnit();

  @Deprecated
  public final boolean constructAnonymousClassMappings(TreeLogger logger) {
    /*
     * Check if the unit has one or more classes with generated names. 'javac'
     * below refers to the compiler that was used to compile the java files on
     * disk. Returns true if our heuristic for constructing the anonymous class
     * mappings worked.
     */
    anonymousClassMap = new HashMap<String, String>();
    for (String topLevelClass : getTopLevelClasses()) {
      // Generate a mapping for each top-level class separately
      List<String> javacClasses =
          new GeneratedClassnameFinder(logger, topLevelClass).getClassNames();
      List<String> jdtClasses = getJdtClassNames(topLevelClass);
      if (javacClasses.size() != jdtClasses.size()) {
        anonymousClassMap = Collections.emptyMap();
        return false;
      }
      int size = javacClasses.size();
      for (int i = 0; i < size; i++) {
        if (!javacClasses.get(i).equals(jdtClasses.get(i))) {
          anonymousClassMap.put(javacClasses.get(i), jdtClasses.get(i));
        }
      }
    }
    return true;
  }

  @Deprecated
  public final boolean createdClassMapping() {
    return anonymousClassMap != null;
  }

  /**
   * Overridden to finalize; always returns object identity.
   */
  @Override
  public final boolean equals(Object obj) {
    return super.equals(obj);
  }

  @Deprecated
  public final Map<String, String> getAnonymousClassMap() {
    /*
     * Return an empty map so that class-rewriter does not need to check for
     * null. A null value indicates that anonymousClassMap was never created
     * which is the case for many units. An example is a class containing jsni
     * units but no inner classes.
     */
    if (anonymousClassMap == null) {
      return Collections.emptyMap();
    }
    return anonymousClassMap;
  }

  /**
   * Returns all contained classes.
   */
  public abstract Collection<CompiledClass> getCompiledClasses();

  public abstract List<JsniMethod> getJsniMethods();

  /**
   * Returns the last modified time of the compilation unit.
   */
  public abstract long getLastModified();

  /**
   * @return a way to lookup method argument names for this compilation unit.
   */
  public abstract MethodArgNamesLookup getMethodArgs();

  /**
   * This is the resource location from the classpath or some deterministic
   * virtual location (in the case of generators or mock data) where the source
   * for this unit originated. This should be unique for each unit compiled to
   * create a module.
   * 
   * @see com.google.gwt.dev.resource.Resource#getLocation()
   */
  public abstract String getResourceLocation();

  /**
   * Returns the full abstract path of the resource. If a resource has been
   * re-rooted, this path should include any path prefix that was stripped.
   * 
   * @see com.google.gwt.dev.resource.Resource#getPath() 
   * @see com.google.gwt.dev.resource.Resource#getPathPrefix()
   */
  public abstract String getResourcePath();

  /**
   * Returns the fully-qualified name of the top level public type.
   */
  public abstract String getTypeName();

  /**
   * Returns the GWT AST types in this unit.
   */
  public List<JDeclaredType> getTypes() {
    try {
      byte[] bytes = getTypesSerialized();
      ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
      return JProgram.deserializeTypes(ois);
    } catch (IOException e) {
      throw new RuntimeException("Unexpected IOException on in-memory stream", e);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException("Unexpected error deserializing AST for '" + getTypeName() + "'",
          e);
    }
  }

  /**
   * Returns the GWT AST types in this unit in serialized form.
   */
  public abstract byte[] getTypesSerialized();

  @Deprecated
  public final boolean hasAnonymousClasses() {
    for (CompiledClass cc : getCompiledClasses()) {
      if (isAnonymousClass(cc)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Overridden to finalize; always returns identity hash code.
   */
  @Override
  public final int hashCode() {
    return super.hashCode();
  }

  /**
   * Returns <code>true</code> if this unit had errors.
   */
  public abstract boolean isError();

  /**
   * Returns <code>true</code> if this unit was generated by a
   * {@link com.google.gwt.core.ext.Generator}.
   */
  @Deprecated
  public abstract boolean isGenerated();

  /**
   * 
   * @return true if the Compilation Unit is from a super-source.
   */
  @Deprecated
  public abstract boolean isSuperSource();

  /**
   * Overridden to finalize; always returns {@link #getResourceLocation()}.
   */
  @Override
  public final String toString() {
    return getResourceLocation();
  }

  /**
   * The canonical serialized form of a CompilatinUnit is
   * {@link CachedCompilationUnit}.
   */
  protected final Object writeReplace() {
    return asCachedCompilationUnit();
  }

  /**
   * Returns the content ID for the source with which this unit was compiled.
   */
  abstract ContentId getContentId();

  /**
   * The set of dependencies on other classes.
   */
  abstract Dependencies getDependencies();

  abstract CategorizedProblem[] getProblems();

  private List<String> getJdtClassNames(String topLevelClass) {
    List<String> classNames = new ArrayList<String>();
    for (CompiledClass cc : getCompiledClasses()) {
      if (isAnonymousClass(cc) && cc.getInternalName().startsWith(topLevelClass + "$")) {
        classNames.add(cc.getInternalName());
      }
    }
    Collections.sort(classNames, new GeneratedClassnameComparator());
    return classNames;
  }

  private List<String> getTopLevelClasses() {
    List<String> topLevelClasses = new ArrayList<String>();
    for (CompiledClass cc : getCompiledClasses()) {
      if (cc.getEnclosingClass() == null) {
        topLevelClasses.add(cc.getInternalName());
      }
    }
    return topLevelClasses;
  }

  /**
   * TODO(amitmanjhi): what is the difference between an anonymous and local
   * class for our purposes? All our unit tests pass whether or not we do the
   * additional {@link #isClassnameGenerated} check. We either need to find the
   * real difference and add a unit test, or else simply this.
   */
  private boolean isAnonymousClass(CompiledClass cc) {
    return cc.isLocal() && isClassnameGenerated(cc.getInternalName());
  }
}
