{ (define LIBNAME "Simplified Racket Web Servlets")
  (include "head.tinc") }

<p>This teachpack provides a simplified API for Racket servlets. The
teachpack does not require any understanding of HTML and higher-order
functions. It uses structures and lists, and is therefore well-suited for
use with an HtDP course.

<hr>
<h3>Interface</h3>

<pre>
   ; Data Constructors  -------------------------------------------------------
   {(idx make-password)} ; asking for a password
   {(idx make-number)}   ; asking for a number
   {(idx make-yes-no)}   ; asking for a Yes-No style answer
   {(idx make-boolean)}  ; asking for a true-false style answer
   {(idx make-radio)}    ; requesting one choice from some mutually exclusive choices

   #| Data Definitions --------------------------------------------------------

   Forms ----------------------------------------------------------------------
   Query    = (union String
                (make-password String)
                (make-number   String)
                (make-boolean  String)
                (make-yes-no   String String String)
                (make-radio    String (cons String (listof String))))
   FormItem = (list Symbol Query)
   Form     = (cons FormItem (listof FormItem))

   Table -------------------------------------------------------------------
   Response = (union String Number Boolean)
   Table    = (listof (list Symbol Response))
   |#

   ; Functions ----------------------------------------------------------------

   {(idx form?)}               ; TST -> Boolean
   ; checking the structure of forms

   {(idx form-element?)}       ; TST -> Boolean
   ; checking the structure of form-elements

   {(idx single-query)}        ; Query -> Response
   ; posing a single question

   {(idx queries)}             ; (listof Query) -> (listof Response)
   ; posing a list of questions

   {(idx echo-answers)}        ; (listof Response) -> true
   ; echoing the answers from a list of questions to a Web page (development)

   {(idx form-query)}          ; Form -> Table
   ; posing a list of questions with tag

   {(idx extract/single)}      ; Symbol Table -> Response
   ; extracting the answer for a given tag from a response; the tag must
   ; occur exactly once.

   {(idx extract)}             ; Symbol Table -> (listof Response)
   ; extracting all the answers for a given tag from a response; the list
   ; is empty if there is no such tag.

   {(idx echo-response)}       ; Table -> true
   ; echoing the response from a form to a Web page (development)

   {(idx inform)}              ; String String *-> true
   ; posting some information on a Web page, wait for continue signal

   {(idx final-page)}          ; String String *-> true
   ; posting some information on a Web page,
   ; killing the script and all associated backtrack/clone points

</pre>
<hr>
<h3>Pragmatics</h3>

<p>The following table specifies what kind of answer each form of query
produces:

<pre>
  Query                                      GUI Item         Response
________________________________________________________________________________
  String                                     text field       String
  (make-password String)                     password field   String
  (make-number   String)                     text field       Number
  (make-boolean  String)                     check box        Boolean
  (make-yes-no   String String1 String2)     2-pronged radio  String1 or String2
  (make-radio    String loString)            radio button     one of loString
  (make-button   String0)                    submit button    String0
</pre>

<p>The functions play the following role:
<ul>
<li>
   <code>form?</code> and <code>form-element?</code> enable programmers to
   check the well-formedness of their queries.

<li>
   <code>single-query</code> poses a question and waits for a answer from
   the consumer.

<li>
   <code>queries</code> poses a list of questions and waits for the
   submission of answers; it produces a list of answers that is as
   long as the list of given questions.

<li>
   <code>echo-answers</code> echoes a list of answers to a Web page; this
   function is useful for testing Web form designs.

<li>
   <code>form-query</code> poses a form with queries and waits for the
   submission of answers; it produces a list of tagged or labeled answers
   that is as long as the list of given questions.

<li>
   <code>echo-response</code> echoes a response to a Web page as a table.

<li>
   <code>inform</code> posts some information on a Web page and wait for a
   continue signal (a link) from the consumer; the first string plays the
   role of a title and the rest form a paragraph.

<li>
   <code>final-page</code> posts some information on a Web page and
   shuts down the script and all associated backtrack/clone points.
</ul>


<h3>Example</h3>

<p>The following example illustrates how the library enables programs to
interact with the consumer. In particular, note the properly recursive
calls to <code>login</code> in <code>inform-error</code>. Also note how the
functions <code>make-password</code> and <code>make-number</code> return
strings and numbers, respectively.

<pre>
#| Login Site -----------------------------------------------------------------
   Author: Matthias Felleisen
   Language: Intermediate
   Teachpack: servlet2.ss

   Login Web Site:

   A login site consists of three pages:
    1. login: request user information: name, password, year-of-birth
       - if correct, respond with greeting for name
       - if incorrect, go to error page
    2. error: inform user of error, continue goes back to login page
    3. greetings: say hello to name
   The second and third are generated from user input, the first is
   generated by the program alone.

|#

;; Login Page -----------------------------------------------------------------

; ask three questions: one plain, one password, one numeric
(define login-page
  (list
   (list 'name "User Name")
   (list 'pass (make-password "Password"))
   (list 'yofb (make-number "Year-of-birth"))))

; Table -> true
; process the response for login-page
(define (login r)
  (let ([name (extract/single 'name r)])
    (if (string=? (lookup-password name) (extract/single 'pass r))
        (if (= (lookup-yofb name) (extract/single 'yofb r))
            (greetings name)
            (inform-error "bad data"))
        (inform-error "bad match"))))

; String -> (union false String)
; lookup the password for name in DB
(define (lookup-password name)
  (local ([define (x=? x) (string=? name x)]
          [define r (assf x=? DB)])
    (if (boolean? r) false (second r))))

; String -> (union false Number)
; lookup the year-of-birth for name in DB
(define (lookup-yofb name)
  (local ([define (x=? x) (string=? name x)]
          [define r (assf x=? DB)])
    (if (boolean? r) false (third r))))

(define DB
  '(("matthias" "okay" 1958)))

;; Error Page -----------------------------------------------------------------

; String -> true
; consume error message, print and enable return to login page
(define (inform-error s)
  (let ([_ (inform "Error" s)])
    (login (form-query login-page))))

;; Greetings Page -------------------------------------------------------------

; String -> true
; consume name and display good bye message
(define (greetings name)
  (inform "Welcome" "Welcome " name " and good bye."))

;; Run ------------------------------------------------------------------------
(login (form-query login-page))
</pre>

{(include "foot.tinc")}
