// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)

#pragma once

////////////////////////////////

typedef struct LNK_InputObj
{
  struct LNK_InputObj *next;
  B32                  is_thin;
  B32                  has_disk_read_failed;
  String8              dedup_id;
  String8              path;
  String8              data;
  String8              lib_path;
} LNK_InputObj;

typedef struct LNK_InputObjList
{
  U64           count;
  LNK_InputObj *first;
  LNK_InputObj *last;
} LNK_InputObjList;

////////////////////////////////

#define LNK_MakeChunkInputIdx(obj_idx, sect_idx) (((U64)(obj_idx) << 32) | (U64)((sect_idx) & max_U32))

typedef struct LNK_Obj
{
  String8             data;
  String8             path;
  String8             lib_path;
  U64                 input_idx;
  U64                 common_symbol_size;
  COFF_MachineType    machine;
  U64                 chunk_count;
  U64                 sect_count;
  String8            *sect_name_arr;
  String8            *sect_sort_arr;
  LNK_RelocList      *sect_reloc_list_arr;
  LNK_ChunkPtr       *chunk_arr;
  LNK_SymbolList      symbol_list;
  LNK_DirectiveInfo   directive_info;
  LNK_ExportParseList export_parse;
  String8List         include_symbol_list;
  LNK_AltNameList     alt_name_list;
} LNK_Obj;

typedef struct LNK_ObjNode
{
  struct LNK_ObjNode *next;
  LNK_Obj             data;
} LNK_ObjNode;

typedef struct LNK_ObjList
{
  U64          count;
  LNK_ObjNode *first;
  LNK_ObjNode *last;
} LNK_ObjList;

typedef struct LNK_ObjNodeArray
{
  U64          count;
  LNK_ObjNode *v;
} LNK_ObjNodeArray;

////////////////////////////////

typedef struct LNK_SectDefn
{
  struct LNK_SectDefn *next;
  LNK_Obj             *obj;
  String8              name;
  COFF_SectionFlags    flags;
  U64                  idx;
} LNK_SectDefn;

typedef struct
{
  U64           count;
  LNK_SectDefn *first;
  LNK_SectDefn *last;
} LNK_SectDefnList;

typedef struct
{
  LNK_InputObj    **inputs;
  LNK_ObjNode      *obj_node_arr;
  U64               obj_id_base;
  LNK_SectDefnList *defn_arr;
  LNK_SectionTable *st;
  U64              *function_pad_min;
} LNK_ObjIniter;

typedef struct
{
  Rng1U64          *range_arr;
  LNK_ObjNode      *obj_node_arr;
  LNK_SectDefnList *defn_arr;
  LNK_SectDefnList *conf_arr;
} LNK_ObjNewSectScanner;

typedef struct
{
  LNK_SectionTable *st;
  LNK_ObjNode      *obj_arr;
  U64             **chunk_count_arr_arr;
} LNK_ChunkCounter;

typedef struct
{
  LNK_ChunkManager *cman;
  U64             **chunk_id_arr_arr;
  U64               obj_idx;
} LNK_ChunkRefAssign;

typedef struct
{
  LNK_SectionTable *st;
  Rng1U64          *range_arr;
  U64             **chunk_id_arr_arr;
  LNK_ObjNode      *obj_arr;
  LNK_ChunkList   **nosort_chunk_list_arr_arr;
  LNK_ChunkList   **chunk_list_arr_arr;
} LNK_ChunkRefAssigner;

typedef struct
{
  LNK_SymbolType   type;
  LNK_ObjNodeArray in_arr;
  LNK_SymbolList  *out_arr;
  Rng1U64         *range_arr;
} LNK_SymbolCollector;

typedef struct
{
  LNK_Obj      **obj_arr;
  String8        name;
  String8        postfix;
  B32            collect_discarded;
  LNK_ChunkList *list_arr;
} LNK_CollectObjChunksTaskData;

typedef struct
{
  Rng1U64          *range_arr;
  LNK_ObjNodeArray  in_arr;
  String8List      *out_arr;
} LNK_DefaultLibCollector;

typedef struct
{
  LNK_ObjNode  *in_arr;
  String8List  *out_arr;
  Rng1U64      *range_arr;
} LNK_ManifestDependencyCollector;

////////////////////////////////

internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...);

////////////////////////////////

internal void             lnk_input_obj_list_push_node(LNK_InputObjList *list, LNK_InputObj *node);
internal void             lnk_input_obj_list_concat_in_place(LNK_InputObjList *list, LNK_InputObjList *to_concat);
internal LNK_InputObj *   lnk_input_obj_list_push(Arena *arena, LNK_InputObjList *list);
internal LNK_InputObj **  lnk_array_from_input_obj_list(Arena *arena, LNK_InputObjList list);
internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, String8List list);
internal LNK_InputObjList lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count);

////////////////////////////////

internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, String8List list);

internal LNK_Obj **       lnk_obj_arr_from_list(Arena *arena, LNK_ObjList list);
internal LNK_ObjNodeArray lnk_obj_list_reserve(Arena *arena, LNK_ObjList *list, U64 count);
internal LNK_ChunkList *  lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8 name, String8 postfix, B32 collect_discarded);
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 *function_pad_min, U64 input_count, LNK_InputObj **inputs);

internal LNK_Chunk *       lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr);
internal LNK_SymbolArray   lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, U64 coff_symbol_count, void *coff_symbols, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block);
internal LNK_RelocList     lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count);
internal LNK_RelocList *   lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_ChunkPtr *chunk_ptr_arr, LNK_SymbolArray symbol_array);
internal LNK_DirectiveInfo lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr);

internal U32 lnk_obj_get_features(LNK_Obj *obj);
internal U32 lnk_obj_get_comp_id(LNK_Obj *obj);
internal U32 lnk_obj_get_vol_md(LNK_Obj *obj);

