package re3lib;

import java.io.File;
import java.io.IOException;

import generic.jar.ResourceFile;
import ghidra.app.decompiler.DecompInterface;
import ghidra.app.script.GhidraScript;
import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;

// A general configuration for the reman project
// including all paths, specific addresses and stuff
public class RemanConfig {
  private static final String RECOMPILE_PREFIX = "game_re";

  // Version control project root
  public final String rootDir;
  // The output directory for the recompiled game
  public final String outputDir;
  public final String typeBlacklistPath;
  public final String categoryPathBlacklistPath;
  public final String functionBlacklistPath;
  // The static memory block
  public final Address staticMemoryBlockStart;
  public final Address staticMemoryBlockEnd;

  // The path to the database file
  public final File databasePath;

  // The automatically decompiled files
  public final File dirDecompAuto;
  // The manually decompiled files (will not be overwritten by the auto
  // decompiler)
  public final File dirDecompFix;
  // The automatically generated files get written here in case a gh_fix entry
  // exists
  // usable for referencing the modified function against the auto-decompiled one
  public final File dirDecompRef;

  // The path for generated function stubs, for yet-to-be-compiled functions
  // Usefully for testing a part of the recompiled code without linker errors
  public final File dirDecompStub;

  // The CMake timestamp file, automatically touched sometimes to trigger a
  // reconfigure
  // mostly when adding new files to the project
  public final File cmakeTimestampFile;

  public final Program currentProgram;
  public final DecompileCache decompCache;

  public final GhidraScript script;

  public static RemanConfig INSTANCE;

  public static final String GLOBAL_H_FILE = "gh_global.h"; // Default filepath for globals
  public static final String GLOBAL_CXX_FILE = "gh_global.cxx"; // Default filepath for globals

  public RemanConfig(GhidraScript script) {
    staticMemoryBlockStart = script.getCurrentProgram().getAddressFactory().getAddress("00400000");
    staticMemoryBlockEnd = script.getCurrentProgram().getAddressFactory().getAddress("00843fff");

    this.script = script;

    rootDir = new File(script.getSourceFile().getAbsolutePath()).getParentFile().getParentFile().getParentFile().toString();
    outputDir = new File(rootDir, RECOMPILE_PREFIX).toString();
    script.println("Output path: " + outputDir);

    typeBlacklistPath = new File(outputDir, "type_blacklist.txt").toString();
    categoryPathBlacklistPath = new File(outputDir, "type_path_blacklist.txt").toString();
    functionBlacklistPath = new File(outputDir, "function_blacklist.txt").toString();

    databasePath = new File(outputDir, "gh.db");

    dirDecompAuto = new File(outputDir, "gh_auto");
    dirDecompFix = new File(outputDir, "gh_fix");
    dirDecompRef = new File(outputDir, "gh_ref");
    dirDecompStub = new File(outputDir, "gh_stub");

    cmakeTimestampFile = new File(outputDir, "gh_cmake_timestamp");

    currentProgram = script.getCurrentProgram();

    DecompInterface decomp = new DecompInterface();
    decomp.openProgram(currentProgram);
    decompCache = new DecompileCache(decomp, script.getMonitor());
  }

  public void createDirectories() {
    dirDecompAuto.mkdirs();
    dirDecompFix.mkdirs();
    dirDecompRef.mkdirs();
    dirDecompStub.mkdirs();
  }

  public void touchCMakeTimestamp() {
    try {
      if (!cmakeTimestampFile.exists()) {
        cmakeTimestampFile.createNewFile();
      }
      cmakeTimestampFile.setLastModified(System.currentTimeMillis());
    } catch (IOException e) {
    }
  }
}
