(***********************************************************************)
(*                                                                     *)
(*                           Calves                                    *)
(*                                                                     *)
(*          Francois Rouaix, projet Cristal, INRIA Rocquencourt        *)
(*                                                                     *)
(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
(*  Automatique.  Distributed only by permission.                      *)
(*                                                                     *)
(***********************************************************************)

(* Safe Navigator internals *)
open Safetk
open Safetkanim

(* Miscellaneous utilities : nothing really interesting. But then, it's safe *)
module Mstring : sig
  val uppercase : string -> string
  val lowercase : string -> string
  val split_str : (char -> bool) -> string -> string list
  val first_char_pos : char -> string -> int
  val last_char_pos : char -> string -> int
  val get_suffix : string -> string
  val gensym : string -> string
end

module Mlist : sig
  val rev_do_list : ('a -> unit) -> 'a list -> unit
end

module Feed : sig
  type internal = Feed.internal
  type t = Feed.t = {
    feed_read : string -> int -> int -> int;
    feed_schedule : (unit -> unit) -> unit;
    feed_unschedule : unit -> unit;
    feed_close : unit -> unit;
    feed_internal : internal  
    }
  (* A Feed is a handle to the contents of a document being loaded.
     As loading should be kept asynchronous, the proper usage of a feed is
     to feed_schedule a callback that does feed_read.
     feed_read returns 0 when EOF is reached.
     A synchronous feed_read (outside the invocation of a callback installed
     by feed_schedule) might block the applet/navigator indefinitely.
   *)
  end

(* Various dialog boxes *)
module Error : sig
  val f : string -> unit
    (* [f msg] displays an error message [msg] in a dialog box and waits
       for the user to click Ok *)
  val ok : string -> unit
    (* [ok msg] displays the warning or simple notification [msg] in a
       dialog box and waits for the user to click Ok *)
  val choose: string -> bool
    (* [choose msg] displays [msg] in a dialog box, and waits for the user
       to click on Ok or Cancel. Returns true for Ok, false for Cancel *)
  val ari : string -> int
    (* [ari msg] displays [msg] in a dialog box, and waits for the user
       to click on Abort/Retry/Ignore. Returns 0/1/2 respectively *)

  class t (Widget.widget) =
   method  f : string -> unit
   method ok : string -> unit
   method choose: string -> bool
   method ari : string -> int
  end

  end


module Url : sig
  type t = Url.t
  val string_of : t -> string
  end

module Lexurl : sig
  val make : string -> Url.t
  end

(* Manifest types are kept because we reuse this for Safemmm *)
module Hyper : sig
  type link_method = Hyper.link_method =
     GET 
   | HEAD
   | POST of string

  type link = Hyper.link = {
    h_uri : string;
    h_context: string option;
    h_method : link_method		(* default is GET *)
    }

  type link_error =  Hyper.link_error =
      LinkResolve of string
    | UrlLexing of string * int

  exception Invalid_link of link_error

  val urlconcat: Url.t -> string -> string
     (* [urlconcat url relurl] resolves the relative URL [relurl] in the
	 context of the URL [url]
	Doesn't handle fragments
      *)
  val string_of : link -> string
    (* make an abolute URI (including fragment) from link 
       raises Invalid_link(msg) *)

  type func = Hyper.func = {
    hyper_visible : bool;
    hyper_title : string;
    hyper_func : link -> unit
    }
end

module Www : sig
(*
 * Requests
 *)

type request =  { 
    www_link : Hyper.link;        (* the link that produced this request *)
    www_url : Url.t;	          (* parsed version *)
    www_fragment : string option; (* because viewer is passed down *)
    mutable www_auth : (string * string) list;  (* basic auth *)
    mutable www_headers : string list;		  (* additional headers *)
    mutable www_logging : string -> unit;	  (* logging *)
    mutable www_error : Error.t
  }

exception Invalid_request of request * string

val make : Hyper.link -> request
  (* raises: 
      Url_Lexing
      Invalid_link
   *)
end



module Document : sig
  (* identification of a Web document *)
  type document_id = Document.document_id = {
    document_url : Url.t;
      (* URL of the document *)
    document_stamp : int
      (* Always 0 in NN 3.0 *)
    }

  (* This type can't be used. Exported for typing purposes only *)
  type logger = Document.logger

  (* Handles to document requested by the applet through the navigator *)
  type handle = Document.handle = {
    document_id : document_id;
      (* identification of the document *)
    document_referer : string option;
      (* URL of refering document, if any *)
    mutable document_status : int;
    mutable document_headers : string list;
      (* HTTP headers of document, or faked ones.
         In NN3.0, the only possible headers are Content-Type,
         Content-Length (not necessary valid), and 
         Last-Modified (not necessary valid)
       *)
    document_feed : Feed.t;
      (* where to get the data *)
    document_fragment : string option;
      (* fragment (#foo) if any *)
    mutable document_logger : logger
      (* how to log information relative to this document processing *)
    }

  type document_continuation = {
    document_process : handle -> unit;
      (* The callback invoked when the request for a document succeeds.
         The argument [handle] contains a Feed, from which one can
         read the document contents. *)
    document_finish : bool -> unit
      (* The callback invoked when the request for a document is aborted.
         Not supported in NN3.0 *)
     }

  val dclose : bool -> handle -> unit
    (* close a document handle (in particular, closes its feed).
       In MMM, first argument should be true in most cases, as it allows
       further accesses to the document.
     *)
end


(* Information to get back to the navigator *)
module Viewers : sig
  (* A context is given to each applet invocation *)
  type context = Viewers.context = { 
    viewer_base  : Document.document_id;
      (* the base url for the embedded object *)
      (* not available as for NN 3.0  (same as URL of embedded) *)
    viewer_hyper : (string * Hyper.func) list;
      (* my other name is Captain Hook.
         Each hyperfunction can be called on an URL. Hyperfunctions have
         symbolic names
           in NN3.0: goto
           in MMM: goto, gotonew, save
       *)
    viewer_log   : string -> unit;
      (* Displays a status message in the navigator *)
    viewer_params : (string * string) list
      (* Parameters of viewer *)
   }
end

(* Registering an applet *)
module Applets : sig
  val register : string -> (Widget.widget -> Viewers.context -> unit) -> unit
    (* [register <applet name> <applet_callback>]
       The name should then be used as attribute value of "function" in the
       EMBED element (e.g. <EMBED SRC="foo.cmo" function="my function">
       The applet callback is invoked as
        [f ctx nargs args] where
          ctx is the viewer context
          nargs is the a-list [name, value] of named EMBED arguments
          args is the list of anonymous EMBED arguments (_="foo")
     *)
  end

module Capabilities : sig
  type t = Capabilities.t 
  type right = Capabilities.right =
     FileR of string			(* read access to files *)
   | FileW of string			(* write acces to files *)
   | DocumentR of string			(* read access to URLs *)
      (* Document read access affects decoders, embedded viewers, as well as
	 the general retrieval mechanism *)
   (* The following rights are available only in MMM *)
   | HTMLDisplay

  val get : unit -> t
    (* Get the initial default capabilities for all applets defined in
       the bytecode file.
       MUST BE CALLED ONLY AT LOAD-TIME. Raises Not_found otherwise.
     *)

  val whoami : unit -> string
  (* get our url location. Can be used to set initial rights using
     paths computed from location, or also to prohibit (more or less)
     copying of an applet.
     MUST BE CALLED ONLY AT LOAD-TIME. Raises Not_found otherwise
   *)

  val require : t -> right list -> bool
   (* get some specific capabilities, to avoid popping dialog boxes all
      over the place. Moreover, can make use of regexp
    *)

  exception Denied
   (* exception raised by various functions in modules Safe*, when
      access to a resource is denied
    *)

  end

module Retrieval(C: sig val capabilities: Capabilities.t end) : sig

val retrieve : Www.request -> Document.document_continuation -> unit
  (* [retrieve wr conts] retrieves a document obtained by [wr]
     through the navigator interface.
   *)
val get_image : Url.t -> (Tkanim.imageType -> unit) -> unit
  (* [get_image url cont] retrieves an image located at [url] and 
     applies the continuation [cont] on it. Images are cached.
   *)
end
