;;  File ooq.ss  Object-oriented approach to queue ADT.
;;  The internal data structure:
;;    Elements of the queue are in a list.
;;      We keep a pointer to the front and back of the queue.and the code for manipulating
;;  is the same as in the previous example (queue.ss)

(define make-queue
  (lambda ()
    (let ([front '()] [rear '()])
      (lambda args
        (let ([method-name (car args)])
          (case method-name
            [(enqueue!)
             (if (not (= (length args) 2))
                 (error 'queue "enqueue! method must have one argument")
                 (let* ([obj (cadr args)]
			[x (cons obj '())])
		   (if (null? front)
		       (set! front x)
		       (set-cdr! rear x))
		   (set! rear x)))]
            [(empty?) (null? front)]
            [(dequeue!)
             (if (null? front)
                 (error 'dequeue! "cannot dequeue from empty queue")
                 (let ([obj (car front)])
                   (set! front (cdr front))
                   (if (null? front)
                       (set! rear '()))
                   obj))]
            [else (error 'queue "Allowed queue operations are ~s"
                         "empty?, enqueue!, dequeue!")]))))))

; WITHOUT ERROR CHECKING

(define make-queue
  (lambda ()
    (let ([front '()] [rear '()])
      (lambda args
        (case (car args)
          [(enqueue!) (let ([x (cons (cadr args) '())])
			(if (null? front)
			    (set! front x)
			    (set-cdr! rear x))
			(set! rear x))]
          [(empty?) (null? front)]
          [(dequeue!) (let ([obj (car front)])
			(set! front (cdr front))
			(if (null? front)
			    (set! rear '()))
			obj)])))))




(let ([q1 (make-queue)] [q2 (make-queue)])
  (q1 'enqueue! 3)
  (and (q2 'empty?) (not (q1 'empty?))))

(let ([q1 (make-queue)] [q2 (make-queue)])
  (q1 'enqueue! 3)
  (q1 'enqueue! 4)
  (q1 'dequeue!))

(let ([q1 (make-queue)] [q2 (make-queue)])
  (q1 'enqueue! 3)
  (q1 'enqueue! 4)
  (q2 'enqueue! (q1 'dequeue!))
  (and (not (q1 'empty?)) (not (q1 'empty?))))

(let ([q1 (make-queue)] [q2 (make-queue)])
  (q1 'enqueue! 3)
  (q1 'enqueue! 4)
  (q2 'enqueue! (q1 'dequeue!))
  (q2 'enqueue! (q1 'dequeue!))
  (and (q1 'empty?) (not (q2 'empty?))))

(let ([q1 (make-queue)] [q2 (make-queue)])
  (q1 'enqueue! 3)
  (q1 'enqueue! 4)
  (q2 'enqueue! (q1 'dequeue!))
  (q2 'enqueue! (q1 'dequeue!))
  (let* ([x (q2 'dequeue!)]
	 [y (q2 'dequeue!)])
    (list x y (q2 'empty?))))
  





;;;  > (define theQueue (make-queue))
;;;  > (theQueue 'enqueue! 'a)
;;;  > (theQueue 'enqueue! 'b)
;;;  > (theQueue 'empty-queue?)
;;;  #f
;;;  > (theQueue 'dequeue!)
;;;  a
;;;  > (theQueue 'dequeue!)
;;;  b
;;;  > (theQueue 'dequeue!)
;;;  
;;;  Error in dequeue!: cannot dequeue from empty queue.
;;;  Type (debug) to enter the debugger.
;;;  >
;;;  > (theQueue 'reverse)
;;;  
;;;  Error in queue: Allowed queue operations are "empty-queue, enque!, dequeue!".
;;;  Type (debug) to enter the debugger.
;;;  >