(**************************************************************************)
(*  Copyright © 2025-2025 Stéphane Glondu <steph@glondu.net>              *)
(*                                                                        *)
(*  This program is free software: you can redistribute it and/or modify  *)
(*  it under the terms of the GNU Affero General Public License as        *)
(*  published by the Free Software Foundation, either version 3 of the    *)
(*  License, or (at your option) any later version, with the additional   *)
(*  exemption that compiling, linking, and/or using OpenSSL is allowed.   *)
(*                                                                        *)
(*  This program is distributed in the hope that it will be useful, but   *)
(*  WITHOUT ANY WARRANTY; without even the implied warranty of            *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *)
(*  Affero General Public License for more details.                       *)
(*                                                                        *)
(*  You should have received a copy of the GNU Affero General Public      *)
(*  License along with this program.  If not, see                         *)
(*  <http://www.gnu.org/licenses/>.                                       *)
(**************************************************************************)

open Core

type t = { fields : string list; map : string StringMap.t }

let empty = { fields = []; map = StringMap.empty }
let mem k m = StringMap.mem (String.lowercase_ascii k) m.map
let find k m = StringMap.find (String.lowercase_ascii k) m.map

let add k v m =
  let k' = String.lowercase_ascii k in
  let fields = if StringMap.mem k' m.map then m.fields else k :: m.fields in
  let map = StringMap.add k' v m.map in
  { fields; map }

let remove k m =
  let k' = String.lowercase_ascii k in
  if StringMap.mem k' m.map then
    let fields =
      List.filter (fun x -> String.lowercase_ascii x <> k') m.fields
    in
    let map = StringMap.remove k' m.map in
    { fields; map }
  else m

let filter f m =
  let fields, map =
    List.fold_left
      (fun (fields, map) k ->
        if f k then (k :: fields, map)
        else (fields, StringMap.remove (String.lowercase_ascii k) map))
      ([], m.map) (List.rev m.fields)
  in
  if map == m.map then m else { fields; map }

let pp outc m =
  List.iter
    (fun k ->
      let v = StringMap.find (String.lowercase_ascii k) m.map in
      Format.fprintf outc "%s: %s\n" k v)
    (List.rev m.fields);
  Format.fprintf outc "\n"
