#scope_file;

#run {
   set_build_options_dc(.{ do_output = false, write_added_strings = false });

   create_opts :: (visitor: Declaration_Visitor = null) -> Generate_Bindings_Options {
      opts: Generate_Bindings_Options;
      opts.visitor                       = visitor;
      opts.add_generator_command         = false;
      opts.generate_library_declarations = false;
      array_add(*opts.extra_clang_arguments, "-x", "c");
      return opts;
   }


   print(".. generating bindings (platform: %)\n\n", OS);

   opts := create_opts(rl_enum_visitor);

   #if OS == .WINDOWS {
      array_add(*opts.libpaths, "win");
   } else #if OS == .LINUX {
      array_add(*opts.libpaths, "linux");
   } else #if OS == .MACOS {
      array_add(*opts.libpaths, "mac");
   } else {
      assert(false, "unsupported OS: %", OS);
   }

   array_add(*opts.libnames, "libraylib");

   array_add(*opts.source_files, "lib/raylib.h", "lib/raymath.h");
   assert(generate_bindings(opts, "raylib.jai"), "unable to generate bindings for raylib!");

   libpaths := opts.libpaths;
   libnames := opts.libnames;

   opts = create_opts();
   opts.libpaths = libpaths;
   opts.libnames = libnames;

   array_add(*opts.strip_prefixes, "rl", "RL");
   array_add(*opts.source_files, "lib/rlgl.h");
   array_add(*opts.extra_clang_arguments, "-x", "c");

   assert(generate_bindings(opts, "./rlgl/rlgl.jai"), "unable to generate bindings for raylib!");
}

rl_enum_visitor :: (decl: *Declaration, parent: *Declaration) -> Declaration_Visit_Result {
   replace_type :: (args: []*Declaration, arg_name: string, hardcoded_type: string) {
      for args if it.name == arg_name {
         change_type_to_enum(it, hardcoded_type);
         return;
      }
   }

   if decl.kind == {
      case .TYPEDEF;
         td := decl.(*Typedef);
         if td.name == {
            case "TraceLogCallback";
               ptr := td.type.pointer_to;
               replace_type(ptr.type_of_function.arguments, "logLevel", "TraceLogLevel");
         }

      case .FUNCTION;
         func := decl.(*Function);
         ftype := func.type.type_of_function;

         if func.name == {
            case "IsWindowState"; #through;
            case "SetWindowState"; #through;
            case "ClearWindowState"; #through;
            case "SetConfigFlags";
               replace_type(ftype.arguments, "flags", "ConfigFlags");

            case "IsKeyPressed"; #through;
            case "IsKeyPressedRepeat"; #through;
            case "IsKeyDown"; #through;
            case "IsKeyReleased"; #through;
            case "IsKeyUp"; #through;
            case "SetExitKey";
               replace_type(ftype.arguments, "key", "KeyboardKey");

            case "IsGamepadButtonPressed"; #through;
            case "IsGamepadButtonDown"; #through;
            case "IsGamepadButtonReleased"; #through;
            case "IsGamepadButtonUp";
               replace_type(ftype.arguments, "button", "GamepadButton");

            case "GetGamepadAxisMovement";
               replace_type(ftype.arguments, "axis", "GamepadAxis");

            case "IsMouseButtonPressed"; #through;
            case "IsMouseButtonDown"; #through;
            case "IsMouseButtonReleased"; #through;
            case "IsMouseButtonUp";
               replace_type(ftype.arguments, "button", "MouseButton");

            case "IsGestureDetected";
               replace_type(ftype.arguments, "gesture", "Gesture");
            case "SetGesturesEnabled";
               replace_type(ftype.arguments, "flags", "Gesture");

            case "GetGestureDetected";
               real := New(CType);
               real.hardcoded_jai_string = "Gesture";
               ftype.return_type = real;

            case "UpdateCamera";
               replace_type(ftype.arguments, "mode", "CameraMode");

            case "LoadImageRaw"; #through;
            case "GetPixelColor"; #through;
            case "GetPixelDataSize"; #through;
            case "SetPixelColor";
               replace_type(ftype.arguments, "format", "PixelFormat");

            case "ImageFormat";
               replace_type(ftype.arguments, "newFormat", "PixelFormat");

            case "LoadTextureCubemap";
               replace_type(ftype.arguments, "layout", "CubemapLayout");

            case "SetTextureFilter";
               replace_type(ftype.arguments, "filter", "TextureFilter");

            case "SetTextureWrap";
               replace_type(ftype.arguments, "wrap", "TextureWrap");

            case "SetMaterialTexture";
               replace_type(ftype.arguments, "mapType", "MaterialMapIndex");
         }
   }

   return .STOP;
};

#import "File";
#import "Basic";
#import "String";
#import "Compiler";
#import "Hash_Table";
#import "Bindings_Generator";
