// Decompile selected function recursively
// @category _Reman3
// @menupath Reman3.Dump Current Function (recursive)

import java.util.ArrayList;
import java.util.List;

import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Function;
import re3lib.FunctionDumper;
import re3lib.GlobalDumper;
import re3lib.PCallTracer;
import re3lib.RecompileConfig;
import re3lib.TypeDumper;

public class DumpCurrentFunctionRecursive extends GhidraScript {
  @Override
  public void run() throws Exception {
    RecompileConfig.INSTANCE = new RecompileConfig(this);
    RecompileConfig.INSTANCE.createDirectories();

    GlobalDumper globalDumper = new GlobalDumper(this);
    globalDumper.loadGlobalManifest();

    FunctionDumper functionDumper = new FunctionDumper(this, globalDumper);

    PCallTracer tracer = new PCallTracer();
    tracer.setBlacklist(functionDumper.functionAddrBlackList);
    tracer.traceCalls(getFunctionContaining(currentAddress));

    List<Function> functionsToDump = new ArrayList<>();
    List<Function> functionsToDumpNew = new ArrayList<>();
    for (Function func : tracer.out) {
      if (FunctionDumper.isDumpedFix(func))
        continue;

      println("Dump: " + func.getName());
      functionsToDump.add(func);

      if (!FunctionDumper.isDumpedAuto(func))
        functionsToDumpNew.add(func);
    }

    if (!functionsToDump.isEmpty()) {
      String newOpt = "Only new (" + functionsToDumpNew.size() + ")";
      String okOpt = "Yes (" + functionsToDump.size() + ")";
      String choice = askChoice("Confirmation", "About to generate " + functionsToDump.size() + " functions ("
          + functionsToDumpNew.size() + " new), continue?",
          new ArrayList<String>() {
            {
              add(okOpt);
              add(newOpt);
              add("No");
            }
          }, okOpt);
      if (choice == okOpt) {
      } else if (choice == newOpt) {
        functionsToDump = functionsToDumpNew;
      } else {
        return;
      }

      for (Function func : functionsToDump) {
        functionDumper.dump(func);
      }

      if (functionDumper.createdFile)
        RecompileConfig.INSTANCE.touchCMakeTimestamp();

      globalDumper.dumpGlobals();
      globalDumper.saveGlobalManifest();
    }

    // Dump types
    TypeDumper dumper = new TypeDumper(this);
    dumper.run();
  }
}
