private static ArrayList<SourceKey> createTree(String[] files) {
    ArrayList<SourceKey> ret = new ArrayList<SourceKey>();
    try {
      log("Processing Source Tree:");
      for (String file : files) {
        String data = Files.toString(new File(file), Charset.forName("UTF-8")).replaceAll("\r", "");
        String name = file.replace('\\', '/').substring(SRC.length() + 1);
        log("    " + name);
        CompilationUnit cu = Util.createUnit(parser, "1.6", name, data);

        ArrayList<TypeDeclaration> classes = new ArrayList<TypeDeclaration>();
        List<AbstractTypeDeclaration> types = (List<AbstractTypeDeclaration>) cu.types();
        for (AbstractTypeDeclaration type : types) {
          TREE.processClass(type);
          if (type instanceof TypeDeclaration) {
            classes.add((TypeDeclaration) type);
          }
        }
        ret.add(new SourceKey(name.substring(0, name.length() - 5), cu, data.trim(), classes));
      }

      for (String lib : libs) {
        // log("Processing Tree: " + lib);
        TREE.processLibrary(new File(lib));
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

    return ret;
  }
  public static void main(String[] args) throws Exception {
    SRC = new File(args[0]).getAbsolutePath();
    SRG = new SrgFile(new File(args[2])).read();
    if (!args[1].equalsIgnoreCase("none") && args[1].length() != 0) {
      if (args[1].contains(File.pathSeparator)) {
        libs = args[1].split(File.pathSeparator);
      } else {
        libs = Util.gatherFiles(new File(args[1]).getAbsolutePath(), ".jar", false);
      }
    } else {
      libs = new String[0];
    }

    addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
    addURL.setAccessible(true);
    for (String s : libs) {
      addURL.invoke(CodeFixer.class.getClassLoader(), new File(s).toURI().toURL());
    }

    FATAL = !argExists("non-fatal", args);
    DRYRUN = argExists("dry-run", args);
    String data_file = argValue("fix-config", args);
    if (data_file != null) {
      File f = new File(data_file);
      if (f.exists()) {
        FIXES.load(new FileInputStream(f));
      }
    }

    parser = Util.createParser(JavaCore.VERSION_1_6, SRC, libs);

    String[] files = Util.gatherFiles(SRC, ".java", false);
    try {
      ArrayList<SourceKey> srcClasses = createTree(files);

      log("Gathering Fixes:");
      HashMap<String, ArrayList<FixTypes>> classFixes = findFixes(srcClasses);

      log("Applying Fixes:");
      for (String key : classFixes.keySet()) {
        ArrayList<FixTypes> fixes = classFixes.get(key);
        Collections.sort(fixes);

        log("  " + key);

        SourceKey data = null;
        for (SourceKey s : srcClasses) {
          if (s.name.equals(key)) {
            data = s;
            break;
          }
        }

        if (data == null) {
          log("    Could not find sourcekey for fixes: " + key);
          System.exit(1);
        }

        int offset = 0;
        String src = data.data;

        for (FixTypes fix : fixes) {
          log("    Fix: " + fix + " " + offset);

          String pre = src.substring(0, fix.getStart() + offset);
          String post = src.substring(fix.getStart() + fix.getLength() + offset);

          src = pre + fix.newText + post;
          offset += (fix.newText.length() - fix.getLength());
        }

        String outFile = SRC + "/" + key + ".java";
        try {
          if (!DRYRUN) {
            FileWriter out = new FileWriter(outFile);
            out.write(src);
            out.close();
          }
        } catch (IOException e) {
          System.out.println("Exception " + e.toString());
        }
        System.out.println("");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }