(*********************************************************************************)
(*                OCaml-CSS                                                      *)
(*                                                                               *)
(*    Copyright (C) 2023-2024 INRIA All rights reserved.                         *)
(*    Author: Maxence Guesdon, INRIA Saclay                                      *)
(*                                                                               *)
(*    This program is free software; you can redistribute it and/or modify       *)
(*    it under the terms of the GNU General Public License as                    *)
(*    published by the Free Software Foundation, version 3 of the License.       *)
(*                                                                               *)
(*    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 General Public License for more details.                               *)
(*                                                                               *)
(*    You should have received a copy of the GNU General Public                  *)
(*    License along with this program; if not, write to the Free Software        *)
(*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA                   *)
(*    02111-1307  USA                                                            *)
(*                                                                               *)
(*    As a special exception, you have permission to link this program           *)
(*    with the OCaml compiler and distribute executables, as long as you         *)
(*    follow the requirements of the GNU GPL in regard to all of the             *)
(*    software in the executable aside from the OCaml compiler.                  *)
(*                                                                               *)
(*    Contact: Maxence.Guesdon@inria.fr                                          *)
(*                                                                               *)
(*********************************************************************************)

(** Properties *)

(**/**)
module Tid : sig type _ t = .. end
module type Tid = sig
    type t
    type _ Tid.t += Tid : t Tid.t
 end
type 'a tid = (module Tid with type t = 'a)
val gen_tid : unit -> (module Tid with type t = 's)
type ('a, 'b) teq = Teq : ('a, 'a) teq
val eq : 'r tid -> 's tid -> ('r, 's) teq option
val gen_pid : unit -> int

(**/**)

(** {2 Properties} *)


(** Parsed property values, with location and [important] flag. *)
type 'a value = {
    v : 'a T.p_value;
    loc : T.loc;
    important : bool;
}

(** A property definition. *)
type 'a prop

(** Initial (i.e. default) value of property. *)
val initial : 'a prop -> 'a

(** Name of property. *)
val name : 'a prop -> string

(** Parser to parser values for the given property. *)
val parser : 'a prop -> (T.ctx -> start:T.pos -> 'a value Angstrom.t)

(** Whether property is inherited or not. *)
val inherited : 'a prop -> bool

(** [to_string p v] applies the property's function passed at its
  creation to map a value of the type of the property to a string. *)
val to_string : 'a prop -> 'a -> string

(** [value_to_string p v] returns a string representation of the
  given value for the given property, using {!T.string_of_p_value}
  with [to_string p]. *)
val value_to_string : 'a prop -> 'a T.p_value -> string

(** Returns the property pretty-printer. *)
val pp : 'a prop -> Format.formatter -> 'a -> unit

(** Returns {!T.pp_p_value} with the pretty-printer for the given property. *)
val pp_value : 'a prop -> Format.formatter -> 'a T.p_value -> unit

(**/**)
val tid : 'a prop -> 'a tid
(**/**)

(** {2 Creating properties} *)

(** [mk_prop name v to_string parser] creates a new property [name]
  with initial value [v], the [to_string] function
  to map a value to a string and an {!Angstrom} parser. This parser
  takes a context {!T.type-ctx} and returns a value of the same type as
  [v] or fails to indicate that no value of this type could be parsed.
  Optional arguments:
  {ul
   {- [register_prop] (default is [true]) indicates whether to register
    the property so that its parser is used when encoutering a declaration
    with this property in CSS.}
   {- [inherited] (default is [false]) specifies whether the value for
    this property is inherited from parent or not. This is used in
    {{!C}computations}.}
   {- [pp] can be used to specify a pretty-printing function for values
    of this property. If none is provided, a default one is created
    using [to_string].}
  }
*)
val mk_prop :
  string -> ?register_prop:bool -> ?inherited:bool ->
  'a -> ('a -> string) -> ?pp:(Format.formatter -> 'a -> unit) ->
  (T.ctx -> 'a Angstrom.t) -> 'a prop

(** {2 Property maps} *)

module Key : sig
  type t = V : 'a prop -> t
  val compare : t -> t -> int
end

val compare_prop : 'a prop -> 'b prop -> int

module M : sig
  include Map.S with type key = Key.t
  val find_opt : 'a prop -> 'b t -> 'b option
  val add : 'a prop -> 'b -> 'b t -> 'b t
 end

val empty : 'a M.t
val fold : ('a -> 'b -> 'b) -> 'a M.t -> 'b -> 'b
val iter : ('a -> unit) -> 'a M.t -> unit
val filter : ('a -> bool) -> 'a M.t -> 'a M.t
val to_list : 'a M.t -> 'a list
val merge : 'a M.t -> 'a M.t -> 'a M.t

(** {2 Mapping properties to parsed values} *)

type binding = B : 'a prop * 'a value -> binding

type t = binding M.t

val opt : t -> 'a prop -> 'a value option
val get : t -> 'a prop -> 'a T.p_value

val add_v : t -> 'a prop -> 'a value -> t
val add : t -> 'a prop -> 'a T.p_value -> T.loc -> bool -> t
val add_vl : t -> 'a prop -> ('a * T.loc) -> t
val add_with_important :
  t -> 'a prop -> 'a T.p_value ->
   T.loc -> T.ctx -> t Angstrom.t
val set_important : t -> 'a prop -> bool -> t

val v_initial : 'a prop -> 'a value
val filter_inherited : t -> t

val is_var : 'a prop -> bool

module type Prop_space =
 sig
    type p = P : 'a prop -> p
    val space_name : string
    val register : 'a prop -> unit
    val register_prop_parser :
      string -> (T.ctx -> T.pos -> t -> t Angstrom.t) ->  unit
    val mk_prop :
      string -> ?register_prop:bool -> ?inherited:bool ->
        'a -> ('a -> string) -> ?pp:(Format.formatter -> 'a -> unit) ->
        (T.ctx -> 'a Angstrom.t) -> 'a prop
    val props : unit -> p M.t
    val get_var_prop : string -> string prop option
    val parse_and_add_by_name :
      string ->
        (T.ctx -> Stdlib.Lexing.position -> t -> t Angstrom.t) option
    val parse_and_add :
      'a prop ->
        (T.ctx -> Stdlib.Lexing.position -> t -> t Angstrom.t) option
    val mk_var_prop : string -> string prop
  end

val mk_prop_space : string -> (module Prop_space)
module Css : Prop_space

(** {2:predefined Predefined CSS properties (in {!module-Css} space)} *)

val accent_color : T.accent_color prop
val align_content : T.align_content prop
val align_items : T.align_items prop
val align_self : T.align_self prop
val aspect_ratio : T.aspect_ratio prop
val background_attachment : T.background_attachment prop
val background_clip : T.background_clip prop
val background_color : T.background_color prop
val background_image : T.background_image prop
val background_origin : T.background_origin prop
val background_position_x : T.background_position_x prop
val background_position_y : T.background_position_y prop
val background_repeat : T.background_repeat prop
val background_size : T.background_size prop
val block_size : T.size prop
val border_collapse : T.border_collapse prop
val border_spacing : T.border_spacing prop
val border_top : T.color prop * T.line_style prop * T.border_width prop
val border_top_color : T.color prop
val border_top_style : T.line_style prop
val border_top_width : T.border_width prop
val border_right : T.color prop * T.line_style prop * T.border_width prop
val border_right_color : T.color prop
val border_right_style : T.line_style prop
val border_right_width : T.border_width prop
val border_bottom : T.color prop * T.line_style prop * T.border_width prop
val border_bottom_color : T.color prop
val border_bottom_style : T.line_style prop
val border_bottom_width : T.border_width prop
val border_left : T.color prop * T.line_style prop * T.border_width prop
val border_left_color : T.color prop
val border_left_style : T.line_style prop
val border_left_width : T.border_width prop
val color : T.color prop
val display : T.display prop
val flex_basis : T.flex_basis prop
val flex_direction : T.flex_direction prop
val flex_grow : T.number prop
val flex_shrink : T.number prop
val flex_wrap : T.flex_wrap prop
val font_family : T.font_family prop
val font_kerning : T.font_kerning prop
val font_size : T.font_size prop
val font_stretch : T.font_stretch prop
val font_style : T.font_style prop
val font_variant_alternates : T.font_variant_alternates prop
val font_variant_caps : T.font_variant_caps prop
val font_variant_east_asian : T.font_variant_east_asian prop
val font_variant_emoji : T.font_variant_emoji prop
val font_variant_ligatures : T.font_variant_ligatures prop
val font_variant_numeric : T.font_variant_numeric prop
val font_variant_position : T.font_variant_position prop
val font_weight : T.font_weight prop
val height : T.height prop
val inline_size : T.size prop
val justify_content : T.justify_content prop
val justify_items : T.justify_items prop
val justify_self : T.justify_self prop
val line_height : T.line_height prop
val list_style_image : T.list_style_image prop
val list_style_position : T.list_style_position prop
val list_style_type : T.list_style_type prop
val margins : T.margin prop * T.margin prop * T.margin prop * T.margin prop
val margin_top : T.margin prop
val margin_right : T.margin prop
val margin_bottom : T.margin prop
val margin_left : T.margin prop
val max_height : T.max_size prop
val max_width : T.max_size prop
val min_height : T.size prop
val min_width : T.size prop
val opacity : T.opacity prop
val paddings :
  T.padding prop * T.padding prop * T.padding prop * T.padding prop
val padding_top : T.padding prop
val padding_right : T.padding prop
val padding_bottom : T.padding prop
val padding_left : T.padding prop
val position : T.position prop
val text_align : T.text_align prop
val text_align_last : T.text_align_last prop
val vertical_align : T.vertical_align prop
val visibility : T.visibility prop
val white_space : T.white_space prop
val word_spacing : T.word_spacing prop
val width : T.width prop

(**/**)
val is_prefix : s:string -> pref:string -> bool


