Finish up the "info" command in dicttool. (A6)

Bug: 7388857
Change-Id: I704f12a6be76ce1644ec5e8dd3b667f112e9c04a
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index e88a4ae..705f664 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -224,6 +224,8 @@
     static final int MAX_TERMINAL_FREQUENCY = 255;
     static final int MAX_BIGRAM_FREQUENCY = 15;
 
+    public static final int SHORTCUT_WHITELIST_FREQUENCY = 15;
+
     // This option needs to be the same numeric value as the one in binary_format.h.
     static final int NOT_VALID_WORD = -99;
     static final int SIGNED_CHILDREN_ADDRESS_SIZE = 3;
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
index 4453798..4abed9f 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
@@ -22,6 +22,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -255,8 +256,6 @@
 
     /**
      * Options global to the dictionary.
-     *
-     * There are no options at the moment, so this class is empty.
      */
     public static final class DictionaryOptions {
         public final boolean mGermanUmlautProcessing;
@@ -268,6 +267,39 @@
             mGermanUmlautProcessing = germanUmlautProcessing;
             mFrenchLigatureProcessing = frenchLigatureProcessing;
         }
+        @Override
+        public String toString() { // Convenience method
+            return toString(0);
+        }
+        public String toString(final int indentCount) {
+            final StringBuilder indent = new StringBuilder();
+            for (int i = 0; i < indentCount; ++i) {
+                indent.append(" ");
+            }
+            final StringBuilder s = new StringBuilder();
+            for (final String optionKey : mAttributes.keySet()) {
+                s.append(indent);
+                s.append(optionKey);
+                s.append(" = ");
+                if ("date".equals(optionKey)) {
+                    // Date needs a number of milliseconds, but the dictionary contains seconds
+                    s.append(new Date(
+                            1000 * Long.parseLong(mAttributes.get(optionKey))).toString());
+                } else {
+                    s.append(mAttributes.get(optionKey));
+                }
+                s.append("\n");
+            }
+            if (mGermanUmlautProcessing) {
+                s.append(indent);
+                s.append("Needs German umlaut processing\n");
+            }
+            if (mFrenchLigatureProcessing) {
+                s.append(indent);
+                s.append("Needs French ligature processing\n");
+            }
+            return s.toString();
+        }
     }
 
     public final DictionaryOptions mOptions;
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
index c176675..cd04d18 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.latin.dicttool;
 
+import com.android.inputmethod.latin.makedict.FormatSpec;
 import com.android.inputmethod.latin.makedict.FusionDictionary;
 import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
 import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
@@ -150,8 +151,9 @@
                     if (SHORTCUT_TAG.equals(params[0])) {
                         shortcut = params[1];
                     } else if (FREQUENCY_TAG.equals(params[0])) {
-                        shortcutFreq =
-                                WHITELIST_TAG.equals(params[1]) ? 15 : Integer.parseInt(params[1]);
+                        shortcutFreq = WHITELIST_TAG.equals(params[1])
+                                ? FormatSpec.SHORTCUT_WHITELIST_FREQUENCY
+                                : Integer.parseInt(params[1]);
                     }
                 }
                 if (null != shortcut) {
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java
index bafde62..be4b2b8 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java
@@ -18,8 +18,11 @@
 
 import com.android.inputmethod.latin.dicttool.BinaryDictOffdeviceUtils.DecoderChainSpec;
 import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
+import com.android.inputmethod.latin.makedict.FormatSpec;
 import com.android.inputmethod.latin.makedict.FusionDictionary;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
 import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+import com.android.inputmethod.latin.makedict.Word;
 
 import org.xml.sax.SAXException;
 
@@ -38,8 +41,9 @@
     public Info() {
     }
 
+    @Override
     public String getHelp() {
-        return "info <filename>: prints various information about a dictionary file";
+        return COMMAND + "<filename>: prints various information about a dictionary file";
     }
 
     private static void crash(final String filename, final Exception e) {
@@ -72,6 +76,7 @@
                         FileChannel.MapMode.READ_ONLY, 0, decodedSpec.mFile.length());
                 System.out.println("Format : Binary dictionary format");
                 System.out.println("Packaging : " + decodedSpec.describeChain());
+                System.out.println("Uncompressed size : " + decodedSpec.mFile.length());
                 return BinaryDictInputOutput.readDictionaryBinary(
                         new BinaryDictInputOutput.ByteBufferWrapper(buffer), null);
             }
@@ -87,12 +92,40 @@
         return null;
     }
 
+    private static void showInfo(final FusionDictionary dict) {
+        System.out.println("Header attributes :");
+        System.out.print(dict.mOptions.toString(2));
+        int wordCount = 0;
+        int bigramCount = 0;
+        int shortcutCount = 0;
+        int whitelistCount = 0;
+        for (final Word w : dict) {
+            ++wordCount;
+            if (null != w.mBigrams) {
+                bigramCount += w.mBigrams.size();
+            }
+            if (null != w.mShortcutTargets) {
+                shortcutCount += w.mShortcutTargets.size();
+                for (WeightedString shortcutTarget : w.mShortcutTargets) {
+                    if (FormatSpec.SHORTCUT_WHITELIST_FREQUENCY == shortcutTarget.mFrequency) {
+                        ++whitelistCount;
+                    }
+                }
+            }
+        }
+        System.out.println("Words in the dictionary : " + wordCount);
+        System.out.println("Bigram count : " + bigramCount);
+        System.out.println("Shortcuts : " + shortcutCount + " (out of which " + whitelistCount
+                + " whitelist entries)");
+    }
+
+    @Override
     public void run() {
-        // TODO: implement this
         if (mArgs.length < 1) {
             throw new RuntimeException("Not enough arguments for command " + COMMAND);
         }
         final String filename = mArgs[0];
         final FusionDictionary dict = getDictionary(filename);
+        showInfo(dict);
     }
 }