;; A procedural data abstraction version of polynomials.
;; The code you expect to see here is at the end of this file.

;; The following is written in the style of chapter 12.

(define pda-zero-poly
  (lambda msg
    (case (car msg)
      ((type) "poly")
      ((degree leading-coef) 0)
      ((rest-of-poly) pda-zero-poly)
      (else (delegate base-object msg)))))

(define pda-poly-cons
  (lambda (deg coef rp)
    (let ((deg-rp (send rp 'degree))
	  (new-p (lambda msg
		   (case (car msg)
		     ((type) "poly")
		     ((degree) deg)
		     ((leading-coef) coef)
		     ((rest-of-poly) rp)
		     (else (delegate base-object msg))))))
      (if (or (and (zero? deg) (zero? deg-rp) (zero? (send rp 'leading-coef)))
	      (< deg-rp deg))
	  (if (zero? coef)
	     rp
	     new-p)
	  (error "poly-cons: degree specified is too low")))))

;; code from chapter 12 ...

(define invalid-method-name-indicator "unknown")

; - Program 12.3, pg. 388 -

(define delegate
  (lambda (obj msg)
    (apply obj msg)))

; - End Program -

; - Program 12.4, pg. 389 -

(define base-object
  (lambda msg
    (case (1st msg)
      ((type) "base-object")
      (else invalid-method-name-indicator))))

; - Program 12.5, pg. 389 -

(define send
  (lambda args
    (let ((object (car args)) (message (cdr args)))
      (let ((try (apply object message)))
        (if (eq? invalid-method-name-indicator try)
            (error 
              (string-append (symbol->string (car message)) ": "
                             "Bad method name sent to object of " 
                             (object 'type) " type."))
            try)))))

; - End Program -

;; ... end of code from chapter 12



;; The ADT-style wrapper needed for chapter 5 work.

(define the-zero-poly pda-zero-poly)

(define degree
  (lambda (poly)
    (send poly 'degree)))
    
(define leading-coef
  (lambda (poly)
    (send poly 'leading-coef)))

(define rest-of-poly 
  (lambda (poly)
    (send poly 'rest-of-poly)))

(define poly-cons pda-poly-cons)

