(*
 * <COPYRIGHT>
 * Copyright 2002 Joachim Schrod Network and Publication Consultance GmbH, Gerd Stolpmann
 *
 * <GPL>
 * This file is part of WDialog.
 *
 * WDialog 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; either version 2 of the License, or
 * (at your option) any later version.
 *
 * WDialog 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 WDialog; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * </>
 *)

(* $Id: wd_types.mli,v 3.10 2003/03/21 14:23:44 stolpmann Exp $
 * ----------------------------------------------------------------------
 *
 *)

(** This module defines the fundamental types for WDialog *)

type (+'a) dict = 'a Wd_dictionary.t
  (** The type ['a dict] is just an abbreviation for dictionaries (mappings from
   *  strings to ['a]).
   *)

type event =
    Button of string
  | Image_button of (string * int * int)
  | Indexed_button of (string * string)
  | Indexed_image_button of (string * string * int * int)
  | No_event
  | Popup_request of string (** *)
(** [ ]
 *
 *  Events are generated when the user presses a button, clicks at a hyperlink,
 *  or opens a server-generated popup window.
 *
 * - [Button n]: The button with name [n] has been pressed
 *   ([<ui:button name="n" ...>])
 * - [Image_button (n,x,y)]: The image button with name [n] has been pressed
 *   at the coordinates [(x,y)]. ([<ui:imagebutton name="n" ...>])
 * - [Indexed_button (n,i)]: The button with name [n] and index [i] has been pressed
 *   ([<ui:button name="n" index="i" ...>])
 * - [Indexed_image_button (n,i,x,y)]: The image button with name [n] and index [i]
 *   has been pressed at the coordinates [(x,y)].
 *   ([<ui:imagebutton name="n" index="i" ...>])
 * - [No_event]: This value indicates that there was no event (or no
 *   recognized event)
 * - [Popup_request s]: A server popup window has just popped up, and the contents
 *   for the window have been requested. The argument is the second argument
 *   of the "open" Javascript function that has been generated by the
 *   ui:server-popup element.
 *)


type interactors =
    { mutable ui_buttons :             string option Wd_interactor.t;
      mutable ui_imagebuttons :        string option Wd_interactor.t;
      mutable ui_anchors :             string option Wd_interactor.t;
      mutable ui_indexed_buttons :     string option Wd_interactor.t;
      mutable ui_indexed_imagebuttons :string option Wd_interactor.t;
      mutable ui_indexed_anchors :     string option Wd_interactor.t;
      mutable ui_vars :                unit Wd_interactor.t;
      mutable ui_enumvars :            (string * string option * string) list;
      mutable ui_uploads :             unit Wd_interactor.t;
    }
   (** Values of this type store the mapping from the (name,index) pairs
     * of interactor elements to the real CGI parameter names together
     * with auxiliary components.
     *
     * What's the problem? Interactor elements like [ui:a] allow the programmer
     * to identify these either by a single name (which is an arbitrary
     * string) or by a pair of a "name" and an "index" (i.e. two arbitrary
     * strings). In contrast to this, CGI parameter names are much more
     * restricted. First, these names are only strings; there is no
     * built-in representation for pairs of strings. Second, you cannot
     * use arbitrary characters within these names because of limitations
     * of the transport protocol and because of bugs in browsers. (As
     * the "multipart/form-data" representation used in the transport
     * protocol bases on the RFC 822 mail format, it is neither possible to
     * pass 8 bit values, nor to pass control characters. A known bug
     * in Netscape browsers is that the double-quote and backslash characters
     * are incorrectly represented.)
     *
     * The solution is to generate the CGI parameter names using only
     * unproblematic characters, and to keep the mapping of the original
     * [string] or [string * string] to the generated CGI name. This record
     * stores the mappings for the various namespaces. The mapping is
     * encapsulated in the {!Wd_interactor} module, and the type
     * ['a Wd_interactor.t] (where ['a] is arbitrary) represents such a mapping. The
     * CGI names are simply enumerated, and the [Wd_interactor.t] value stores only
     * the numbers (IDs) of the CGI parameters. The complete CGI name is formed
     * using a prefix and the number stored in [Wd_interactor.t]. For example,
     * ui:buttons without index have the prefix "button_"; and if the
     * ui_button record component contains entries for the IDs 0, 1, and 2,
     * the complete CGI names are "button_0", "button_1", and "button_2",
     * respectively.
     *
     * The type parameter ['a] of ['a Wd_interactor.t] is the type of the
     * auxiliary component stored with every entry. See below for the
     * meanings in every case.
     *
     * The [Wd_interactor.t] structure always maps from pairs [string * string] to
     * numeric IDs. Because of this, there are usually two mappings, one
     * for the (name,index) pairs, and one for the simple names. The record
     * components listed below that have a name with "indexed" are responsible
     * for the pairs, the corresponding component without "indexed" stores
     * the mapping for the simple case.
     *
     * The simple case is represented as [Wd_interactor.t] by using always the
     * empty string [""] as index.
     *
     * {b THE COMPONENTS ARE:}
     *
     * {ol
     * {- {b BUTTON-TYPE INTERACTORS:}
     * {ul
     * {- [ui_buttons]:          Enumerates the [ui:button] interactors
     *                           that have only a name, not an index.
     *                           CGI prefix: "button_".
     * }
     * {- [ui_indexed_buttons]:  Enumerates the [ui:button] interactors
     *                           that have both a name and an index.
     *                           CGI prefix: "xbutton_".
     * }
     * {- [ui_imagebuttons]:     Enumerates the [ui:imagebutton] interactors
     *                           that have only a name, not an index.
     *                           CGI prefix: "imagebutton_".
     * }
     * {- [ui_indexed_imagebuttons]: Enumerates the [ui:imagebutton] interactors
     *                           that have both a name and an index.
     *                           CGI prefix: "ximagebutton_".
     * }
     * {- [ui_anchors]:          Enumerates the [ui:a] interactors
     *                           that have only a name, not an index.
     *                           CGI prefix: "anchor_".
     * }
     * {- [ui_indexed_anchors]:  Enumerates the [ui:a] interactors
     *                           that have both a name and an index.
     *                           CGI prefix: "xanchor_".
     * }
     * }
     *
     * These components use the auxiliary component to store the "goto"
     * attribute of the interactor, if present.
     *
     * }
     * {- {b BOX-LIKE INTERACTORS:}
     * {ul
     * {- [ui_vars]:             Enumerates the interactors that are bound
     *                           to an object variable (i.e. they have a
     *                           [variable] attribute, like [ui:text]).
     *                           As variables allow either only non-indexed
     *                           names or only indexed names, this component
     *                           contains both interactors identified by a simple
     *                           string name and interactors identified by
     *                           (name,index) pairs; it is not possible that
     *                           there are conflicts between the two naming
     *                           methods.
     *                           CGI prefix: "var_".
     *                           This component does not have an auxiliary
     *                           component.
     * }
     * {- [ui_enumvars]:         This list enumerates the simple names
     *                           [(name, None, pg)] or pairs [(name, Some index, pg)]
     *                           that occur in checkbox, radiobutton and select
     *                           list interactors. [pg] is the name of the page
     *                           where the interactor occurs (knowing the page
     *                           is necessary for popup dialogues).
     * }
     * {- [ui_uploads]:          Enumerates the [ui:file] interactors. These
     *                           may only have a simple name.
     *                           CGI prefix: "upload_".
     *                           This component does not have an auxiliary
     *                           component.
     * }
     * }
     * }
     * }
     *)


type 'dlg poly_var_value =
    String_value   of string
  | Enum_value     of string list
  | Dialog_value   of 'dlg option
  | Dyn_enum_value of (string * string) list
  | Alist_value    of (string * 'dlg poly_var_value) list (** *)
(** [ ]
 *
 * [poly_var_value] is the type of instance variables of dialogs. There are
 * six possibilities for [poly_var_value]s:
 * - [String_value s]: The instance variable contains the string [s]
 * - [Enum_value [x1;x2;...]]: The instance variable contains an enumerator
 *   value with the internal items [x1], [x2], etc. (As variables are declared
 *   it is known which items are possible, and whether there are corresponding
 *   external values.)
 * - [Dialog_value None]: The instance variable does not contain a dialog.
 * - [Dialog_value (Some dlg)]: The variable contains the dialog dlg.
 * - [Dyn_enum_value [(x1,y1);(x2,y2);...]]: The variable contains the enumerator
 *   with internal items [x1], [x2],... and the corresponding external values
 *   [y1], [y2], ...
 * - [Alist_value [(i1,v1); (i2,v2); ...]]: The variable contains the associative
 *   list where the index [i1] is mapped to the value [v1], [i2] is mapped to [v2] etc.
 *
 * See also {!Wd_types.var_value} below.
 *)


type enum_decl =
    { enum_name : string;
      mutable enum_definition : (string * string) list;
    }
(** The type of an enumeration declaration (i.e. [ui:enumeration]). The component
 *  [enum_name] is the name of the enumeration. The component [enum_definition]
 *  is the list of the pairs of internal and external names, in the right order.
 *)


type var_type_name =
    String_type
  | Enum_type of enum_decl
  | Dialog_type
  | Dyn_enum_type    (** *)
(** The different variable types *)


type 'dlg poly_var_decl =
    { var_name : string;
      var_type : var_type_name;
      var_default : 'dlg poly_var_value option;
      var_temporary : bool;
      var_associative : bool;
      var_protected : bool;
    }
(** This record describes variable declarations. [var_name] contains the name of the
 * variable. [var_type] is the declared type according to the [type] attribute.
 * [var_default] contains either [None], in which case no special initial value is
 * declared, or [Some v], where [v] is the initial value. [var_temporary] corresponds
 * to the [temporary] attribute, [var_associative] to the [associative] attribute,
 * and finally [var_protected] to the [protected] attribute.
 *)


type response_header =
    { mutable rh_status : Netcgi_types.status;
      mutable rh_content_type : string;
      mutable rh_cache : Netcgi_types.cache_control;
      mutable rh_filename : string option;
      mutable rh_language : string option;
      mutable rh_script_type : string option;
      mutable rh_style_type : string option;
      mutable rh_set_cookie : Netcgi_types.cgi_cookie list;
      mutable rh_fields : (string * string list) list;
    }
(** This record contains the CGI header of the response. It is initialized
 *  quite early and can be modified while executing the request. The fields
 *  correspond to the arguments of the method [set_header] of the class
 *  type [cgi_activation], defined in [Netcgi_types].
 *)

type debug_mode_style =
  [ `Fully_encoded
  | `Partially_encoded
  ]
(** Whether the generated HTML comments do escape HTML meta characters
 *  always ([`Fully_encoded]), or only partially ([`Partially_encoded]).
 *)

type environment =
    { (* Overall way of operation: *)
      debug_mode : bool;
      debug_mode_style : debug_mode_style;
      prototype_mode : bool;
      server_popup_mode : bool;
      (* Web variables *)
      self_url : string;
      response_header : response_header;
      cgi : Netcgi_types.cgi_activation;
    }
(** This record contains data that may be different for every CGI request. The
 *  [debug_mode] and [prototype_mode] components are true iff the corresponding
 *  mode is switched on. The [server_popup_mode] is true iff the current request
 *  is a popup request. [self_url] is the URL that invokes the CGI recursively.
 *  [cgi] contains the full CGI request. The [request_header] is the 
 *  designated header of the HTTP response.
 *)


type trans_vars =
    { mutable within_popup : bool;
      mutable current_page : string;
      mutable popup_env_initialized : bool;
      mutable condition_code : bool;
              (* last result of <ui:if>, <ui:ifvar>, <ui:iflang> *)
      mutable serialize_session : unit -> string;
    }
(** This record is private for the transformation engine. *)


(** This class type contains the dialog declaration *)
class type dialog_decl_type =
  object ('self)

    (* PUBLIC *)
    method name : string
      (** The name of the dialog *)

    method enumeration : string -> enum_decl
      (** Returns the declared enumeration *)

    method variable_names : string list
      (** Returns the names of all declared variables *)

    method variable : string -> dialog_type poly_var_decl
      (** Returns a single variable declaration *)

    method page_names : string list
      (** Returns the names of all declared pages *)

    method page : string -> syntax_tree_type
      (** Returns the XML tree of the demanded page (i.e. the [ui:page] node) *)

    method page_is_declared_as_popup : string -> bool
      (** Returns whether the page is declared as popup page (attribute
       *  [popup]
       *)

    method start_page : string
      (** Returns the name of the start page *)

    method default_context : syntax_tree_type dict
      (** Returns the default context of the dialog, i.e. the context parameters
       *  that are declared by the [ui:context] element occurring directly in
       *  the [ui:dialog] element, and not in a certain page.
       *)

    method language_variable : string option
      (** Returns [Some v] if a language variable called [v] is declared, or
       *  [None] if no such variable exists.
       *)

    (* RESTRICTED *)

    (**/**)

    method set_name : string -> unit
    method set_start_page : string -> unit
    method add_enumeration : enum_decl -> unit
    method add_variable : dialog_type poly_var_decl -> unit
    method add_page : string -> syntax_tree_type -> unit
    method set_default_context : syntax_tree_type dict -> unit
    method set_language_variable : string -> unit
  end

(** This class contains the dialog instance *)
and virtual dialog_type =
  object ('self)

    method copy : dialog_type
      (** return a copy of the dialog *)
    method name : string
      (** return the name of the dialog *)
    method page_name : string
      (** return the name of the current page *)
    method page_names : string list
      (** returns the names of all defined pages of this dialog *)
    method variable : string -> dialog_type poly_var_value
      (** [variable n]: Get the variable with name [n], or raise 
       * [No_such_variable]. The name [n] cannot only refer to variables
       * declared in this dialog, but also to variables of subdialogs
       * using the dot notation: "name1.name2...nameN". Here, [name1]
       * must be a dialog variable, and [name2] a variable of this
       * subdialog, and so on, until the final variable [nameN] is
       * reached, whose value is returned. - The dot notation is accepted
       * by the following methods, too.
       *)
    method variable_decl : string -> dialog_type poly_var_decl
      (* [variable_decl n] returns the declaration of the variable [n].
       * Raises [Not_found] if there is no declaration. Note that the
       * dot notation is allowed in contrast to [declaration # variable n].
       *)
    method string_variable : string -> string
      (** [string_variable n]: Get the contents of the string variable [n].
       * Raise [No_such_variable] if the variable does not exist. [Runtime_error]
       * if the variable is not a string.
       *)
    method enum_variable : string -> string list
      (** [enum_variable n]: Get the contents of the enumerator variable [n].
       * The enumerator must have been declared. The returned list contains
       * only the internal values.
       * Raise [No_such_variable] if the variable does not exist. [Runtime_error]
       * if the variable is not a declared enumerator.
       *)
    method dyn_enum_variable : string -> (string * string) list
      (** [dyn_enum_variable n]: Get the contents of the enumerator variable [n].
       * The enumerator may be dynamic or may be declared. The returned
       * list contains both the internal and the external values.
       * Raise [No_such_variable] if the variable does not exist. [Runtime_error]
       * if the variable is not an enumerator.
       *)
    method dialog_variable : string -> dialog_type option
      (** [dialog_variable n]: Get the contents of the dialog variable [n].
       * Raise [No_such_variable] if the variable does not exist.
       * [Runtime_error] if the variable is not a dialog.
       *)
    method alist_variable : string -> (string * dialog_type poly_var_value) list
      (** [alist_variable n]: Get the contents of the associative variable [n].
       * Raise [No_such_variable] if the variable does not exist.
       * [Runtime_error] if the variable is not an alist.
       *)
    method lookup_string_variable : string -> string -> string
    method lookup_enum_variable : string -> string -> string list
    method lookup_dyn_enum_variable : string -> string -> (string * string) list
    method lookup_dialog_variable : string -> string -> dialog_type option
      (** [lookup_]*[_variable n x]: Get the contents of the associative
       * variable [n] at index [x].
       * [No_such_variable] if the variable does not exist.
       * [Not_found] if the variable is undefined at [x].
       * [Runtime_error] if the variable has the wrong type.
       *)
    method set_variable : string -> dialog_type poly_var_value -> unit
      (** [set_variable n v]: Sets the variable [n] to the value [v]. The value [v]
       * must be compatible to the declared type of the variable.
       * [No_such_variable] if the variable does not exist.
       * [Runtime_error] if the variable is not compatible.
       *)
    method unset_variable : string -> unit
      (** [unset_variable n]: Sets the variable [n] to the declared default
       * value.
       * If the default is not declared, the following default values apply:
       * For strings: the default is the empty string.
       * For enumerators: the default is the empty list.
       * For dialogs: the default is that the value does not exist.
       *)
    method lookup_uploaded_file : string -> Netcgi_types.cgi_argument option
      (** [lookup_uploaded_file name]:
       * Checks whether the file upload box [name] was used. If so,
       * [Some arg], where [arg] is the transporting CGI argument is returned.
       * If the box was not used, but the box exists, [None] is returned.
       * Raises a [Runtime_error] if the named box does not exist.
       *
       * {b Important note:} Uploaded files are not persistent. This means that
       * they are only existent in the [handle] phase, not during initialization
       * nor the [prepare_page] phase. You get a failure
       * "Upload.get: not initialized" if you try to access uploaded files
       * in the wrong moment.
       *)
    method dump : Format.formatter -> unit
	(** [dump f] output a textual description of the current state into
	 * formatter [f]. (A debugging aid.)
	 *)
    method next_page : string
      (** Returns the name of the designated next page. *)
    method set_next_page : string -> unit
      (** Sets the name of the designated next page *)
    method event : event
      (** returns the event that just has happened *)
    method is_server_popup_request : bool
      (** Returns whether someone invoked [set_server_popup_request] before.
       * This is usually done if an dialog is restored for a server-driven
       * popup window (tag [ui:server-popup]).
       *)
    method serialize : string
      (** Returns the state of this dialog as string *)
    method unserialize : string -> unit
      (** Sets the state of this dialog from the string which must be a
       * previously serialized dialog.
       *)

    method environment : environment
      (** Return the environment of the current CGI activation *)
    method declaration : dialog_decl_type
      (** Return the declaration of this dialog *)
    method application : application_type
      (** Return the application *)
    method universe : universe_type
      (** Return the universe *)

    (*********************************************************************)

    (** {b The following methods must be defined in subclasses:} *)

    method virtual prepare_page : unit -> unit
      (** This method is invoked just before a new output page is generated.
       *
       * {b Preconditions:}
       *
       * The method [page_name] returns the name of this page.
       * The method [event] still returns the action last happened, but
       * the name of the page where this action happened is lost. It may
       * be interesting whether the last event was [No_event] because this
       * indicates that the page is the initial page of the dialog.
       *
       * This method should set any variables which are necessary to
       * generate the new page (mostly variable containing HTML fragments).
       * Furthermore, any state that needs to be saved should be put into
       * variables, too.
       *)
    method virtual handle : unit -> unit
      (** This method is invoked just after the user triggered an event (e.g.
       * pressed a button).
       *
       * {b Preconditions:}
       * The method [page_name] returns the name of the page that was visible
       * while the event was triggered.
       * The method [event] returns the description of the event.
       *
       * {b Postconditions:}
       * The method may set the next page to display by invoking
       * [set_next_page]; if it does not then the default will be used.
       * The default is either specified by the XML element describing
       * the interactor that triggered the event, or the default is
       * otherwise this page again.
       *
       * This method should modify the variables according to the event
       * that happened, and optionally set the next page to display.
       *
       * There is also an alternate way to go to another page: raising
       * the exception Change_page.
       *
       * By raising the exception Change_dialog this method may force to go to
       * another dialog.
       *)

    (*********************************************************************)

    (**/**)

    (* Internal methods *)
    method set_event : event -> unit
      (* set_event e: Sets the current event to e. *)
    method set_server_popup_request : unit -> unit
      (* Sets that this dialog is restored for a server popup window *)
    method init : string -> unit
      (* MOSTLY INTERNAL USE:
       * init p: re-initializes the dialog in order to go to page p.
       *)
    method interactors : interactors
      (* ONLY INTERNAL USE *)

    (* -- class [dialog] also has a private method:
     * method private put_tree : string -> Template.tree -> unit
     *)

  end

(** This class represents the whole application *)
and application_type =
  object ('self)
    method start_dialog_name : string
      (** Returns the name of the start dialog *)
    method dialog_names : string list
      (** Returns the names of the declared dialogs *)
    method dialog_declaration : string -> dialog_decl_type
      (** Returns the declaration for the passed dialog *)
    method template_names : string list
      (** Returns the names of the declared templates (including the templates of
       * the core and the standard libraries)
       *)
    method template : string -> template_type
      (** Returns the definition of the passed template *)
    method study : unit -> unit
      (** Studies all defined templates *)
    method output_encoding : string -> (string -> string)
      (** Returns the output encoding as function [string -> string] *)
    method add_output_encoding : string -> (string -> string) -> unit
      (** Adds the output encoding function (second argument) under the
       * passed name (first argument) to the application. It is not
       * possible to redefine existing functions.
       *)
    method var_function : 
             string -> 
	       (dialog_type ->
                dialog_type poly_var_value list -> 
		  dialog_type poly_var_value)
      (** Returns the variable function as O'Caml function *)
    method dtd : Pxp_dtd.dtd
      (** Returns the DTD of WDialog *)
    method charset : Pxp_types.rep_encoding
      (** Returns the character set used for the internal representation, and for
       *  the generated HTML pages.
       *)
    method debug_mode : bool
      (** Returns whether there is a processing instruction [<?wd-debug-mode?>].
       *  This value is used to initialize the environment.
       *)
    method debug_mode_style : debug_mode_style
      (** Returns the style of the debug mode *)
    method prototype_mode : bool
      (** Returns whether there is a processing instruction [<?wd-prototype-mode?>].
       *  This value is used to initialize the environment.
       *)
    method onstartup_call_handle : bool
      (** Returns whether there is a processing instruction [<?wd-onstartup-call-handle?>].
       *)

    (**/**)

    method set_start_dialog_name : string -> unit
    method add_dialog_declaration : dialog_decl_type -> unit
    method add_template : ?lib:bool -> string -> template_type -> unit
    method add_var_function : 
             string -> 
	     ( dialog_type -> 
	       dialog_type poly_var_value list -> 
		 dialog_type poly_var_value) ->
	       unit
    method set_debug_mode : bool -> debug_mode_style -> unit
    method set_prototype_mode : bool -> unit
    method set_onstartup_call_handle : bool -> unit
  end

(** This class represents a template definition *)
and template_type =
  object

    method study : application_type -> unit
       (** Studies the template for the scope of the passed application *)
    method instantiate :
             ?context: syntax_tree_type dict ->
	     ?vars: trans_vars ->
             ?params:  syntax_tree_type dict ->
             dialog_type ->
               syntax_tree_type
       (** Instantiates the template. The parameter [~context] may contain the
	*  context parameters (defaults to the empty set). [~vars] may contain the
	*  transformation variables (defaults to: not available). [~params] may
	*  contains the lexical parameters (defaults to the empty set).
	*  In every case, the current dialog instance must be passed.
	*
	*  The result of the instantiation is the XML tree where all dollar notations
	*  have been replaced by the passed actual parameter values. It is not necessary
	*  that the template is completely expanded, however, i.e. it may contain
	*  [ui:use] elements.
	*
	*  The exception [Instantiation_error] will be raised if something goes
	*  wrong.
	*)
  end

(** This class represents the XML syntax tree *)
and syntax_tree_type =
  object ('self)

    inherit [syntax_tree_type Pxp_document.node] Pxp_document.extension
      (** The syntax tree is an extension of the PXP model for XML trees *)

    inherit template_type
      (** The syntax tree is always a template definition. This has formal
       *  reasons.
       *)

    (** {b Scanner methods}
     *
     * The side-effect of the scanners is to put the result into the passed
     * argument.
     *)
    method scan_application : application_type -> unit
    method scan_dialog : application_type -> dialog_decl_type -> unit
    method scan_enumeration : enum_decl -> unit
    method scan_literal : unit -> dialog_type poly_var_value
	(** (But this one is functional) *)

    method escaped_data : string
      (** Returns the string contained in the data node after HTML-escaping has
       *  been applied. This string is cached.
       *)

    method to_html :
      ?context: syntax_tree_type dict ->
      ?vars:    trans_vars ->
      dialog_type ->
      Netchannels.out_obj_channel ->
	unit
      (** This method writes the current node and all its children to the passed
       *  output channel. This method is for HTML context, i.e. character data
       *  are to be HTML-escaped, and all elements have to be interpreted.
       *)

    (* TODO: to_xhtml *)
    method to_text :
      ?context: syntax_tree_type dict ->
      ?vars:    trans_vars ->
      dialog_type ->
      Netchannels.out_obj_channel ->
	unit
      (** This method writes the current node and all its children to the passed
       *  output channel. This method is for attribute context, i.e. character data
       *  remain as they are without escaping them, and only the elements are
       *  interpreted that are defined for attribute context.
       *)
  end

(** The universe is the registry of classes and dialogs *)
and universe_type =
  object ('self)

    method application : application_type
      (** Return the application this universe is made for *)
    method register : string -> (universe_type -> string -> environment -> dialog_type) -> unit
      (** Registers that a certain O'Caml class implements the callbacks of the
       *  dialog declared in the UI definition. More precisely,
       *
       *  [u # register name f_new]
       *
       *  registers that the dialog [name] is realized by the objects returned by
       *  the evaluation of the constructing function [f_new]. The arguments passed
       *  to [f_new] are:
       *
       *  [f_new u name env]
       *
       *  where [u] and [name] are the universe and the dialog name, and [env]
       *  is the environment of the current CGI activation. It is legal to store
       *  [env] in the created objects because they are created for every activation
       *  anew.
       *)

    method create : environment -> string -> dialog_type
      (** Creates a new object for the passed environment and dialog name. This method
       *  effectively calls the function [f_new] that has previously been registered.
       *)
  end

(** The session manager creates new sessions, and looks sessions up in the
  *  (possibly fictive) session database
  *)
and session_manager_type =
  object

    method create : dialog_type -> session_type
	(** Creates a new session for this dialog *)

    method unserialize : universe_type -> environment -> string -> session_type
	(** Restores an old session for the passed universe and the passed
	 * environment. The string is the session in serialized form as returned
	 * by the [serialize] method.
	 *)
  end

(** This is a single session *)
and session_type =
  object

    method dialog_name : string
      (** Returns the name of the dialog this session encapsulates *)

    method dialog : dialog_type
      (** Returns the dialog *)

    method commit_changes : unit -> unit
      (** Causes that [serialize] returns the current state of the dialog.
       *  This means that [commit_changes] extracts the state from the dialog,
       *  and prepares the string that will be returned by [serialize].
       *)

    method serialize : string
      (** Returns the state of the dialog at the time of the last [commit_change]
       * or the state of the initial dialog
       *)
    method change_dialog : dialog_type -> unit
      (** Continue with a new dialog. The methods [dialog_name] and [dialog] will
       * immediately reflect the change. However, you have to call [commit_changes]
       * to make [serialize] return the state of the new dialog.
       *)
  end


type var_value = dialog_type poly_var_value
  (** [ ]
   *
   * This type is the concrete version of {!Wd_types.poly_var_value} that is
   *  actually used
   *)

type var_decl  = dialog_type poly_var_decl
  (** [ ]
   *
   * This type is the concrete version of {!Wd_types.poly_var_decl} that is
   * actually used
   *)


exception Change_dialog of dialog_type
  (** The implementation of the [handle] method of a dialog may raise
   * [Change_dialog] to drop the current dialog and continue with another
   * dialog.
   *)

exception Change_page of string
  (** The implementation of the [handle] method of a dialog  may raise
   *  [Change_page] to set the next page to display for the current dialog.
   *)

exception Formal_user_error of string
  (** A formal error that happens independently of the current runtime state.
   *  The string argument explains the error.
   *)

exception Runtime_error of string
  (** A certain operation cannot be performed because the current state does
   *  not fulfill the necessary preconditions.
   *  The string argument explains the error.
   *)

exception No_such_variable of string
  (** It has been tried to access a non-declared variable. The string is the
   *  name of the variable.
   *)

exception Instantiation_error of string
  (** An error generated by the [instantiate] method. The caller should
   * catch this exception and report the error from its own view
   *)

(**/**)

val revision_types : string
  (* Returns the CVS revision string. It is part of the hash value
   * that goes into the serialized objects
   *)

(* ======================================================================
 * History:
 *
 * $Log: wd_types.mli,v $
 * Revision 3.10  2003/03/21 14:23:44  stolpmann
 * 	ocamldoc updated
 *
 * Revision 3.9  2003/02/21 21:58:53  stolpmann
 * 	Changed docs.
 *
 * Revision 3.8  2003/02/16 23:48:15  stolpmann
 * 	Improved wd-debug-mode: there are now two styles
 *
 * Revision 3.7  2003/01/04 21:55:26  stolpmann
 * 	new record response_header
 *
 * Revision 3.6  2002/11/09 11:41:19  stolpmann
 * 	Fix: ui:select accepts dot notation. A new method
 * variable_decl needs to be defined for dialogs. This method
 * returns the var_decl record and interprets the dot notation.
 *
 * Revision 3.5  2002/10/20 19:39:17  stolpmann
 * 	New feature: The brackets $[...] can contain expressions,
 * not only variables
 *
 * Revision 3.4  2002/10/18 20:17:49  stolpmann
 * 	New feature: dot notation to access contents of dialog
 * variables
 *
 * Revision 3.3  2002/04/10 20:04:05  stolpmann
 * 	The CVS revision number is exported.
 *
 * Revision 3.2  2002/02/14 16:15:21  stolpmann
 * 	Added copyright notice.
 *
 * Revision 3.1  2002/02/12 20:29:25  stolpmann
 * 	Initial release at sourceforge.
 *
 * Revision 2.1  2002/02/11 18:27:55  gerd
 * 	Initial revision.
 *
 *
 *)
