/*
 * 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();
  }

  // TODO: variable never read, remove?
  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());
  }
  
  @Override
  public boolean equals(Object o) {
    if (!(o instanceof ApiClassDiffGenerator)) {
      return false;
    }
    return this.getName().equals(((ApiClassDiffGenerator) o).getName());
  }

  @Override
  public int hashCode() {
    return this.getName().hashCode();
  }

  // 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 (Map.Entry<ApiAbstractMethod, ApiChange> entry
          : incompatibilityMap.entrySet()) {
        addProperty(intersectingElements, entry.getKey(), entry.getValue());
      }

      /*
       * 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);
      }
    }
  }

}
