(*********************************************************************************)
(*                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                                          *)
(*                                                                               *)
(*********************************************************************************)

module Log = Log
module T = T
module U = U
module Vp = Vp
module S = S
module Sp = Sp
module P = P
module Sh = Sh
module C = C
module Kw = Kw

(** A CSS structure is a list of {!S.statement}s. *)
type 'ns css = 'ns S.statement list

(** [parse_string parser string] parses the given [string] with given [parser],
  creating the required {!T.type-ctx} to compute locations.
  Optional argument [fname] can be used to specify a filename
  in the [fname] field of {!T.pos} structures.
*)
let parse_string : ?fname:string -> (T.ctx -> 'a Angstrom.t) -> string -> ('a, string) result =
  fun ?fname parser str ->
  let ctx = T.string_ctx ?fname str in
  let parser = Vp.handle_end parser ctx in
  Angstrom.parse_string ~consume:Angstrom.Consume.All parser str

(** [parse_css string] will parse the CSS statements in the given [string].
  Optional argument [prop_space] can be used to specify a property space
  (default is {!P.Css}).
  Optional argument [fname] can be used to specify a filename
  in the [fname] field of {!T.pos} structures.
  Raises {!T.Error} in case of error.*)
let parse_css ?(prop_space=(module P.Css:P.Prop_space)) ?fname str : string css =
  let parser = Sp.statements prop_space in
  match parse_string ?fname parser str with
  | Ok v -> v
  | Error msg -> T.error (T.Parse_error (None, T.Other msg))

(** Namespaces map strings to IRIs. *)
type namespaces = Iri.t T.Smap.t

(** [expand_ns css] expands the namespaces in the given [css], according
  to the namespace statements in [css]. Some predefined namespaces
  can be given with [ns] optional argument. If not specified, the
  {{!S.default_ns}default namespaces} are used.*)
let expand_ns : ?ns:namespaces -> string css -> Iri.t css = S.expand_statement_list

(** [expand_nested statements] expands nested rules in [statements].
  By now, this expansion handles only nesting rules with a
  single selector nested. *)
let expand_nested : 'a css -> 'a css = S.expand_nested

(** Pretty-print the given (non-expanded) CSS to the given formatter. *)
let pp_string_css : Format.formatter -> string css -> unit =
  let to_s = function
  | ("",s) -> s
  | (ns, s) -> Printf.sprintf "%s|%s" ns s
  in
  S.pp_statement_list to_s

(** Pretty-print the given (with namespaces expanded) CSS to the given formatter. *)
let pp_iri_css : Format.formatter -> Iri.t css -> unit =
  let to_s (iri, s) =
    match Iri.to_string iri with
    | "" -> s
    | iri -> Printf.sprintf "%s|%s" iri s in
  S.pp_statement_list to_s

(** See {!C.compute_decls}. *)
let compute_decls = C.compute_decls

