/*
 * 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 java.util.*;
import java.util.stream.Collectors;

public class TodoFile {

  public static final String MISSING = "No description text";

  public static boolean areTagsUseful(InheritedTags tags) {
    while (tags != null) {
      if (areTagsUseful(tags.tags())) {
        return true;
      }
      tags = tags.inherited();
    }
    return false;
  }

  public static boolean areTagsUseful(TagInfo[] tags) {
    for (TagInfo t : tags) {
      if ("Text".equals(t.name()) && t.text().trim().length() != 0) {
        return true;
      }
      if ("@inheritDoc".equals(t.name())) {
        return true;
      }
    }
    return false;
  }

  public static void setHDF(Data data, String base, SourcePositionInfo pos, String name,
      String descr) {
    data.setValue(base + ".pos", pos.toString());
    data.setValue(base + ".name", name);
    data.setValue(base + ".descr", descr);
  }

  static class PackageStats {
    String name;
    public int total;
    public int errors;
  }

  public static String percent(int a, int b) {
    return "" + Math.round((((b - a) / (float) b)) * 100) + "%";
  }

  public static void writeTodoFile(String filename) {
    Data data = Doclava.makeHDF();
    Doclava.setPageTitle(data, "Missing Documentation");
    TreeMap<String, PackageStats> packageStats = new TreeMap<String, PackageStats>();

    Collection<ClassInfo> classes = Converter.rootClasses().stream().sorted(ClassInfo.comparator)
        .collect(Collectors.toList());

    int classIndex = 0;

    for (ClassInfo cl : classes) {
      if (cl.isHiddenOrRemoved()){
        continue;
      }

      String classBase = "classes." + classIndex;

      String base = classBase + ".errors.";
      int errors = 0;
      int total = 1;

      if (!areTagsUseful(cl.inlineTags())) {
        setHDF(data, base + errors, cl.position(), "&lt;class comment&gt;", MISSING);
        errors++;
      }


      for (MethodInfo m : cl.constructors()) {
        boolean good = true;
        total++;
        if (m.checkLevel()) {
          if (!areTagsUseful(m.inlineTags())) {
            setHDF(data, base + errors, m.position(), m.prettySignature(), MISSING);
            good = false;
          }
        }
        if (!good) {
          errors++;
        }
      }

      for (MethodInfo m : cl.selfMethods()) {
        boolean good = true;
        total++;
        if (m.checkLevel()) {
          if (!areTagsUseful(m.inlineTags())) {
            setHDF(data, base + errors, m.position(), m.name() + m.prettySignature(), MISSING);
            good = false;
          }
        }
        if (!good) {
          errors++;
        }
      }


      for (FieldInfo f : cl.enumConstants()) {
        boolean good = true;
        total++;
        if (f.checkLevel()) {
          if (!areTagsUseful(f.inlineTags())) {
            setHDF(data, base + errors, f.position(), f.name(), MISSING);
            good = false;
          }
        }
        if (!good) {
          errors++;
        }
      }

      for (FieldInfo f : cl.selfFields()) {
        boolean good = true;
        total++;
        if (f.checkLevel()) {
          if (!areTagsUseful(f.inlineTags())) {
            setHDF(data, base + errors, f.position(), f.name(), MISSING);
            good = false;
          }
        }
        if (!good) {
          errors++;
        }
      }

      if (errors > 0) {
        data.setValue(classBase + ".qualified", cl.qualifiedName());
        data.setValue(classBase + ".errorCount", "" + errors);
        data.setValue(classBase + ".totalCount", "" + total);
        data.setValue(classBase + ".percentGood", percent(errors, total));
      }

      PackageInfo pkg = cl.containingPackage();
      String pkgName = pkg != null ? pkg.name() : "";
      PackageStats ps = packageStats.get(pkgName);
      if (ps == null) {
        ps = new PackageStats();
        ps.name = pkgName;
        packageStats.put(pkgName, ps);
      }
      ps.total += total;
      ps.errors += errors;

      classIndex++;
    }

    int allTotal = 0;
    int allErrors = 0;

    int i = 0;
    for (PackageStats ps : packageStats.values()) {
      data.setValue("packages." + i + ".name", "" + ps.name);
      data.setValue("packages." + i + ".errorCount", "" + ps.errors);
      data.setValue("packages." + i + ".totalCount", "" + ps.total);
      data.setValue("packages." + i + ".percentGood", percent(ps.errors, ps.total));

      allTotal += ps.total;
      allErrors += ps.errors;

      i++;
    }

    data.setValue("all.errorCount", "" + allErrors);
    data.setValue("all.totalCount", "" + allTotal);
    data.setValue("all.percentGood", percent(allErrors, allTotal));

    ClearPage.write(data, "todo.cs", filename, true);
  }
}
