class CallGraphGrapher extends SceneTransformer {
  private static final Logger logger = LoggerFactory.getLogger(CallGraphGrapher.class);

  public CallGraphGrapher(Singletons.Global g) {
  }

  public static CallGraphGrapher v() {
    return G.v().soot_jimple_toolkits_annotation_callgraph_CallGraphGrapher();
  }

  private MethodToContexts methodToContexts;
  private CallGraph cg;
  private boolean showLibMeths;

  private ArrayList<MethInfo> getTgtMethods(SootMethod method, boolean recurse) {
    // logger.debug("meth for tgts: "+method);
    if (!method.hasActiveBody()) {
      return new ArrayList<MethInfo>();
    }
    Body b = method.getActiveBody();
    ArrayList<MethInfo> list = new ArrayList<MethInfo>();
    Iterator sIt = b.getUnits().iterator();
    while (sIt.hasNext()) {
      Stmt s = (Stmt) sIt.next();
      Iterator edges = cg.edgesOutOf(s);
      while (edges.hasNext()) {
        Edge e = (Edge) edges.next();
        SootMethod sm = e.tgt();
        // logger.debug("found target method: "+sm);

        if (sm.getDeclaringClass().isLibraryClass()) {
          if (isShowLibMeths()) {
            if (recurse) {
              list.add(new MethInfo(sm, hasTgtMethods(sm) | hasSrcMethods(sm), e.kind()));
            } else {
              list.add(new MethInfo(sm, true, e.kind()));
            }
          }
        } else {
          if (recurse) {
            list.add(new MethInfo(sm, hasTgtMethods(sm) | hasSrcMethods(sm), e.kind()));
          } else {
            list.add(new MethInfo(sm, true, e.kind()));
          }
        }
      }
    }
    return list;
  }

  private boolean hasTgtMethods(SootMethod meth) {
    ArrayList<MethInfo> list = getTgtMethods(meth, false);
    if (!list.isEmpty()) {
      return true;
    } else {
      return false;
    }
  }

  private boolean hasSrcMethods(SootMethod meth) {
    ArrayList<MethInfo> list = getSrcMethods(meth, false);
    if (list.size() > 1) {
      return true;
    } else {
      return false;
    }
  }

  private ArrayList<MethInfo> getSrcMethods(SootMethod method, boolean recurse) {
    // logger.debug("meth for srcs: "+method);
    ArrayList<MethInfo> list = new ArrayList<MethInfo>();

    for (Iterator momcIt = methodToContexts.get(method).iterator(); momcIt.hasNext();) {
      final MethodOrMethodContext momc = (MethodOrMethodContext) momcIt.next();
      Iterator callerEdges = cg.edgesInto(momc);
      while (callerEdges.hasNext()) {
        Edge callEdge = (Edge) callerEdges.next();
        SootMethod methodCaller = callEdge.src();
        if (methodCaller.getDeclaringClass().isLibraryClass()) {
          if (isShowLibMeths()) {
            if (recurse) {
              list.add(
                  new MethInfo(methodCaller, hasTgtMethods(methodCaller) | hasSrcMethods(methodCaller), callEdge.kind()));
            } else {
              list.add(new MethInfo(methodCaller, true, callEdge.kind()));
            }
          }
        } else {
          if (recurse) {
            list.add(new MethInfo(methodCaller, hasTgtMethods(methodCaller) | hasSrcMethods(methodCaller), callEdge.kind()));
          } else {
            list.add(new MethInfo(methodCaller, true, callEdge.kind()));
          }
        }
      }
    }
    return list;
  }

  protected void internalTransform(String phaseName, Map options) {

    CGGOptions opts = new CGGOptions(options);
    if (opts.show_lib_meths()) {
      setShowLibMeths(true);
    }
    cg = Scene.v().getCallGraph();
    if (Options.v().interactive_mode()) {
      reset();
    }
  }

  public void reset() {<FILL_FUNCTION_BODY>}

  private SootMethod getFirstMethod(SootClass sc) {
    ArrayList paramTypes = new ArrayList();
    paramTypes.add(soot.ArrayType.v(soot.RefType.v("java.lang.String"), 1));
    SootMethod sm = sc.getMethodUnsafe("main", paramTypes, soot.VoidType.v());
    if (sm != null) {
      return sm;
    } else {
      return (SootMethod) sc.getMethods().get(0);
    }
  }

  public void handleNextMethod() {
    if (!getNextMethod().hasActiveBody()) {
      return;
    }
    ArrayList<MethInfo> tgts = getTgtMethods(getNextMethod(), true);
    // System.out.println("for: "+getNextMethod().getName()+" tgts: "+tgts);
    ArrayList<MethInfo> srcs = getSrcMethods(getNextMethod(), true);
    // System.out.println("for: "+getNextMethod().getName()+" srcs: "+srcs);
    CallGraphInfo info = new CallGraphInfo(getNextMethod(), tgts, srcs);
    // System.out.println("sending next method");
    InteractionHandler.v().handleCallGraphPart(info);
    // handleNextMethod();
  }

  private SootMethod nextMethod;

  public void setNextMethod(SootMethod m) {
    nextMethod = m;
  }

  public SootMethod getNextMethod() {
    return nextMethod;
  }

  public void setShowLibMeths(boolean b) {
    showLibMeths = b;
  }

  public boolean isShowLibMeths() {
    return showLibMeths;
  }

}

    if (methodToContexts == null) {
      methodToContexts = new MethodToContexts(Scene.v().getReachableMethods().listener());
    }

    if (Scene.v().hasCallGraph()) {
      SootClass sc = Scene.v().getMainClass();
      SootMethod sm = getFirstMethod(sc);
      // logger.debug("got first method");
      ArrayList<MethInfo> tgts = getTgtMethods(sm, true);
      // logger.debug("got tgt methods");
      ArrayList<MethInfo> srcs = getSrcMethods(sm, true);
      // logger.debug("got src methods");
      CallGraphInfo info = new CallGraphInfo(sm, tgts, srcs);
      // logger.debug("will handle new call graph");
      InteractionHandler.v().handleCallGraphStart(info, this);
    }
  
<methods>public non-sealed void <init>() ,public final void transform(java.lang.String, Map<java.lang.String,java.lang.String>) ,public final void transform(java.lang.String) ,public final void transform() <variables>