/*
 * 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 info.persistent.dex;

import com.android.dexdeps.ClassRef;
import com.android.dexdeps.DexData;
import com.android.dexdeps.FieldRef;
import com.android.dexdeps.Output;

import java.util.*;

public class DexFieldCounts extends DexCount {

    DexFieldCounts(OutputStyle outputStyle) {
        super(outputStyle);
    }

    @Override
    public void generate(DexData dexData, boolean includeClasses, String packageFilter, int maxDepth, Filter filter) {
        FieldRef[] fieldRefs = getFieldRefs(dexData, filter);

        for (FieldRef fieldRef : fieldRefs) {
            String classDescriptor = fieldRef.getDeclClassName();
            String packageName = includeClasses ? Output.descriptorToDot(classDescriptor).replace(
                    '$', '.') : Output.packageNameOnly(classDescriptor);
            if (packageFilter != null && !packageName.startsWith(packageFilter)) {
                continue;
            }
            overallCount++;
            String packageNamePieces[] = packageName.split("\\.");
            DexCount.Node packageNode = packageTree;
            for (int i = 0; i < packageNamePieces.length && i < maxDepth; i++) {
                packageNode.count++;
                String name = packageNamePieces[i];
                if (packageNode.children.containsKey(name)) {
                    packageNode = packageNode.children.get(name);
                } else {
                    DexCount.Node childPackageNode = new DexCount.Node();
                    if (name.length() == 0) {
                        // This method is declared in a class that is part of the default package.
                        // Typical examples are methods that operate on arrays of primitive data
                        // types.
                        name = "<default>";
                    }
                    packageNode.children.put(name, childPackageNode);
                    packageNode = childPackageNode;
                }
            }
            packageNode.count++;
        }
    }

    private static FieldRef[] getFieldRefs(DexData dexData, Filter filter) {
        FieldRef[] fieldRefs = dexData.getFieldRefs();
        out.println("Read in " + fieldRefs.length + " method IDs.");
        if (filter == Filter.ALL) {
            return fieldRefs;
        }

        ClassRef[] externalClassRefs = dexData.getExternalReferences();
        out.println("Read in " + externalClassRefs.length + " external class references.");
        Set<FieldRef> externalFieldRefs = new HashSet<FieldRef>();
        for (ClassRef classRef : externalClassRefs) {
            Collections.addAll(externalFieldRefs, classRef.getFieldArray());
        }
        out.println("Read in " + externalFieldRefs.size() + " external field references.");
        List<FieldRef> filteredFieldRefs = new ArrayList<FieldRef>();
        for (FieldRef FieldRef : fieldRefs) {
            boolean isExternal = externalFieldRefs.contains(FieldRef);
            if ((filter == Filter.DEFINED_ONLY && !isExternal)
                    || (filter == Filter.REFERENCED_ONLY && isExternal)) {
                filteredFieldRefs.add(FieldRef);
            }
        }
        out.println("Filtered to " + filteredFieldRefs.size() + " " +
                (filter == Filter.DEFINED_ONLY ? "defined" : "referenced") + " field IDs.");
        return filteredFieldRefs.toArray(new FieldRef[filteredFieldRefs.size()]);
    }


}

@@ -618,124 +618,9 @@
 eps.
-ClassRef;%0Aimport com.android.dexdeps.DexData;%0Aimport com.android.dexdeps.FieldRef;%0Aimport com.android.dexdeps.Output
+*
 ;%0A%0Ai
@@ -1125,16 +1125,36 @@
 lasses ?
+%0A                   
  Output.
@@ -1194,16 +1194,27 @@
 replace(
+'$', '.') :
 %0A       
@@ -1229,20 +1229,8 @@
     
- '$', '.') :
  Out
@@ -1307,16 +1307,36 @@
  null &&
+%0A                   
  !packag
@@ -1430,32 +1430,87 @@
 overallCount++;%0A
+            if (outputStyle == OutputStyle.TREE) %7B%0A    
             Stri
@@ -1568,33 +1568,28 @@
             
-DexCount.
+    
 Node package
@@ -1608,16 +1608,20 @@
 geTree;%0A
+    
         
@@ -1701,32 +1701,36 @@
                 
+ 
+   
 packageNode.coun
@@ -1726,32 +1726,36 @@
 geNode.count++;%0A
+    
                 
@@ -1798,32 +1798,36 @@
                 
+ 
+   
 if (packageNode.
@@ -1852,24 +1852,28 @@
 ey(name)) %7B%0A
+    
             
@@ -1942,16 +1942,20 @@
         
+  
+  
 %7D else %7B
@@ -1975,25 +1975,20 @@
         
-DexCount.
+    
 Node chi
@@ -2011,17 +2011,8 @@
 new 
-DexCount.
 Node
@@ -2031,24 +2031,28 @@
             
+   
+ 
 if (name.len
@@ -2061,24 +2061,28 @@
 h() == 0) %7B%0A
+    
             
@@ -2188,24 +2188,28 @@
             
+    
 // Typical e
@@ -2272,43 +2272,16 @@
 data
-%0A                        //
  types.%0A
     
@@ -2276,16 +2276,20 @@
  types.%0A
+    
         
@@ -2324,16 +2324,20 @@
 ault%3E%22;%0A
+    
         
@@ -2362,32 +2362,36 @@
                 
+    
 packageNode.chil
@@ -2436,32 +2436,36 @@
                 
+    
 packageNode = ch
@@ -2488,34 +2488,42 @@
                 
+ 
-%7D%0A
+   %7D%0A    
             %7D%0A  
@@ -2524,32 +2524,36 @@
   %7D%0A            
+  
+  
 packageNode.coun
@@ -2549,32 +2549,358 @@
 geNode.count++;%0A
+            %7D else if (outputStyle == OutputStyle.FLAT) %7B%0A                IntHolder count = packageCount.get(packageName);%0A                if (count == null) %7B%0A                    count = new IntHolder();%0A                    packageCount.put(packageName, count);%0A                %7D%0A                count.value++;%0A            %7D%0A
         %7D%0A    %7D%0A
@@ -3086,21 +3086,20 @@
 gth + %22 
-metho
+fiel
 d IDs.%22)

Fix FLAT style output