// Path: src/main/java/org/cf/resequencer/Console.java
// public class Console {
//     private static final boolean StackTrace = false;
//     public static int VerboseLevel;
//     public static String LogFile = "console.log";
// 
//     public static void msgln() {
//         System.out.println();
//     }
// 
//     public static void msgln(final String msg) {
//         System.out.println(msg);
//     }
// 
//     public static void msg(final String msg) {
//         System.out.print(msg);
//     }
// 
//     public static void debug(final String msg) {
//         if (VerboseLevel > 0) {
//             System.out.println(msg);
//         }
//     }
// 
//     public static void debug(final String msg, final int verboseLevel) {
//         if (verboseLevel <= VerboseLevel) {
//             debug(msg);
//         }
//     }
// 
//     public static void warn(final String msg) {
//         System.err.println("Warning: " + msg);
//         if (StackTrace) {
//             Thread.dumpStack();
//         }
//     }
// 
//     public static void error(final String msg) {
//         System.err.println("Error: " + msg);
//         if (StackTrace) {
//             Thread.dumpStack();
//         }
//     }
// 
//     public static void die(final Exception ex) {
//         die(ex, -1);
//     }
// 
//     public static void die(final Exception ex, final int exitStatus) {
//         if (StackTrace) {
//             ex.printStackTrace();
//         }
//         System.err.println("" + ex);
//         System.exit(exitStatus);
//     }
// 
//     public static void die(final String msg) {
//         die(msg, -1);
//     }
// 
//     public static void die(final String msg, int exitStatus) {
//         System.err.println("Fatal error: " + msg);
//         if (StackTrace) {
//             Thread.dumpStack();
//         }
//         System.exit(exitStatus);
//     }
// 
//     // run command and return {result, exit status}
//     public static String[] execute(String[] cmd) {
//         debug("Executing: " + Arrays.asList(cmd).toString());
// 
//         StringBuffer output = new StringBuffer();
//         Integer status = null;
// 
//         InputStream in = null;
//         try {
//             Process child = Runtime.getRuntime().exec(cmd);
// 
//             BufferedReader stdInput = new BufferedReader(new InputStreamReader(child.getInputStream()));
// 
//             String s;
//             while ((s = stdInput.readLine()) != null) {
//                 output.append(s).append('\n');
//             }
// 
//             status = child.waitFor();
// 
//             debug("Exit status: " + status, 2);
//         } catch (Exception ex) {
//             error("Run command failed.\n" + ex);
//         } finally {
//             IOUtils.closeQuietly(in);
//         }
// 
//         return new String[] { output.toString(), String.valueOf(status) };
//     }
// 
//     public static boolean deleteBestEffort(File path, String whatIsIt) {
//         return deleteBestEffort(path, whatIsIt, 3, false);
//     }
// 
//     public static boolean deleteBestEffort(File path, String whatIsIt, int maxTries) {
//         return deleteBestEffort(path, whatIsIt, maxTries, false);
//     }
// 
//     public static boolean deleteBestEffort(File path, String whatIsIt, int maxTries, boolean quiet) {
//         System.gc();
// 
//         int tries = 0;
//         while (!FileUtils.deleteQuietly(path) && (tries < maxTries)) {
//             System.gc();
//             tries++;
// 
//             if (!quiet) {
//                 warn("Unable to delete " + whatIsIt + ": " + path + ". Trying again ...");
//             }
// 
//             try {
//                 Thread.sleep(3000);
//             } catch (InterruptedException ex) {
//             }
//         }
// 
//         return !path.exists();
//     }
// }


import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.cf.resequencer.Console;
package org.cf.resequencer.patch;



/**
 * Handles matching fingerprints with smali files.
 * 
 * @author Caleb Fenton
 */
public class SmaliMatcher {

    private final SmaliFile[] SmaliFileList;
    private FingerprintReader myFPReader;
    private ArrayList<SmaliFile> SmaliFileMatches;
    private final int ProgressIncrement = 100;

    /**
     * 
     * @param smaliFiles
     *            array of paths to smali files
     * @param reader
     *            instance of FingerprintReader
     */
    public SmaliMatcher(SmaliFile[] smaliFiles, FingerprintReader reader) {
        SmaliFileList = smaliFiles;
        SmaliFileMatches = new ArrayList<SmaliFile>();
        myFPReader = reader;

        removeDisabledFingerprints();
    }

    /**
     * Performs region and match operations.
     * 
     * @return SmaliFiles with matched regions stored inside.
     */
    public List<SmaliFile> performMatching() {
        System.out.print("  Matching " + SmaliFileList.length + " files against " + myFPReader.Fingerprints.size()
                        + " fingerprints ");

        int count = 1;
        for (SmaliFile sf : SmaliFileList) {
            for (String fpName : myFPReader.Fingerprints.keySet()) {
                Fingerprint fp = myFPReader.Fingerprints.get(fpName);
                if (fp.FindOnce && wasFingerprintFound(fp.toString())) {
// Path: src/main/java/org/cf/resequencer/Console.java
// public class Console {
//     private static final boolean StackTrace = false;
//     public static int VerboseLevel;
//     public static String LogFile = "console.log";
// 
//     public static void msgln() {
//         System.out.println();
//     }
// 
//     public static void msgln(final String msg) {
//         System.out.println(msg);
//     }
// 
//     public static void msg(final String msg) {
//         System.out.print(msg);
//     }
// 
//     public static void debug(final String msg) {
//         if (VerboseLevel > 0) {
//             System.out.println(msg);
//         }
//     }
// 
//     public static void debug(final String msg, final int verboseLevel) {
//         if (verboseLevel <= VerboseLevel) {
//             debug(msg);
//         }
//     }
// 
//     public static void warn(final String msg) {
//         System.err.println("Warning: " + msg);
//         if (StackTrace) {
//             Thread.dumpStack();
//         }
//     }
// 
//     public static void error(final String msg) {
//         System.err.println("Error: " + msg);
//         if (StackTrace) {
//             Thread.dumpStack();
//         }
//     }
// 
//     public static void die(final Exception ex) {
//         die(ex, -1);
//     }
// 
//     public static void die(final Exception ex, final int exitStatus) {
//         if (StackTrace) {
//             ex.printStackTrace();
//         }
//         System.err.println("" + ex);
//         System.exit(exitStatus);
//     }
// 
//     public static void die(final String msg) {
//         die(msg, -1);
//     }
// 
//     public static void die(final String msg, int exitStatus) {
//         System.err.println("Fatal error: " + msg);
//         if (StackTrace) {
//             Thread.dumpStack();
//         }
//         System.exit(exitStatus);
//     }
// 
//     // run command and return {result, exit status}
//     public static String[] execute(String[] cmd) {
//         debug("Executing: " + Arrays.asList(cmd).toString());
// 
//         StringBuffer output = new StringBuffer();
//         Integer status = null;
// 
//         InputStream in = null;
//         try {
//             Process child = Runtime.getRuntime().exec(cmd);
// 
//             BufferedReader stdInput = new BufferedReader(new InputStreamReader(child.getInputStream()));
// 
//             String s;
//             while ((s = stdInput.readLine()) != null) {
//                 output.append(s).append('\n');
//             }
// 
//             status = child.waitFor();
// 
//             debug("Exit status: " + status, 2);
//         } catch (Exception ex) {
//             error("Run command failed.\n" + ex);
//         } finally {
//             IOUtils.closeQuietly(in);
//         }
// 
//         return new String[] { output.toString(), String.valueOf(status) };
//     }
// 
//     public static boolean deleteBestEffort(File path, String whatIsIt) {
//         return deleteBestEffort(path, whatIsIt, 3, false);
//     }
// 
//     public static boolean deleteBestEffort(File path, String whatIsIt, int maxTries) {
//         return deleteBestEffort(path, whatIsIt, maxTries, false);
//     }
// 
//     public static boolean deleteBestEffort(File path, String whatIsIt, int maxTries, boolean quiet) {
//         System.gc();
// 
//         int tries = 0;
//         while (!FileUtils.deleteQuietly(path) && (tries < maxTries)) {
//             System.gc();
//             tries++;
// 
//             if (!quiet) {
//                 warn("Unable to delete " + whatIsIt + ": " + path + ". Trying again ...");
//             }
// 
//             try {
//                 Thread.sleep(3000);
//             } catch (InterruptedException ex) {
//             }
//         }
// 
//         return !path.exists();
//     }
// }


// Path: src/main/java/org/cf/resequencer/patch/SmaliMatcher.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.cf.resequencer.Console;

package org.cf.resequencer.patch;



/**
 * Handles matching fingerprints with smali files.
 * 
 * @author Caleb Fenton
 */
public class SmaliMatcher {

    private final SmaliFile[] SmaliFileList;
    private FingerprintReader myFPReader;
    private ArrayList<SmaliFile> SmaliFileMatches;
    private final int ProgressIncrement = 100;

    /**
     * 
     * @param smaliFiles
     *            array of paths to smali files
     * @param reader
     *            instance of FingerprintReader
     */
    public SmaliMatcher(SmaliFile[] smaliFiles, FingerprintReader reader) {
        SmaliFileList = smaliFiles;
        SmaliFileMatches = new ArrayList<SmaliFile>();
        myFPReader = reader;

        removeDisabledFingerprints();
    }

    /**
     * Performs region and match operations.
     * 
     * @return SmaliFiles with matched regions stored inside.
     */
    public List<SmaliFile> performMatching() {
        System.out.print("  Matching " + SmaliFileList.length + " files against " + myFPReader.Fingerprints.size()
                        + " fingerprints ");

        int count = 1;
        for (SmaliFile sf : SmaliFileList) {
            for (String fpName : myFPReader.Fingerprints.keySet()) {
                Fingerprint fp = myFPReader.Fingerprints.get(fpName);
                if (fp.FindOnce && wasFingerprintFound(fp.toString())) {
                    Console.debug("    Skipping " + fp + " because it's already been found.", 3);