/*
 * 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.tools.apichecker;

import com.google.gwt.core.ext.typeinfo.NotFoundException;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Produces the diff between the API of two apiClasses.
 */
final class ApiClassDiffGenerator implements Comparable<ApiClassDiffGenerator> {

  static final Collection<ApiChange> EMPTY_COLLECTION = new ArrayList<ApiChange>(
      0);

  static String printSetWithHashCode(Set<?> set, String identifier) {
    StringBuffer sb = new StringBuffer();
    sb.append(identifier + ", size = " + set.size());
    for (Object element : set) {
      sb.append(element + ", hashcode = " + element.hashCode());
    }
    sb.append("\n");
    return sb.toString();
  }

  private final ApiDiffGenerator apiDiffGenerator;
  private final String className;
  private HashMap<ApiField, Set<ApiChange>> intersectingFields = null;

  /**
   * Map from methods and constructors in intersection to a string describing
   * how they have changed. The description could be the addition/removal of a
   * static/abstract/final keyword.
   */
  private EnumMap<ApiClass.MethodType, Map<ApiAbstractMethod, Set<ApiChange>>> intersectingMethods;
  private Set<ApiField> missingFields = null;
  /**
   * list of missing constructors and methods.
   */
  private EnumMap<ApiClass.MethodType, Set<ApiAbstractMethod>> missingMethods;
  private final ApiClass newClass;

  private final ApiClass oldClass;

  ApiClassDiffGenerator(String className,
      ApiPackageDiffGenerator apiPackageDiffGenerator) throws NotFoundException {
    this.className = className;
    apiDiffGenerator = apiPackageDiffGenerator.getApiDiffGenerator();
    this.newClass = apiPackageDiffGenerator.getNewApiPackage().getApiClass(
        className);
    this.oldClass = apiPackageDiffGenerator.getOldApiPackage().getApiClass(
        className);
    if (newClass == null || oldClass == null) {
      throw new NotFoundException("for class " + className
          + ", one of the class objects is null");
    }

    intersectingFields = new HashMap<ApiField, Set<ApiChange>>();
    intersectingMethods = new EnumMap<ApiClass.MethodType, Map<ApiAbstractMethod, Set<ApiChange>>>(
        ApiClass.MethodType.class);
    missingMethods = new EnumMap<ApiClass.MethodType, Set<ApiAbstractMethod>>(
        ApiClass.MethodType.class);
    for (ApiClass.MethodType methodType : ApiClass.MethodType.values()) {
      intersectingMethods.put(methodType,
          new HashMap<ApiAbstractMethod, Set<ApiChange>>());
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.lang.Comparable#compareTo(java.lang.Object)
   */
  public int compareTo(ApiClassDiffGenerator other) {
    return getName().compareTo(other.getName());
  }

  // TODO(amitmanjhi): handle methods with variable length arguments
  void computeApiDiff() {
    Set<String> newFieldNames = newClass.getApiFieldNames();
    Set<String> oldFieldNames = oldClass.getApiFieldNames();
    Set<String> intersection = ApiDiffGenerator.removeIntersection(
        newFieldNames, oldFieldNames);
    missingFields = oldClass.getApiFieldsBySet(oldFieldNames);
    processFieldsInIntersection(intersection);

    for (ApiClass.MethodType methodType : ApiClass.MethodType.values()) {
      Set<String> newMethodNames = newClass.getApiMemberNames(methodType);
      Set<String> oldMethodNames = oldClass.getApiMemberNames(methodType);
      intersection = ApiDiffGenerator.removeIntersection(newMethodNames,
          oldMethodNames);
      missingMethods.put(methodType, oldClass.getApiMembersBySet(
          oldMethodNames, methodType));
      processElementsInIntersection(intersection, methodType);
    }
  }

  Collection<ApiChange> getApiDiff() {
    Collection<ApiChange.Status> apiStatusChanges = oldClass.getModifierChanges(newClass);
    Collection<ApiChange> apiChangeCollection = new ArrayList<ApiChange>();
    for (ApiChange.Status apiStatus : apiStatusChanges) {
      apiChangeCollection.add(new ApiChange(oldClass, apiStatus));
    }
    // missing fields
    for (ApiElement element : missingFields) {
      apiChangeCollection.add(new ApiChange(element, ApiChange.Status.MISSING));
    }
    apiChangeCollection.addAll(getIntersectingFields());
    for (ApiClass.MethodType methodType : ApiClass.MethodType.values()) {
      apiChangeCollection.addAll(getMissingMethods(methodType));
      apiChangeCollection.addAll(getIntersectingMethods(methodType));
    }
    return apiChangeCollection;
  }

  String getName() {
    return className;
  }

  /*
   * Even though the method name is contained in the "property" parameter, the
   * type information is lost. TODO (amitmanjhi): fix this issue later.
   */
  private <T> void addProperty(Map<T, Set<ApiChange>> hashMap, T key,
      ApiChange property) {
    Set<ApiChange> value = hashMap.get(key);
    if (value == null) {
      value = new HashSet<ApiChange>();
    }
    value.add(property);
    hashMap.put(key, value);
  }

  private Collection<ApiChange> getIntersectingFields() {
    Collection<ApiChange> collection = new ArrayList<ApiChange>();
    List<ApiField> intersectingFieldsList = new ArrayList<ApiField>(
        intersectingFields.keySet());
    Collections.sort(intersectingFieldsList);
    for (ApiField apiField : intersectingFieldsList) {
      for (ApiChange apiChange : intersectingFields.get(apiField)) {
        collection.add(apiChange);
      }
    }
    return collection;
  }

  private Collection<ApiChange> getIntersectingMethods(
      ApiClass.MethodType methodType) {
    Collection<ApiChange> collection = new ArrayList<ApiChange>();
    List<ApiAbstractMethod> apiMethodsList = new ArrayList<ApiAbstractMethod>(
        intersectingMethods.get(methodType).keySet());
    Collections.sort(apiMethodsList);
    for (ApiAbstractMethod apiMethod : apiMethodsList) {
      collection.addAll(intersectingMethods.get(methodType).get(apiMethod));
    }
    return collection;
  }

  private Collection<ApiChange> getMissingMethods(ApiClass.MethodType methodType) {
    Collection<ApiChange> collection = new ArrayList<ApiChange>();
    List<ApiAbstractMethod> apiMethodsList = new ArrayList<ApiAbstractMethod>(
        missingMethods.get(methodType));
    Collections.sort(apiMethodsList);
    for (ApiAbstractMethod apiMethod : apiMethodsList) {
      collection.add(new ApiChange(apiMethod, ApiChange.Status.MISSING));
    }
    return collection;
  }

  /**
   * Attempts to find out if a methodName(null) call previously succeeded, and
   * would fail with the new Api. Currently, this method is simple.
   * TODO(amitmanjhi): generalize this method.
   * 
   * @param methodsInNew Candidate methods in the new Api
   * @param methodsInExisting Candidate methods in the existing Api.
   * @return the possible incompatibilities due to method overloading.
   */
  private Map<ApiAbstractMethod, ApiChange> getOverloadedMethodIncompatibility(
      Set<ApiAbstractMethod> methodsInNew,
      Set<ApiAbstractMethod> methodsInExisting) {
    if (!ApiCompatibilityChecker.API_SOURCE_COMPATIBILITY
        || methodsInExisting.size() != 1 || methodsInNew.size() <= 1) {
      return Collections.emptyMap();
    }
    ApiAbstractMethod existingMethod = methodsInExisting.toArray(new ApiAbstractMethod[0])[0];
    String signature = existingMethod.getCoarseSignature();
    List<ApiAbstractMethod> matchingMethods = new ArrayList<ApiAbstractMethod>();
    for (ApiAbstractMethod current : methodsInNew) {
      if (current.getCoarseSignature().equals(signature)) {
        matchingMethods.add(current);
      }
    }
    if (isPairwiseCompatible(matchingMethods)) {
      return Collections.emptyMap();
    }
    Map<ApiAbstractMethod, ApiChange> incompatibilities = new HashMap<ApiAbstractMethod, ApiChange>();
    incompatibilities.put(existingMethod, new ApiChange(existingMethod,
        ApiChange.Status.OVERLOADED_METHOD_CALL,
        "Many methods in the new API with similar signatures. Methods = "
            + methodsInNew + " This might break API source compatibility"));
    return incompatibilities;
  }

  /**
   * @return true if each pair of methods within the list is compatibile.
   */
  private boolean isPairwiseCompatible(List<ApiAbstractMethod> methods) {
    int length = methods.size();
    for (int i = 0; i < length - 1; i++) {
      for (int j = i + 1; j < length; j++) {
        ApiAbstractMethod firstMethod = methods.get(i);
        ApiAbstractMethod secondMethod = methods.get(j);
        if (!firstMethod.isCompatible(secondMethod)
            && !secondMethod.isCompatible(firstMethod)) {
          return false;
        }
      }
    }
    return true;
  }

  /**
   * Processes elements in intersection, checking for incompatibilities.
   * 
   * @param intersection
   * @param methodType
   */
  private void processElementsInIntersection(Set<String> intersection,
      ApiClass.MethodType methodType) {

    Set<ApiAbstractMethod> missingElements = missingMethods.get(methodType);
    Map<ApiAbstractMethod, Set<ApiChange>> intersectingElements = intersectingMethods.get(methodType);

    Set<ApiAbstractMethod> onlyInExisting = new HashSet<ApiAbstractMethod>();
    Set<ApiAbstractMethod> onlyInNew = new HashSet<ApiAbstractMethod>();
    Set<String> commonSignature = new HashSet<String>();

    for (String elementName : intersection) {
      Set<ApiAbstractMethod> methodsInNew = newClass.getApiMethodsByName(
          elementName, methodType);
      Set<ApiAbstractMethod> methodsInExisting = oldClass.getApiMethodsByName(
          elementName, methodType);
      onlyInNew.addAll(methodsInNew);
      onlyInExisting.addAll(methodsInExisting);
      Map<ApiAbstractMethod, ApiChange> incompatibilityMap = getOverloadedMethodIncompatibility(
          methodsInNew, methodsInExisting);
      for (ApiAbstractMethod existingMethod : incompatibilityMap.keySet()) {
        addProperty(intersectingElements, existingMethod,
            incompatibilityMap.get(existingMethod));
      }

      /*
       * We want to find out which method calls that the current API supports
       * will succeed even with the new API. Determine this by iterating over
       * the methods of the current API. Keep track of a method that has the
       * same exact argument types as the old method. If such a method exists,
       * check Api compatibility with just that method. Otherwise, check api
       * compatibility with ALL methods that might be compatible. (This
       * conservative estimate will work as long as we do not change the Api in
       * pathological ways.)
       */
      for (ApiAbstractMethod methodInExisting : methodsInExisting) {
        Set<ApiChange> allPossibleApiChanges = new HashSet<ApiChange>();
        ApiAbstractMethod sameSignatureMethod = null;
        for (ApiAbstractMethod methodInNew : methodsInNew) {
          Set<ApiChange> currentApiChange = new HashSet<ApiChange>();
          boolean hasSameSignature = false;
          if (methodInExisting.isCompatible(methodInNew)) {
            if (methodInExisting.isOverridable()) {
              // check if the new method's api is exactly the same
              currentApiChange.addAll(methodInExisting.getAllChangesInApi(methodInNew));
            } else {
              // check for changes to return type and exceptions
              currentApiChange.addAll(methodInExisting.checkExceptionsAndReturnType(methodInNew));
            }
            for (ApiChange.Status status : methodInExisting.getModifierChanges(methodInNew)) {
              currentApiChange.add(new ApiChange(methodInExisting, status));
            }
            if (methodInNew.getInternalSignature().equals(
                methodInExisting.getInternalSignature())) {
              currentApiChange.add(new ApiChange(methodInExisting,
                  ApiChange.Status.COMPATIBLE));
              hasSameSignature = true;
            } else {
              currentApiChange.add(new ApiChange(methodInExisting,
                  ApiChange.Status.COMPATIBLE_WITH,
                  methodInNew.getApiSignature()));
            }
          }

          if (currentApiChange.size() > 0) {
            if (hasSameSignature) {
              allPossibleApiChanges = currentApiChange;
              sameSignatureMethod = methodInNew;
            } else if (sameSignatureMethod == null) {
              allPossibleApiChanges.addAll(currentApiChange);
            }
          }
        }
        // put the best Api match
        if (allPossibleApiChanges.size() > 0) {
          onlyInExisting.remove(methodInExisting);
          String signatureInExisting = methodInExisting.getInternalSignature();
          if (sameSignatureMethod != null
              && signatureInExisting.equals(sameSignatureMethod.getInternalSignature())) {
            commonSignature.add(signatureInExisting);
          }
          for (ApiChange apiChange : allPossibleApiChanges) {
            addProperty(intersectingElements, methodInExisting, apiChange);
          }
        }
      }

      /**
       * Look for incompatiblities that might result due to new methods
       * over-loading existing methods. Instead of applying JLS to determine the
       * best match, just be conservative and report all possible
       * incompatibilities if there is no old method with the exact same
       * signature.
       * 
       * <pre>
       * class A { // old version 
       *   final void foo(Set<String> p1, Set<String> p2); 
       * }
       * 
       * class A { // new version 
       *   final void foo(Set<String> p1, Set<String> p2); 
       *   void foo(HashSet<String> p1, Set<String> p2) throws ...; 
       * }
       * </pre>
       */
      for (ApiAbstractMethod methodInNew : methodsInNew) {
        ApiAbstractMethod sameSignatureMethod = null;
        for (ApiAbstractMethod methodInExisting : methodsInExisting) {
          if (methodInNew.getInternalSignature().equals(
              methodInExisting.getInternalSignature())) {
            sameSignatureMethod = methodInExisting;
            break;
          }
        }

        // do not look for incompatibilities with overloaded methods, if exact
        // match exists.
        if (sameSignatureMethod != null) {
          continue;
        }
        for (ApiAbstractMethod methodInExisting : methodsInExisting) {
          if (methodInNew.isCompatible(methodInExisting)) {
            // new method is going to be called instead of existing method,
            // determine incompatibilities
            for (ApiChange apiChange : methodInExisting.checkExceptionsAndReturnType(methodInNew)) {
              addProperty(intersectingElements, methodInExisting, apiChange);
            }
          }
        }
      }

      // printOutput(commonSignature, onlyInExisting, onlyInNew);
    }
    missingElements.addAll(onlyInExisting);
  }

  private void processFieldsInIntersection(Set<String> intersection) {
    for (String fieldName : intersection) {
      ApiField newField = newClass.getApiFieldByName(fieldName);
      ApiField oldField = oldClass.getApiFieldByName(fieldName);
      Set<ApiChange> apiChanges = oldField.getModifierChanges(newField);
      if (apiChanges.size() > 0) {
        intersectingFields.put(oldField, apiChanges);
      }
    }
  }

}
