;;> ********************** 
;;> * CSU-211 Lab 8 Code * 
;;> ********************** 

;      +-------------------------------+
;      v                               |
;; A Stack is either                   |
;;   -- MtStack = (make-mt-stack)      +
;;   -- PushStack = (make-push-stack Stack Number)
(define-struct mt-stack ())
(define-struct push-stack (other top))


;; push: Stack Number -> Stack
(define (push stack num)
  (make-push-stack stack num))

;; pop: Stack -> Stack
(define (pop stack)
  (cond [(mt-stack? stack) (error 'pop "Can't Pop MtStack")]
        [(push-stack? stack) (push-stack-other stack)]))

;; top: Stack -> Number
(define (top stack)
  (cond [(mt-stack? stack) (error 'pop "Can't Top MtStack")]
        [(push-stack? stack) (push-stack-top stack)]))

;; draw-stack: Stack Number Number Scene -> Scene
(define (draw-stack stack x y scn)
  (cond [(mt-stack? stack) scn]
        [(push-stack? stack)
         (place-image (text (number->string (top stack)) 14 'black)
                      (- x 10) (- y 10)
                      (place-image (rectangle 40 20 'outline 'black)
                                   x y
                                   (draw-stack (pop stack) x (+ y 20) scn)))]))

;      +----------------------------------------+
;      v                                        |
;; A Queue is either                            |
;;   -- Qend = (make-qend)                      +
;;   -- FrontQueue = (make-front-queue Number Queue)
(define-struct qend ())
(define-struct front-queue (front back))


;; enqueue: Number Queue
(define (enqueue q num)
  (cond [(qend? q) (make-front-queue num q)]
        [else (make-front-queue (front-queue-front q)
                                (enqueue (front-queue-back q) num))]))

;; dequeue: Queue -> Queue
(define (dequeue q)
  (cond [(qend? q) (error 'pop "Can't Dequeue Qend")]
        [else (front-queue-back q)]))

;; peek: Queue -> Number
(define (peek q)
  (cond [(qend? q) (error 'pop "Can't Peek Qend")]
        [else (front-queue-front q)]))

;; draw-queue: Queue Number Number Scene -> Scene
(define (draw-queue q x y scn)
  (cond [(qend? q) scn]
        [else
         (place-image (text (number->string (peek q)) 14 'black)
                      (- x 10) (- y 10)
                      (place-image (rectangle 40 20 'outline 'black)
                                   x y
                                   (draw-queue (dequeue q) x (+ y 20) scn)))]))

;; A Group is (make-group Stack Queue)
(define-struct group (stack queue))

;; draw: Stack -> Scene
(define (draw g)
  (draw-queue (group-queue g) 200 25 
              (draw-stack (group-stack g)
                          100 25 (empty-scene 300 400))))

;; key: Stack Symbol-or-Char -> Scene
(define (key g s/ch)
  (cond [(char? s/ch)
         (cond [(char=? #\u s/ch) 
                (local ((define rand (random 100)))
                  (make-group (push (group-stack g) rand)
                              (enqueue (group-queue g) rand)))]
               [(char=? #\d s/ch) 
                (make-group (pop (group-stack g))
                            (dequeue (group-queue g)))]
               [else g])]
        [else g]))

;; Window Stuff
(big-bang 300 400 1 (make-group (make-mt-stack) 
                                (make-qend)))
(on-redraw draw)
(on-key-event key)