:- module(config_opts).
:- export request_notification_body / 3.
:- export register_option_body / 4.
:- export request_notification / 2.
:- export get_all_options / 1.
:- export get_option / 2.
:- export set_option / 2.
:- export register_option / 3.
:- tool(request_notification / 2,request_notification_body / 3).
:- tool(register_option / 3,register_option_body / 4).
:- comment(request_notification_body / 3, hidden).
:- comment(register_option_body / 4, hidden).
:- comment(summary, "Library for managing configuration options for libraries and applications").
:- comment(desc, html("   This library provides a centralised mechanism for managing configuration\n   options for other libraries and applications.  Such options range from\n   turning logging on and off and specifying what statistics to collect and\n   print, to which redundant constraints and search strategies to use.<P>\n\n   A software component registers the fact that it supports an option by\n   calling register_option/3.  An option's value can then be set and\n   retrieved through set_option/2 and get_option/2, respectively.  And any\n   party wishing to be notified when an option's value changes can achieve\n   this by calling request_notification/2.<P>\n\n   The values and associated parameters of configuration options are\n   persistent across backtracking.  Values are copied when set and\n   retrieved, which means that any non-ground values will contain fresh\n   copies of variables when retrieved rather than the original ones.<P>\n\n   Note that at the moment configuration option settings are global, which\n   makes them unsuitable for some purposes (e.g. any library that might be\n   used by more than one component of a software system if those components\n   may wish to use different settings for that library).  We hope to address\n   this issue in a future version of this library, probably by allowing the\n   use of handles to manage multiple sets of options.<P>\n\n   This library is still experimental and is expected to evolve.  Feedback,\n   suggestions, problem reports, etc. welcome.<P>\n")).
:- comment(author, "Warwick Harvey").
:- comment(status, "evolving").
:- comment(get_all_options / 1, [summary : "Retrieves the current values of all options", args : ["OptionList" : "List of (Module:Name)-Value terms"], amode : get_all_options(?), see_also : [register_option / 3, set_option / 2, get_option / 2], desc : html("   This predicate retrieves the current values of all options, returning a\n   list of terms of the form (Module:Name)-Value, where Name is the name of\n   the option, Module is the module that defined (registered) it, and Value\n   is the current value of the option.<P>\n\n   The values are copied during retrieval, which means that if they are\n   non-ground then they will contain fresh copies of variables rather than\n   the original ones (or sharing with other retrieved copies).\n")]).
:- comment(get_option / 2, [summary : "Retrieves the current value of an option", args : ["Name" : "Name of the option", "Value" : "Value to be given to the option"], amode : get_option(++, ?), see_also : [register_option / 3, set_option / 2], desc : html("   This predicate retrieves the current value Value of the option with name\n   Name.  The option must have already been registered with\n   register_option/3.<P>\n\n   Value is copied during retrieval, which means that if it is non-ground\n   then it will contain fresh copies of variables rather than the original\n   ones (or sharing with other retrieved copies).\n")]).
:- comment(register_option / 3, [summary : "Register an option", args : ["Name" : "Name of the option (any ground term)", "InitialValue" : "Initial value to be given to option", "Options" : "List of options related to this option"], amode : register_option(++, ?, +), see_also : [set_option / 2, get_option / 2, get_all_options / 1, request_notification / 2], desc : html("   This predicate sets up an option with name Name and initial value\n   InitialValue.  Name must be ground; InitialValue can be any term but\n   should normally be ground, since it will be copied when stored and\n   retrieved, which means that any retrieved non-ground value will contain\n   fresh copies of variables rather than the original ones.<P>\n\n   Options must be a list.  The following terms may appear in this list:\n   <DL>\n   <DT>validation_pred(Pred/Arity)</DT>\n       <DD>Pred is used to validate any value to be assigned to the option.\n       This can be used to ensure that only legal values are assigned to the\n       option.  Arity must be either 1 or 2, corresponding to the arity of\n       the predicate to be called: if Arity is 1 then Pred(NewValue) is\n       called, if Arity is 2 then Pred(Name, NewValue) is called; Name is\n       the name of the option and NewValue is the value to be validated.  If\n       the call to Pred succeeds then the value is assigned to the option;\n       if it fails the value is not assigned.  Any choice points left by the\n       call to Pred are pruned upon success.<P>\n\n       Only one validation predicate may be defined for any option; if more\n       are specified then each replaces the one before it.</DD>\n\n   <DT>notify_pred(Pred)</DT>\n       <DD>Specifies that Pred(Name, OldValue, NewValue) should be called\n       whenever the value of the option Name is changed.  OldValue is the\n       old value of the option that has just been replaced and NewValue is\n       the new value that has just been assigned.  Pred should not modify\n       OldValue or NewValue in any way, as this may interfere with other\n       notification predicates.  Note that any choice points left by the\n       call to Pred are pruned upon success.<P>\n\n       See also request_notification/2.</DD>\n   </DL>")]).
:- comment(request_notification / 2, [summary : "Requests that a predicate be called when an option changes", args : ["Name" : "Name of the option", "Pred" : "Predicate to call"], amode : request_notification(++, ++), see_also : [register_option / 3, set_option / 2], desc : html("   Specifies that Pred(Name, OldValue, NewValue) should be called whenever\n   the value of the option Name is changed.  OldValue is the old value of\n   the option that has just been replaced and NewValue is the new value that\n   has just been assigned.  Pred should not modify OldValue or NewValue in\n   any way, as this may interfere with other notification predicates.  Note\n   also that any choice points left by the call to Pred are pruned upon\n   success.\n")]).
:- comment(set_option / 2, [summary : "Gives a new value to an option", args : ["Name" : "Name of the option", "Value" : "Value to be given to the option"], amode : set_option(++, ?), see_also : [register_option / 3, get_option / 2, request_notification / 2], desc : html("   This predicate gives a new value Value to the option with name Name.  The\n   option must have already been registered with register_option/3.  If the\n   option has an associated validation predicate (see register_option/3),\n   then this is called before the option is given the new value, and if the\n   validation predicate fails the value is not assigned and set_option/2\n   fails.<P>\n\n   If the new value is successfully set, then any notification predicates\n   associated with the option (see request_notification/2 and\n   register_option/3) are called.<P>\n\n   The value set is persistent across backtracking.  Value is copied during\n   setting, which means that if it is non-ground then it will contain fresh\n   copies of variables rather than the original ones when retrieved later.\n")]).
