(**************************************************************************)
(*                                                                        *)
(*    Copyright 2014-2019 OCamlPro                                        *)
(*    Copyright 2012 INRIA                                                *)
(*                                                                        *)
(*  All rights reserved. This file is distributed under the terms of the  *)
(*  GNU Lesser General Public License version 2.1, with the special       *)
(*  exception on linking described in the file LICENSE.                   *)
(*                                                                        *)
(**************************************************************************)

(** Handles graphs of actions (package changes), based on ocamlgraph *)

open OpamTypes

module type ACTION = sig
  type package
  module Pkg: GenericPackage with type t = package
  include OpamParallel.VERTEX with type t = package action
  val to_string: [< t ] -> string
  val to_aligned_strings:
    ?explicit:bool -> ?append:(package -> string) -> [< t ] list ->
    string list list
  module Set: OpamStd.SET with type elt = package action
  module Map: OpamStd.MAP with type key = package action
end

module MakeAction (P: GenericPackage) : ACTION with type package = P.t and type t = P.t OpamTypes.action

module type SIG = sig
  type package
  include OpamParallel.GRAPH with type V.t = package OpamTypes.action

  (** Reduces a graph of atomic or concrete actions (only removals, installs and
      builds) by turning removal+install to reinstalls or up/down-grades, best
      for display. Dependency ordering won't be as accurate though, as there is
      no proper ordering of (reinstall a, reinstall b) if b depends on a. The
      resulting graph contains at most one action per package name.

      There is no guarantee however that the resulting graph is acyclic. *)
  val reduce: t -> t

  (** Expand install actions, adding a build action preceding them.
      The argument [noop_remove] is a function that should return `true`
      for package where the `remove` action is known not to modify the
      filesystem (such as `conf-*` package).
      The argument [sources_needed p] is a function that should return packages
      list that require fetching same shared source (singleton when no source
      is shared), and an empty list if no fetching is required for that package
      (packages that do not require it are typically up-to-date pins or
      "in-place" builds). *)
  val explicit:
    ?noop_remove:(package -> bool) ->
    sources_needed:(package -> package list) ->
    t -> t

  (** Folds on all recursive successors of the given action, including itself,
      depth-first. *)
  val fold_descendants: (V.t -> 'a -> 'a) -> 'a -> t -> V.t -> 'a
end

module Make (A: ACTION) : SIG with type package = A.package

(** Some messages that may be used for displaying actions. Single utf8 chars if
    the corresponding option is set, otherwise words. *)
val action_strings:
  ?utf8:bool -> 'a action -> string

val symbol_of_action: 'a action -> string

val name_of_action: 'a action -> string

(** Colorise string according to the action *)
val action_color: 'a action -> string -> string

(** Returns a noun corresponding to the action name, singular and plural
    forms *)
val noun_of_action: 'a action -> string * string
