package re3lib;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;

import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;

public class Utils {
  public static void headerGuardPre(PrintWriter writer, String tag) {
    writer.println("#ifndef GH_GENERATED_" + tag + "_H");
    writer.println("#define GH_GENERATED_" + tag + "_H");
    writer.println();
  }

  public static void headerGuardPost(PrintWriter writer, String tag) {
    writer.println("#endif // GH_GENERATED_" + tag + "_H");
  }

  public static String sanitizeIdentifier(String name) {
    return name.replaceAll("[^a-zA-Z0-9_]", "_");
  }

  public static HashSet<String> loadSimpleBlacklist(String path) {
    File file = new File(path);
    HashSet<String> structBlacklist = new HashSet<>();
    try (Scanner scanner = new Scanner(file)) {
      while (scanner.hasNextLine()) {
        String line = scanner.nextLine();
        structBlacklist.add(line.trim());
      }
    } catch (FileNotFoundException e) {
      return null;
    }
    return structBlacklist;
  }

  public static void saveStructBlacklist(HashSet<String> structBlacklist, String path) throws Exception {
    String[] arr = structBlacklist.toArray(new String[0]);
    Arrays.sort(arr);
    File file = new File(path);
    try (PrintWriter writer = new PrintWriter(file)) {
      for (String structName : arr) {
        writer.println(structName);
      }
    }
  }

  public static HashSet<Address> loadFunctionBlacklist(String path) {
    GhidraScript script = RecompileConfig.INSTANCE.script;
    HashSet<Address> fnBlacklist = new HashSet<>();
    File blacklistFile = new File(path);
    try (Scanner scanner = new Scanner(blacklistFile)) {
      while (scanner.hasNextLine()) {
        String line = scanner.nextLine();
        // Strip comment
        String line1 = line.split("//")[0].trim();
        // Deserialize address
        Address addr = RecompileConfig.INSTANCE.currentProgram.getAddressFactory().getAddress(line1);
        fnBlacklist.add(addr);
      }
      script.println("Loaded blacklist with " + fnBlacklist.size() + " entries");
    } catch (FileNotFoundException e) {
      script.println("No blacklist found");
    }
    return fnBlacklist;
  }

  public static void saveFunctionBlacklist(HashSet<Address> fnBlacklist, String path) {
    GhidraScript script = RecompileConfig.INSTANCE.script;
    File blacklistFile = new File(path);
    try (PrintWriter writer = new PrintWriter(blacklistFile)) {
      for (Address addr : fnBlacklist) {
        writer.println(addr.toString() + " // " + script.getFunctionAt(addr).getName());
      }
    } catch (FileNotFoundException e) {
      script.println("Error saving blacklist: " + e.getMessage());
    }
  }
}
