;; The first three lines of this file were inserted by DrRacket. They record metadata
;; about the language level of this file in a form that our tools can easily process.
#reader(lib "htdp-beginner-reader.ss" "lang")((modname 21.6.1) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ())))
(require picturing-programs)
; Worked exercise 21.6.1
; Handlers: we need a tick handler, key handler, check-with handler, and draw handler.
; Model: a structure containing the x coordinate of the picture and its direction (either "left" or "right").

; A moving-x consists of x (a number) and dir (a string, either "left" or "right").
(define-struct moving-x [x dir])
; make-moving-x : number string -> moving-x
; moving-x-x : moving-x -> number
; moving-x-dir : moving-x -> string
; moving-x? : anything -> boolean
(define state1 (make-moving-x 10 "right"))
(define state2 (make-moving-x 29 "left"))
(check-expect (moving-x-x state1) 10)
(check-expect (moving-x-dir state2) "left")

; Inventory template:
#|
(define (function-on-moving-x current)
  ; current                    moving-x
  ; (moving-x-x current)       number
  ; (moving-x-dir current)     string
  ...)
|#

; Outventory template:
#|
(define (function-returning-moving-x whatever)
  (make-moving-x ... ; a number
                 ... ; a string
                 ))
|#

; handle-draw : moving-x -> image
; handle-tick : moving-x -> moving-x
; handle-key : moving-x key -> moving-x

; An old function that we'll use for this problem
(define WIDTH 300)
(define HEIGHT 200)
(define BACKGROUND (rectangle WIDTH HEIGHT "solid" "white"))
; calendar-at-x : number(x) -> image
(check-expect (calendar-at-x 75) (place-image pic:calendar 75 (/ HEIGHT 2) BACKGROUND))
(define (calendar-at-x x)
  (place-image pic:calendar x (/ HEIGHT 2) BACKGROUND))

; Draw handler
(check-expect (handle-draw state1) (calendar-at-x 10))
(check-expect (handle-draw state2) (calendar-at-x 29))
(define (handle-draw current)
  ; current                    moving-x    (make-moving-x 10 "right")
  ; (moving-x-x current)       number      10
  ; (moving-x-dir current)     string      "right"
  ; right answer               image       (calendar-at-x 10)
  (calendar-at-x (moving-x-x current)))

; Tick handler
(define SPEED 3)
(check-expect (handle-tick state1)
              (make-moving-x 13 "right"))
(check-expect (handle-tick state2)
              (make-moving-x 26 "left"))
(check-error (handle-tick (make-moving-x 53 "fnord"))
             "handle-tick: Direction is neither left nor right!")

(define (handle-tick current)
  (cond [(string=? (moving-x-dir current) "left")
         ; current                    moving-x
         ; (moving-x-x current)       number
         ; (moving-x-dir current)     string
         ; SPEED                      number
         ; "left", "right"            strings
         ; right answer
         (make-moving-x (- (moving-x-x current) SPEED) "left")
         ]
        [(string=? (moving-x-dir current) "right")
         ; current                    moving-x
         ; (moving-x-x current)       number
         ; (moving-x-dir current)     string
         ; SPEED                      number
         ; "left", "right"            strings
         ; right answer
         (make-moving-x (+ (moving-x-x current) SPEED) "right")
         ]
        [else
         (error 'handle-tick "Direction is neither left nor right!")]))

; Key handler
(check-expect (handle-key state1 "up") state1) ; ignore up-arrow
(check-expect (handle-key state1 "right") state1) ; already going right; no change
(check-expect (handle-key state1 "left")
              (make-moving-x 10 "left"))
(check-expect (handle-key state2 "right")
              (make-moving-x 29 "right"))

(define (handle-key current key)
  ; current                    moving-x
  ; (moving-x-x current)       number
  ; (moving-x-dir current)     string
  ; "left", "right"            strings
  ; right answer
  (cond [(or (key=? key "left") (key=? key "right"))
         (make-moving-x (moving-x-x current) key)]
        [else current]))


(big-bang
 (make-moving-x (/ WIDTH 2) "right") ; start at middle, moving right
 (check-with moving-x?)
 (on-draw handle-draw)
 (on-tick handle-tick 1)
 (on-key handle-key))