content: /*
   * Copyright (C) 2009 The Android Open Source Project
   *
   * 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.
   */
  
  import java.io.IOException;
  import java.io.FileReader;
  import java.io.BufferedReader;
  import java.io.PrintStream;
  import java.util.Set;
  import java.util.TreeSet;
  import java.util.HashSet;
  import java.util.Iterator;
  
  /**
   * Prints HTML containing removed and added files.
   */
  public class PrintHtmlDiff {
  
      private static final String OLD_PRELOADED_CLASSES
              = "old-preloaded-classes";
  
      public static void main(String[] args) throws IOException,
              ClassNotFoundException {
          Root root = Root.fromFile(args[0]);
  
          BufferedReader oldClasses = new BufferedReader(
              new FileReader(OLD_PRELOADED_CLASSES));
  
          // Classes loaded implicitly by the zygote.
          Set<LoadedClass> zygote = new HashSet<LoadedClass>();
          for (Proc proc : root.processes.values()) {
              if (proc.name.equals("zygote")) {
                  for (Operation op : proc.operations) {
                      zygote.add(op.loadedClass);
                  }
                  break;
              }
          }
  
          Set<LoadedClass> removed = new TreeSet<LoadedClass>();
          Set<LoadedClass> added = new TreeSet<LoadedClass>();
  
          for (LoadedClass loadedClass : root.loadedClasses.values()) {
              if (loadedClass.preloaded && !zygote.contains(loadedClass)) {
                  added.add(loadedClass);
              }
          }
  
          String line;
          while ((line = oldClasses.readLine()) != null) {
              line = line.trim();
              LoadedClass clazz = root.loadedClasses.get(line);
              if (clazz != null) {
                  added.remove(clazz);
                  if (!clazz.preloaded) removed.add(clazz);
              }
          }
  
          PrintStream out = System.out;
  
          out.println("<html><body>");
          out.println("<style>");
          out.println("a, th, td, h2 { font-family: arial }");
          out.println("th, td { font-size: small }");
          out.println("</style>");
          out.println("<script src=\"sorttable.js\"></script>");
          out.println("<p><a href=\"#removed\">Removed</a>");
          out.println("<a name=\"added\"/><h2>Added</h2>");
          printTable(out, root.baseline, added);
          out.println("<a name=\"removed\"/><h2>Removed</h2>");
          printTable(out, root.baseline, removed);
          out.println("</body></html>");
      }
  
      static void printTable(PrintStream out, MemoryUsage baseline,
              Iterable<LoadedClass> classes) {
          out.println("<table border=\"1\" cellpadding=\"5\""
                  + " class=\"sortable\">");
  
          out.println("<thead><tr>");
          out.println("<th>Name</th>");
          out.println("<th>Load Time (us)</th>");
          out.println("<th>Loaded By</th>");
          out.println("<th>Heap (B)</th>");
          out.println("<th>Pages</th>");
          out.println("</tr></thead>");
  
          for (LoadedClass clazz : classes) {
              out.println("<tr>");
              out.println("<td>" + clazz.name + "</td>");
              out.println("<td>" + clazz.medianTimeMicros() + "</td>");
  
              out.println("<td>");
              Set<String> procNames = new TreeSet<String>();
              for (Operation op : clazz.loads) procNames.add(op.process.name);
              for (Operation op : clazz.initializations) {
                  procNames.add(op.process.name);
              }
              if (procNames.size() <= 3) {
                  for (String name : procNames) {
                      out.print(name + "<br/>");
                  }
              } else {
                  Iterator<String> i = procNames.iterator();
                  out.print(i.next() + "<br/>");
                  out.print(i.next() + "<br/>");
                  out.print("...and " + (procNames.size() - 2)
                          + " others.");
              }
              out.println("</td>");
  
              if (clazz.memoryUsage.isAvailable()) {
                  MemoryUsage subtracted
                          = clazz.memoryUsage.subtract(baseline);
  
                  out.println("<td>" + (subtracted.javaHeapSize()
                          + subtracted.nativeHeapSize) + "</td>");
                  out.println("<td>" + subtracted.totalPages() + "</td>");
              } else {
                  for (int i = 0; i < 2; i++) {
                      out.println("<td>n/a</td>");                    
                  }
              }
  
              out.println("</tr>");
          }
  
          out.println("</table>");
      }
  }
  