;; ----------------------------------------------------------------------
;;  SRFI 134 ...
;; ----------------------------------------------------------------------

(import (srfi 158))

;; "ideque/constructors"
(test "ideque 1" '() (ideque->list (ideque)))
(test "ideque 2" '() (ideque->list (list->ideque '())))
(test "ideque 3" '(1 2 3) (ideque->list (ideque 1 2 3)))
(test "ideque 4" '(4 5 6 7) (ideque->list (list->ideque '(4 5 6 7))))
(test "ideque 5" '(10 9 8 7 6 5 4 3 2 1)
      (ideque->list (ideque-unfold zero? values (lambda (n) (- n 1)) 10)))
(test "ideque 6" '(1 2 3 4 5 6 7 8 9 10)
      (ideque->list (ideque-unfold-right zero? values (lambda (n) (- n 1)) 10)))
(test "ideque 8" '(0 2 4 6 8 10)
      (ideque->list (ideque-tabulate 6 (lambda (n) (* n 2)))))

;; corner cases
(test "ideque 9" '() (ideque->list
                      (ideque-unfold (lambda (n) #t) values (lambda (n) (+ n 1)) 0)))
(test "ideque 10" '() (ideque->list
                       (ideque-unfold-right (lambda (n) #t) values (lambda (n) (+ n 1)) 0)))
(test "ideque 11" '() (ideque->list (ideque-tabulate 0 values)))


;; "ideque/predicates"
(test "ideque 12" #t (ideque? (ideque)))
(test "ideque 13" #t (not (ideque? 1)))
(test "ideque 14" #t (ideque-empty? (ideque)))
(test "ideque 15" #t (not (ideque-empty? (ideque 1))))
(test "ideque 16" #t (ideque= eq?))
(test "ideque 17" #t (ideque= eq? (ideque 1)))
(test "ideque 18" #t (ideque= char-ci=? (ideque #\a #\b) (ideque #\A #\B)))
(test "ideque 19" #t (ideque= char-ci=? (ideque) (ideque)))
(test "ideque 20" #t (not (ideque= char-ci=? (ideque #\a #\b) (ideque #\A #\B #\c))))
(test "ideque 21" #t (not (ideque= char-ci=? (ideque #\a #\b) (ideque #\A))))
(test "ideque 22" #t (ideque= char-ci=? (ideque) (ideque) (ideque)))
(test "ideque 23" #t (ideque= char-ci=? (ideque #\a #\b) (ideque #\A #\B) (ideque #\a #\B)))
(test "ideque 24" #t (not (ideque= char-ci=? (ideque #\a #\b) (ideque #\A) (ideque #\a #\B))))
(test "ideque 25" #t (not (ideque= char-ci=? (ideque #\a #\b) (ideque #\A #\B) (ideque #\A #\B #\c))))

;; "ideque/queue-operations"
(test/error "ideque 26" (ideque-front (ideque)))
(test/error "ideque 27" (ideque-back (ideque)))
(test "ideque 28" 1 (ideque-front (ideque 1 2 3)))
(test "ideque 29" 3 (ideque-back (ideque 1 2 3)))
(test "ideque 30" 2 (ideque-front (ideque-remove-front (ideque 1 2 3))))
(test "ideque 31" 2 (ideque-back (ideque-remove-back (ideque 1 2 3))))
(test "ideque 32" 1 (ideque-front (ideque-remove-back (ideque 1 2 3))))
(test "ideque 33" 3 (ideque-back (ideque-remove-front (ideque 1 2 3))))
(test "ideque 34" #t (ideque-empty? (ideque-remove-front (ideque 1))))
(test "ideque 35" #t (ideque-empty? (ideque-remove-back (ideque 1))))
(test "ideque 36" 0 (ideque-front (ideque-add-front (ideque 1 2 3) 0)))
(test "ideque 37" 0 (ideque-back (ideque-add-back (ideque 1 2 3) 0)))

;; ;; "ideque/other-accessors"
(define (check name ideque-op list-op n)
  (let* ((lis (iota n))
         (dq (list->ideque lis)))
    (for-each (lambda (i)
                (test (format "ideque ~s ~d" name i)
                      (receive xs (list-op lis i) xs)
                      (receive xs (ideque-op dq i)
                        (map ideque->list xs))))
              lis)))
(check 'ideque-take ideque-take take 7)
(check 'ideque-drop ideque-drop drop 6)
(check 'ideque-split-at ideque-split-at split-at 8)
;;  ;; out-of-range conditions
(test/error "ideque 38" (ideque->list (ideque-take (ideque 1 2 3 4 5 6 7) 10)))
(test/error "ideque 39" (ideque->list (ideque-take-right (ideque 1 2 3 4 5 6 7) 10)))
(test/error "ideque 40" (ideque-split-at (ideque 1 2 3 4 5 6 7) 10))

(test "ideque 41" '(3 2 1) (map (lambda (n) (ideque-ref (ideque 3 2 1) n)) '(0 1 2)))
(test/error "ideque 42" (ideque-ref (ideque 3 2 1) -1))
(test/error "ideque 43" (ideque-ref (ideque 3 2 1) 3))


;; ;; "ideque/whole-ideque"
(test "ideque 44" 7 (ideque-length (ideque 1 2 3 4 5 6 7)))
(test "ideque 45" 0 (ideque-length (ideque)))
(test "ideque 46" '() (ideque->list (ideque-append)))
(test "ideque 47" '() (ideque->list (ideque-append (ideque) (ideque))))
(test "ideque 48" '(1 2 3 a b c d 5 6 7 8 9)
      (ideque->list (ideque-append (ideque 1 2 3)
                                   (ideque 'a 'b 'c 'd)
                                   (ideque)
                                   (ideque 5 6 7 8 9))))
(test "ideque 49" '() (ideque->list (ideque-reverse (ideque))))
(test "ideque 50" '(5 4 3 2 1) (ideque->list (ideque-reverse (ideque 1 2 3 4 5))))
(test "ideque 51" 0 (ideque-count odd? (ideque)))
(test "ideque 52" 3 (ideque-count odd? (ideque 1 2 3 4 5)))
(test "ideque 53" '((1 a) (2 b) (3 c))
      (ideque->list (ideque-zip (ideque 1 2 3) (ideque 'a 'b 'c 'd 'e))))
(test "ideque 54" '((1 a x) (2 b y) (3 c z))
      (ideque->list (ideque-zip (ideque 1 2 3 4 5)
                                (ideque 'a 'b 'c 'd 'e)
                                (ideque 'x 'y 'z))))
(test "ideque 55" '((1) (2) (3))
      (ideque->list (ideque-zip (ideque 1 2 3))))
(test "ideque 56" '()
      (ideque->list (ideque-zip (ideque 1 2 3) (ideque))))


;; ;; "ideque/mapping"
(test "ideque 57" #t (ideque-empty? (ideque-map list (ideque))))
(test "ideque 58" '(-1 -2 -3 -4 -5) (ideque->list (ideque-map - (ideque 1 2 3 4 5))))
(test "ideque 59" '(-1 -3 5 -8)
      (ideque->list (ideque-filter-map (lambda (x) (and (number? x) (- x)))
                                       (ideque 1 3 'a -5 8))))
(test "ideque 60" '(5 4 3 2 1)
      (let ((r '()))
        (ideque-for-each (lambda (n) (set! r (cons n r)))
                         (ideque 1 2 3 4 5))
        r))
(test "ideque 61" '(1 2 3 4 5)
      (let ((r '()))
        (ideque-for-each-right (lambda (n) (set! r (cons n r)))
                               (ideque 1 2 3 4 5))
        r))
(test "ideque 62" '(5 4 3 2 1 . z)
      (ideque-fold cons 'z (ideque 1 2 3 4 5)))
(test "ideque 63" '(1 2 3 4 5 . z)
      (ideque-fold-right cons 'z (ideque 1 2 3 4 5)))
(test "ideque 64" '(a a b b c c)
      (ideque->list (ideque-append-map (lambda (x) (list x x))
                                       (ideque 'a 'b 'c))))


;; ;; "ideque/filtering"
(test "ideque 65" '(1 3 5)
      (ideque->list (ideque-filter odd? (ideque 1 2 3 4 5))))
(test "ideque 66" '(2 4)
      (ideque->list (ideque-remove odd? (ideque 1 2 3 4 5))))
(test "ideque 67" '((1 3 5) (2 4))
      (receive xs (ideque-partition odd? (ideque 1 2 3 4 5))
        (map ideque->list xs)))


;; ;; "ideque/searching"
(test "ideque 68" 3    (ideque-find number? (ideque 'a 3 'b 'c 4 'd) (lambda () 'boo)))
(test "ideque 69" 'boo (ideque-find number? (ideque 'a 'b 'c 'd) (lambda () 'boo)))
(test "ideque 70" #f   (ideque-find number? (ideque 'a 'b 'c 'd)))
(test "ideque 71" 4    (ideque-find-right number? (ideque 'a 3 'b 'c 4 'd) (lambda () 'boo)))
(test "ideque 72" 'boo (ideque-find-right number? (ideque 'a 'b 'c 'd) (lambda () 'boo)))
(test "ideque 73" #f   (ideque-find-right number? (ideque 'a 'b 'c 'd)))
(test "ideque 74" '(1 3 2)
      (ideque->list (ideque-take-while (lambda (n) (< n 5))
                                       (ideque 1 3 2 5 8 4 6 3 4 2))))
(test "ideque 75" '(5 8 4 6 3 4 2)
      (ideque->list (ideque-drop-while (lambda (n) (< n 5))
                                       (ideque 1 3 2 5 8 4 6 3 4 2))))
(test "ideque 76" '(3 4 2)
      (ideque->list (ideque-take-while-right (lambda (n) (< n 5))
                                             (ideque 1 3 2 5 8 4 6 3 4 2))))
(test "ideque 77" '(1 3 2 5 8 4 6)
      (ideque->list (ideque-drop-while-right (lambda (n) (< n 5))
                                             (ideque 1 3 2 5 8 4 6 3 4 2))))
(test "ideque 78" '()
      (ideque->list (ideque-take-while (lambda (n) (< n 5))
                                       (ideque 5 8 4 6 3 4 2 9))))
(test "ideque 79" '()
      (ideque->list (ideque-drop-while (lambda (n) (< n 5))
                                       (ideque 1 4 3 2 3 4 2 1))))
(test "ideque 80" '()
      (ideque->list (ideque-take-while-right (lambda (n) (< n 5))
                                             (ideque 5 8 4 6 3 4 2 9))))
(test "ideque 81" '()
      (ideque->list (ideque-drop-while-right (lambda (n) (< n 5))
                                             (ideque 1 3 2 4 3 2 3 2))))
(test "ideque 82" '((1 3 2) (5 8 4 6 3 4 2))
      (receive xs (ideque-span (lambda (n) (< n 5))
                               (ideque 1 3 2 5 8 4 6 3 4 2))
        (map ideque->list xs)))
(test "ideque 83" '((5 8) (4 6 3 4 2 9))
      (receive xs (ideque-break (lambda (n) (< n 5))
                                (ideque 5 8 4 6 3 4 2 9))
        (map ideque->list xs)))
(test "ideque 84" 3 (ideque-any (lambda (x) (and (number? x) x))
                                (ideque 'a 3 'b 'c 4 'd 'e)))
(test "ideque 85" 5 (ideque-any (lambda (x) (and (number? x) x))
                                (ideque 'a 'b 'c 'd 'e 5)))
(test "ideque 88" #f (ideque-any (lambda (x) (and (number? x) x))
                                 (ideque 'a 'b 'c 'd 'e)))
(test "ideque 89" 9 (ideque-every (lambda (x) (and (number? x) x))
                                  (ideque 1 5 3 2 9)))
(test "ideque 90" #f (ideque-every (lambda (x) (and (number? x) x))
                                   (ideque 1 5 'a 2 9)))
;; check if we won't see further once we found the result
(test "ideque 91" 1 (ideque-any (lambda (x) (and (odd? x) x))
                                (ideque 2 1 'a 'b 'c 'd)))
(test "ideque 92" #f (ideque-every (lambda (x) (and (odd? x) x))
                                   (ideque 1 2 'a 'b 'c 'd)))

(test "ideque 93" '(1 2 3) (generator->list (ideque->generator (ideque 1 2 3))))
(test "ideque 94" '() (generator->list (ideque->generator (ideque))))
(test "ideque 95" '(1 2 3) (ideque->list (generator->ideque (generator 1 2 3))))
(test "ideque 96" '() (ideque->list (generator->ideque (generator))))

