struct

  module Gatk_config () = struct
    type t = {
      
      (** The name of the configuration, specific to Biokepi. *)

      name: string;

      
      (** MalformedReadFilter options.

This filter is applied automatically by all GATK tools in order to protect them from crashing on reads that are grossly malformed. There are a few issues (such as the absence of sequence bases) that will cause the run to fail with an error, but these cases can be preempted by setting flags that cause the problem reads to also be filtered. *)


      
      (** Ignore reads with CIGAR containing the N operator, instead of failing with an error *)

      filter_reads_with_n_cigar: bool;
      
      (** Ignore reads with mismatching numbers of bases and base qualities, instead of failing with an error.*)

      filter_mismatching_base_and_quals: bool;
      
      (** Ignore reads with no stored bases (i.e. '*' where the sequence should be), instead of failing with an error *)

      filter_bases_not_stored: bool;

      
      (** Other parameters: *)

      parameters: (string * string) list;
    }

    let name t = t.name

    let to_json t: Yojson.Basic.json =
      let {name;
           filter_reads_with_n_cigar;
           filter_mismatching_base_and_quals;
           filter_bases_not_stored;
           parameters} = t in
      `Assoc [
        "name"`String name;
        "filter_reads_with_N_cigar"`Bool filter_reads_with_n_cigar;
        "filter_mismatching_base_and_quals"`Bool filter_mismatching_base_and_quals;
        "filter_bases_not_stored"`Bool filter_bases_not_stored;
        "parameters",
        `Assoc (List.map parameters ~f:(fun (a, b) -> a, `String b));
      ]

    let render {name;
                filter_reads_with_n_cigar;
                filter_mismatching_base_and_quals;
                filter_bases_not_stored;
                parameters} =
      (if filter_reads_with_n_cigar
       then "--filter_reads_with_N_cigar" else "") ::
      (if filter_mismatching_base_and_quals
       then "--filter_mismatching_base_and_quals" else "") ::
      (if filter_bases_not_stored
       then "--filter_bases_not_stored" else "") ::
      List.concat_map parameters ~f:(fun (a, b) -> [a; b])
      |> List.filter ~f:(fun s -> not (String.is_empty s))

    let default =
      {name = "default";
       filter_reads_with_n_cigar = false;
       filter_mismatching_base_and_quals = false;
       filter_bases_not_stored = false;
       parameters = []}
  end

  module Indel_realigner = struct
    include Gatk_config ()
  end

  module Realigner_target_creator = struct
    include Gatk_config ()
  end

  module Bqsr = struct
    include Gatk_config ()
  end

  module Print_reads = struct
    include Gatk_config ()
  end

  type indel_realigner = (Indel_realigner.t * Realigner_target_creator.t)
  type bqsr = (Bqsr.t * Print_reads.t)

  let default_indel_realigner = (Indel_realigner.default, Realigner_target_creator.default)
  let default_bqsr = (Bqsr.default, Print_reads.default)


  module Mutect2 = struct
    type t = {
      name: string;
      use_dbsnp: bool;
      use_cosmic: bool;
      additional_arguments: string list;
    }
    let create
        ?(use_dbsnp = true) ?(use_cosmic = true) name additional_arguments =
      {name; use_dbsnp; use_cosmic; additional_arguments}

    let to_json {name; use_dbsnp; use_cosmic; additional_arguments}
      : Yojson.Basic.json =
    `Assoc [
      "name"`String name;
      "use-cosmic"`Bool use_cosmic;
      "use-dbsnp"`Bool use_dbsnp;
      "additional-arguments",
      `List (List.map additional_arguments ~f:(fun s -> `String s));
    ]

    let default = create "default" []

    let compile ~reference {name; use_dbsnp; use_cosmic; additional_arguments} =
      let with_db use opt_name get_exn =
        if not use then None
        else
          let node = get_exn reference in
          Some ( [opt_name; node#product#path], [KEDSL.depends_on node])
      in
      let args, edges =
        List.filter_opt [
          with_db use_dbsnp  "--dbsnp" Reference_genome.dbsnp_exn;
          with_db use_cosmic  "--cosmic" Reference_genome.cosmic_exn;
        ]
        |> List.split
      in
      (`Arguments (List.concat args @ additional_arguments),
       `Edges (List.concat edges))

    let name t = t.name
  end


end