#lang sicp

(define (make-queue)
  (let ((front-ptr '())
        (rear-ptr '()))

    (define (set-front-ptr! item) 
      (set! front-ptr item))
    (define (set-rear-ptr! item) 
      (set! rear-ptr item))
    (define (empty-queue?) 
      (null? front-ptr))
    (define (front-queue)
      (if (empty-queue?)
        (error "FRONT called with an
               empty queue")
        (car front-ptr)))
    (define (insert-queue! item)
      (let ((new-pair (cons item '())))
        (cond ((empty-queue?)
               (set-front-ptr! new-pair)
               (set-rear-ptr! new-pair)
               dispatch) ;; Instead of queue, we return dispatch
                         ;; I'm using this analogous to C++ "this" 
          (else (set-cdr! rear-ptr 
                          new-pair)
                (set-rear-ptr! new-pair)
                dispatch))))
    (define (delete-queue!)
      (cond ((empty-queue?)
             (error "DELETE! called with 
                    an empty queue"))
        (else (set-front-ptr! 
                            (cdr front-ptr))))
      dispatch)
    (define (print-queue)
      (display front-ptr) (newline))
    (define (dispatch m)
      (cond ((eq? m 'set-front-ptr!) set-front-ptr!)
            ((eq? m 'set-rear-ptr!) set-rear-ptr!)
            ((eq? m 'empty-queue?) empty-queue?)
            ((eq? m 'front-queue) front-queue)
            ((eq? m 'insert-queue!) insert-queue!)
            ((eq? m 'delete-queue!) delete-queue!)
            ((eq? m 'print-queue) print-queue)
            (else (error "DELETE! called with 
                    an empty queue"))))
    dispatch))

(define (set-front-ptr! q item) 
  ((q 'set-front-ptr!) item))
(define (set-rear-ptr! q item)
  ((q 'set-rear-ptr!) item))
(define (empty-queue? q)
  ((q 'empty-queue?)))
(define (front-queue q)
  ((q 'front-queue)))
(define (insert-queue! q item)
  ((q 'insert-queue!) item))
(define (delete-queue! q)
  ((q 'delete-queue!)))
(define (print-queue q)
  ((q 'print-queue)))

(define q1 (make-queue))
(print-queue (insert-queue! q1 'a))
(print-queue (insert-queue! q1 'b))
(print-queue (delete-queue! q1))
(print-queue (delete-queue! q1))
