(*
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *)

open! IStd
open PolyVariantEqual
module F = Format
module L = Logging

let multilink_file_name = "multilink.txt"

type t = string String.Table.t

let add multilinks fname = String.Table.set multilinks ~key:(Filename.basename fname) ~data:fname

let create () : t = String.Table.create ~size:1 ()

(* Cache of multilinks files read from disk *)
let multilink_files_cache = String.Table.create ~size:1 ()

let reset_cache () = String.Table.clear multilink_files_cache

let read ~dir : t option =
  let multilink_fname = Filename.concat dir multilink_file_name in
  match Utils.read_file multilink_fname with
  | Error _ ->
      None
  | Ok lines ->
      let links = create () in
      List.iter
        ~f:(fun line -> String.Table.set links ~key:(Filename.basename line) ~data:line)
        lines ;
      String.Table.set multilink_files_cache ~key:dir ~data:links ;
      Some links


(* Write a multilink file in the given directory *)
let write multilinks ~dir =
  let fname = Filename.concat dir multilink_file_name in
  let outc = Out_channel.create fname in
  String.Table.iteri
    ~f:(fun ~key:_ ~data:src -> Out_channel.output_string outc (src ^ "\n"))
    multilinks ;
  Out_channel.close outc


let lookup ~dir =
  try Some (String.Table.find_exn multilink_files_cache dir)
  with Not_found_s _ | Caml.Not_found -> read ~dir


let resolve fname =
  let fname_s = DB.filename_to_string fname in
  if Sys.file_exists fname_s = `Yes then fname
  else
    let base = Filename.basename fname_s in
    let dir = Filename.dirname fname_s in
    match lookup ~dir with
    | None ->
        fname
    | Some links -> (
      try DB.filename_from_string (String.Table.find_exn links base)
      with Not_found_s _ | Caml.Not_found -> fname )
