(library (srfi :60 integer-bits)
  (export logand bitwise-and logior bitwise-ior logxor bitwise-xor lognot
          bitwise-not bitwise-if bitwise-merge logtest any-bits-set? logcount
          bit-count integer-length log2-binary-factors first-set-bit logbit?
          bit-set? copy-bit bit-field copy-bit-field ash arithmetic-shift
          rotate-bit-field reverse-bit-field integer->list integer->list
          list->integer booleans->integer)
  (import (rnrs))

  (define logand
    (case-lambda
      [() (bitwise-and)]
      [(i) i]
      [(i j) (bitwise-and i j)]
      [(i j k) (bitwise-and i j k)]
      [args (apply bitwise-and args)]))

  (define logior
    (case-lambda
      [() (bitwise-ior)]
      [(i) i]
      [(i j) (bitwise-ior i j)]
      [(i j k) (bitwise-ior i j k)]
      [args (apply bitwise-ior args)]))
  
  (define logxor
    (case-lambda
      [() (bitwise-xor)]
      [(i) i]
      [(i j) (bitwise-xor i j)]
      [(i j k) (bitwise-xor i j k)]
      [args (apply bitwise-xor args)]))

  (define lognot (lambda (n) (bitwise-not n)))

  (define bitwise-merge (lambda (m n0 n1) (bitwise-if m n0 n1)))

  (define logtest (lambda (j k) (not (zero? (logand j k)))))
  (define any-bits-set? (lambda (j k) (not (zero? (logand j k)))))

  (define logcount
    (lambda (n)
      (if (< n 0)
          (bitwise-bit-count (bitwise-not n))
          (bitwise-bit-count n))))

  (define bit-count
    (lambda (n)
      (if (< n 0)
          (bitwise-bit-count (bitwise-not n))
          (bitwise-bit-count n))))

  (define integer-length (lambda (n) (bitwise-length n)))

  (define log2-binary-factors (lambda (n) (bitwise-first-bit-set n)))
  (define first-set-bit (lambda (n) (bitwise-first-bit-set n)))

  (define logbit? (lambda (i n) (bitwise-bit-set? n i)))
  (define bit-set? (lambda (i n) (bitwise-bit-set? n i))) 

  (define copy-bit (lambda (i n b) (bitwise-copy-bit n i (if b 1 0))))

  (define bit-field (lambda (n s e) (bitwise-bit-field n s e)))

  (define copy-bit-field
    (lambda (to from s e)
      (bitwise-copy-bit-field to s e from)))

  (define ash (lambda (n count) (bitwise-arithmetic-shift n count)))
  (define arithmetic-shift
    (lambda (n count)
      (bitwise-arithmetic-shift n count)))

  (define rotate-bit-field
    (lambda (n count start end)
      (bitwise-rotate-bit-field n start end count)))

  (define reverse-bit-field
    (lambda (n start end)
      (bitwise-reverse-bit-field n start end)))

  (define integer->list
    (case-lambda
      [(k len) (let loop ([i len] [ls '()])
                 (if (fx=? i 0)
                     ls
                     (let ([i (fx- i 1)])
                       (loop i (cons (bitwise-bit-set? k i) ls)))))]
      [(k) (integer->list k (bitwise-length k))]))

  (define list->integer
    (lambda (ls)
      (let loop ([ls ls] [i 0] [n 0])
        (if (null? ls)
            n
            (loop (cdr ls) (fx+ i 1) (bitwise-copy-bit n i (if (car ls) 1 0)))))))

  (define booleans->integer
    (lambda args
      (list->integer args))))
