/*
 * Copyright (C) 2010 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.doclava;

import com.google.clearsilver.jsilver.data.Data;
import com.google.doclava.apicheck.ApiCheck;
import com.google.doclava.apicheck.ApiInfo;
import com.google.doclava.apicheck.ApiParseException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


/**
 * Applies version information to the DroidDoc class model from apicheck XML files. Sample usage:
 * 
 * <pre>
 *   ClassInfo[] classInfos = ...
 *
 *   SinceTagger sinceTagger = new SinceTagger()
 *   sinceTagger.addVersion("frameworks/base/api/1.xml", "product 1.0")
 *   sinceTagger.addVersion("frameworks/base/api/2.xml", "product 1.5")
 *   sinceTagger.tagAll(...);
 * </pre>
 */
public class SinceTagger {

  private final Map<String, String> xmlToName = new LinkedHashMap<String, String>();

  /**
   * Specifies the apicheck XML file and the API version it holds. Calls to this method should be
   * called in order from oldest version to newest.
   */
  public void addVersion(String file, String name) {
    xmlToName.put(file, name);
  }

  public void tagAll(ClassInfo[] classDocs) {
    // read through the XML files in order, applying their since information
    // to the Javadoc models
    for (Map.Entry<String, String> versionSpec : xmlToName.entrySet()) {
      String xmlFile = versionSpec.getKey();
      String versionName = versionSpec.getValue();
      
      ApiInfo specApi;
      try {
        specApi = new ApiCheck().parseApi(xmlFile);
      } catch (ApiParseException e) {
        Errors.error(Errors.NO_SINCE_DATA, null, "Could not add since data for " + versionName);
        continue;
      }

      applyVersionsFromSpec(versionName, specApi, classDocs);
    }

    if (!xmlToName.isEmpty()) {
      warnForMissingVersions(classDocs);
    }
  }

  public boolean hasVersions() {
    return !xmlToName.isEmpty();
  }

  /**
   * Writes an index of the version names to {@code data}.
   */
  public void writeVersionNames(Data data) {
    int index = 1;
    for (String version : xmlToName.values()) {
      data.setValue("since." + index + ".name", version);
      index++;
    }
  }

  /**
   * Applies the version information to {@code classDocs} where not already present.
   * 
   * @param versionName the version name
   * @param specApi the spec for this version. If a symbol is in this spec, it was present in the
   *        named version
   * @param classDocs the doc model to update
   */
  private void applyVersionsFromSpec(String versionName, ApiInfo specApi, ClassInfo[] classDocs) {
    for (ClassInfo classDoc : classDocs) {
      PackageInfo packageSpec
          = specApi.getPackages().get(classDoc.containingPackage().name());

      if (packageSpec == null) {
        continue;
      }

      ClassInfo classSpec = packageSpec.allClasses().get(classDoc.name());

      if (classSpec == null) {
        continue;
      }

      versionPackage(versionName, classDoc.containingPackage());
      versionClass(versionName, classDoc);
      versionConstructors(versionName, classSpec, classDoc);
      versionFields(versionName, classSpec, classDoc);
      versionMethods(versionName, classSpec, classDoc);
    }
  }

  /**
   * Applies version information to {@code doc} where not already present.
   */
  private void versionPackage(String versionName, PackageInfo doc) {
    if (doc.getSince() == null) {
      doc.setSince(versionName);
    }
  }

  /**
   * Applies version information to {@code doc} where not already present.
   */
  private void versionClass(String versionName, ClassInfo doc) {
    if (doc.getSince() == null) {
      doc.setSince(versionName);
    }
  }

  /**
   * Applies version information from {@code spec} to {@code doc} where not already present.
   */
  private void versionConstructors(String versionName, ClassInfo spec, ClassInfo doc) {
    for (MethodInfo constructor : doc.constructors()) {
      if (constructor.getSince() == null
          && spec.hasConstructor(constructor)) {
        constructor.setSince(versionName);
      }
    }
  }

  /**
   * Applies version information from {@code spec} to {@code doc} where not already present.
   */
  private void versionFields(String versionName, ClassInfo spec, ClassInfo doc) {
    for (FieldInfo field : doc.fields()) {
      if (field.getSince() == null && spec.allFields().containsKey(field.name())) {
        field.setSince(versionName);
      }
    }
  }

  /**
   * Applies version information from {@code spec} to {@code doc} where not already present.
   */
  private void versionMethods(String versionName, ClassInfo spec, ClassInfo doc) {
    for (MethodInfo method : doc.methods()) {
      if (method.getSince() != null) {
        continue;
      }

      for (ClassInfo superclass : spec.hierarchy()) {
        if (superclass.allMethods().containsKey(method.getHashableName())) {
          method.setSince(versionName);
          break;
        }
      }
    }
  }

  /**
   * Warns if any symbols are missing version information. When configured properly, this will yield
   * zero warnings because {@code apicheck} guarantees that all symbols are present in the most
   * recent API.
   */
  private void warnForMissingVersions(ClassInfo[] classDocs) {
    for (ClassInfo claz : classDocs) {
      if (!checkLevelRecursive(claz)) {
        continue;
      }

      if (claz.getSince() == null) {
        Errors.error(Errors.NO_SINCE_DATA, claz.position(), "XML missing class "
            + claz.qualifiedName());
      }

      for (FieldInfo field : missingVersions(claz.fields())) {
        Errors.error(Errors.NO_SINCE_DATA, field.position(), "XML missing field "
            + claz.qualifiedName() + "#" + field.name());
      }

      for (MethodInfo constructor : missingVersions(claz.constructors())) {
        Errors.error(Errors.NO_SINCE_DATA, constructor.position(), "XML missing constructor "
            + claz.qualifiedName() + "#" + constructor.getHashableName());
      }

      for (MethodInfo method : missingVersions(claz.methods())) {
        Errors.error(Errors.NO_SINCE_DATA, method.position(), "XML missing method "
            + claz.qualifiedName() + "#" + method.getHashableName());
      }
    }
  }

  /**
   * Returns the DocInfos in {@code all} that are documented but do not have since tags.
   */
  private <T extends MemberInfo> Iterable<T> missingVersions(ArrayList<T> all) {
    List<T> result = Collections.emptyList();
    for (T t : all) {
      // if this member has version info or isn't documented, skip it
      if (t.getSince() != null || t.isHidden() || !checkLevelRecursive(t.realContainingClass())) {
        continue;
      }

      if (result.isEmpty()) {
        result = new ArrayList<T>(); // lazily construct a mutable list
      }
      result.add(t);
    }
    return result;
  }

  /**
   * Returns true if {@code claz} and all containing classes are documented. The result may be used
   * to filter out members that exist in the API data structure but aren't a part of the API.
   */
  private boolean checkLevelRecursive(ClassInfo claz) {
    for (ClassInfo c = claz; c != null; c = c.containingClass()) {
      if (!c.checkLevel()) {
        return false;
      }
    }
    return true;
  }
}
