;; Assume we wanted a version of the routes program that provides the
;; user with two choices after they enter their origin city:
;; they can calculate routes or they can change their origin city.  The
;; program should let multiple people use the same computer to calculate
;; routes, and provide the personalization feature we discussed for
;; the first project.

;; The question now is how we should manage the origin data.  We've
;; seen two options so far: hidden variables and cookies.  Recall what
;; we discussed after the first project about the mapping between web
;; constructs and programming constructs:

;;    - web pages correspond to closures
;;    - hidden variables correspond to environments,
;;    - submit buttons correspond to calling functions

;; Let's write a hidden-variable version of the new routes site. 

;; Where does the following code come from?  The first lambda is a web
;; page that takes in the origin city.  It returns a web page
;; that asks the user which operation to perform.  In each case,
;; the code returns a web page for executing the operation, and
;; printing out the results.  WIth our analogy that web pages are
;; functions, the structure of this code follows naturally from the
;; sequence of pages.

(define routes-site/hidden
  (lambda (origin)
    (lambda (service)
      (cond [(symbol=? service 'get-routes)
	     (lambda (dest which visits avoids)
	       (printf "Printing ~a routes from ~a to ~a visiting ~a and avoiding ~a~n"
		       which origin dest visits avoids))]
	    [(symbol=? service 'change-origin)
	     (lambda (neworigin)
	       (routes-site/hidden neworigin))]))))

;; Notice that this page looks exactly like an object!  Web pages are
;; really objects (which means that web sites are really classes).
;; This is consistent with our claim that web pages are closures,
;; because objects are just closures with multiple entry points (as we
;; discussed when we introduced objects).

;; Let's test the hidden variable version

;;(define page1 (routes-site/hidden 'boston))
;;((page1 'get-routes) 'new-york 'all 'hartford 'none)
;;((page1 'get-routes) 'providence 'all 'none 'none)
;;((page1 'change-origin) 'hartford)
;;((page1 'get-routes) 'providence 'all 'none 'none)

;; Note that this version doesn't actually change the saved page (the
;; closure) -- page1 never sees the new origin.  So let's rework to
;; use cookies.

(define routes-site/cookies
  (local [(define origincookie 'unset)]
    (lambda (origin)
      (begin
        (set! origincookie origin)
        (lambda (service)
          (cond [(symbol=? service 'get-routes)
                 (lambda (dest which visits avoids)
                   (printf "Printing ~a routes from ~a to ~a visiting ~a and avoiding ~a~n"
                           which origincookie dest visits avoids))]
                [(symbol=? service 'change-origin)
                 (lambda (neworigin)
                   (begin
                     (set! origincookie neworigin)
                     (printf "Changed origin to ~a~n" origincookie)))]))))))

;; If we test this code, we find that two people using this code on
;; the same machine breaks the personalization feature.  The cookies
;; are too strong, because the same id gets shared across every
;; person's customized page.

;;(define page2 (routes-site/cookies 'boston))
;;((page2 'get-routes) 'new-york 'all 'none 'none)
;;(define page3 (routes-site/cookies 'hartford))
;;((page2 'get-routes) 'new-york 'all 'none 'none)

;; Let's try one last version.  Remember how you implemented the
;; personalization feature for project 1 -- you used IDs that gave you
;; separate access to each customization.  Here's a version that
;; implements the ID version:

(define routes-site/url
  (lambda (origin)
    (local [(define origin-for-id origin)]
      (lambda (service)
        (cond [(symbol=? service 'get-routes)
               (lambda (dest which visits avoids)
                 (printf "Printing ~a routes from ~a to ~a visiting ~a and avoiding ~a~n"
                         which origin-for-id dest visits avoids))]
              [(symbol=? service 'change-origin)
               (lambda (neworigin)
                 (begin
                   (set! origin-for-id neworigin)
                   (printf "Changed origin to ~a~n" origin-for-id)))])))))

;; where are the ID's here?  They come from the different dummy
;; variables introduced for origin.  If you test this code, you'll
;; find that it implements both features that we wanted above

;;(define page4 (routes-site/url 'boston))
;;((page4 'get-routes) 'new-york 'all 'none 'none)
;;(define page5 (routes-site/url 'hartford))
;;((page4 'get-routes) 'new-york 'all 'none 'none)
;;((page5 'get-routes) 'new-york 'all 'none 'none)
;;((page4 'change-origin) 'providence)
;;((page4 'get-routes) 'new-york 'all 'none 'none)
;;((page5 'get-routes) 'new-york 'all 'none 'none)

