;;;; Copyright 2002, Jonathan Bachrach.  See file TERMS.

(use goo/boot)
(use goo/fun)
(use goo/class)
(use goo/macros)
(use goo/any)
(use goo/log)
(use goo/chr)
(use goo/mag)
(use goo/math)
(use goo/types)
(use goo/cols/col)
(use goo/cols/colx)
(use goo/cols/seq)

(exported
 ;; returns destructively reversed sequence.
 (dg rev! (x|<seq!> => <seq!>))
 ;; returns destructively concatenated sequences.
 (dg cat! (x|<seq!> more|... => <seq!>))

 (dg push! (l|<seq!> x|<any> => <seq!>))
 (dg pop! (l|<seq!> => (tup new-col|<seq!> value|<any>)))

 ;; replaces subsequence in range between from and below of dst with
 ;; contents of src.
 (dg sub-setter (dst|<seq!> src|<seq> from|<int> below|<int>))
 (dg sub*-setter (dst|<seq!> src|<seq> from|<int>))

 ;; inserts e into x below index before
 (dg ins! (x|<seq!> e|<any> before|<int> => <seq!>))

 ;; returns sequence with all v's deleted from x.
 (dg del-vals! (x|<seq!> v|<any>  => <seq!>))

 ;; returns sequence with all duplicates removed.
 (dg del-dups! (x|<seq!> => <seq!>))

 (dg sort! (x|<seq!> => <seq!>))
 (dg sort-by! (x|<seq!> test|<fun> => <seq!>))

 ;; deprecated
 (dg alter (dst|<seq!> src|<seq> from|<int> below|<int> => <seq!>))

)

;; TODO: REMOVE PERHAPS?
(dm rev! (x|<seq!> => <seq!>) (rev x))
(dm cat! (x|<seq!> more|... => <seq!>) (app cat more))
(dm push! (l|<seq!> x|<any> => <seq!>) (push l x))
(dm pop! (l|<seq!> => (tup new-col|<seq!> value|<any>)) (pop l))
(dm ins! (x|<seq!> v|<any> before|<int> => <seq!>) (ins x v before))
(dm del-vals! (x|<seq!> v|<any>  => <seq!>) (del-vals x v))
(dm del-dups! (x|<seq!> => <seq!>) (del-dups x))

(dm into (dst|<seq!> src|<seq> => <seq!>)
  (rep in ((ed (enum dst)) (es (enum src)))
    (if (or (fin? es) (fin? ed))
        dst
        (seq (set (now ed) (now es))
             (in (nxt ed) (nxt es))))))

(dm sub-setter (src|<seq!> dst|<seq> from|<int> below|<int> => <seq!>)
  (def dst-len|<int> (len dst))
  (def src-len|<int> (len src))
  (def del-len|<int> (- below from))
  (if (= del-len src-len);;  Can modify in place?
      (rep find ((d (enum dst)) (i 0))
        (if (= i from)
            (rep in ((d d) (s (enum src)))
              (if (fin? s)
                  dst
                  (seq (set (now d) (now s)) (in (nxt d) (nxt s)))))
            (find (nxt d) (+ i 1))))
      ;; Don't know if dst is stretchy so we have to create a new one
      (let ((new-len (+ (- dst-len del-len) src-len))
            (ndst    (fab (class-of dst) new-len)))
        (rep copy ((nd (enum ndst)) (d (enum dst)) (i 0))
          (if (= i from)
              (rep insert ((nd nd) (s (enum src)))
                (if (fin? s)
                    (rep skip ((d d) (i from))
                      (if (= i below)
                          (rep onto ((nd nd) (d d) (i below))
                            (if (= i dst-len)
                                ndst
                                (seq (set (now nd) (now d))
                                     (onto (nxt nd) (nxt d) (+ i 1)))))
                          (skip (nxt d) (+ i 1))))
                    (seq (set (now nd) (now s))
                         (insert (nxt nd) (nxt s)))))
              (seq (set (now nd) (now d))
                   (copy (nxt nd) (nxt d) (+ i 1))))))))

(dm sub*-setter (src|<seq!> dst|<seq> from|<int> => <seq!>)
  (set (sub dst from (len dst)) src))

(dm sort! (items|<seq!> => <seq!>)
  (sort-by! items <))

;; vec.goo now provides a quicksort, so do not use the horrible list bubble-sort
;;(dm sort-by! (items|<seq!> test|<fun> => <seq!>)
;;  (col-res items (sort-by! (as <lst> items) test)))

;; TODO: DEPRECATED
(dm alter (dst|<seq!> src|<seq> from|<int> below|<int> => <seq!>)
  (rep in ((d (enum dst)) (s (enum src)))
    (if (or (fin? d) (fin? s))
        dst
        (seq (set (now d)  (now s)) (in (nxt d) (nxt s))))))


