(define leaf-tag "Leaf")
(define (make-leaf . coords) (cons leaf-tag coords))
(define (is-leaf? obj)
  (and (pair? obj)
       (eq? (car obj) leaf-tag)))
(define (leaf.point leaf) (cdr leaf))

(define node-tag "Node")
(define (make-node dist outside on-or-inside)
  (list node-tag dist outside on-or-inside))
(define (is-node? obj)
  (and (pair? obj)
       (eq? (car obj) node-tag)))
(define (node.distance node)
  (list-ref node 1))
(define (node.outside node)
  (list-ref node 2))
(define (node.on-or-in node)
  (list-ref node 3))

(define (distance node-or-leaf)
  (if (is-node? node-or-leaf)
      (node.distance node-or-leaf)
      (point.to-origin (leaf.point node-or-leaf))))

(define (tree.farthest node-or-leaf)
  (define (walk node-or-leaf)
    (if (is-node? node-or-leaf)
        (walk (node.outside node-or-leaf))
        node-or-leaf))
  (walk node-or-leaf))

(define (tree.nearest node-or-leaf)
  (define (walk node-or-leaf)
    (if (is-node? node-or-leaf)
        (walk (node.on-or-in node-or-leaf))
        node-or-leaf))
  (walk node-or-leaf))

(define (tree.valid? node-or-leaf)
  ;; THIS DOES NOT WORK CORRECTLY
  (if (is-node? node-or-leaf)
      (let ((smaller (node.on-or-in node-or-leaf))
            (not-smaller (node.outside node-or-leaf))
            (my-distance (node.distance node-or-leaf)))
        (and (< (distance smaller) my-distance)
             (>= (distance not-smaller) my-distance)
             (tree.valid? smaller)
             (tree.valid? not-smaller)))
        #T))

(define (valid? node-or-leaf)
  ;; THIS DOES
  (define (min previous new)
    (if (and previous (<= previous new)) previous new))

  (define (max previous new)
    (if (and previous (>= prevous new)) previous new))

  (define (walk node-or-leaf min-OK max-OK)
    (if (is-node? node-or-leaf)
        (let ((smaller (node.on-or-in node-or-leaf))
              (not-smaller (node.outside node-or-leaf))
              (my-distance (node.distance node-or-leaf)))
          (and (or (not min-OK) (>= (distance smaller) min-OK))
               (or (not max-OK) (<= (distance not-smaller) max-OK))
               (walk smaller (min min-OK my-distance) max-OK)
               (walk not-smaller min-OK (max max-OK my-distance))))
        #T))

  (walk node-or-leaf #F #F))

(define test
  (make-node
   10
   (make-leaf 10 0)
   (make-node 7
              (make-leaf 0 8)
              (make-node 5
                         (make-leaf 6 0)
                         (make-leaf 0 3)))))