(module table mzscheme
  (require "private/require.ss")
  (require-contracts)
  (require-lists)
  (require-etc)
  (require (lib "class.ss")
           "private/contracts.ss"
           "table/table-interface.ss"
           "table/unordered-table.ss"
           "table/ordered-table.ss"
           "table/hashed-table.ss")
  (define key-list/c (listof any/c))
  (define value-list/c (listof any/c))
  (define key-value-sexp/c (listof (list/c any/c any/c)))
  (define key-value-alist/c (listof (cons/c any/c any/c)))
  (define key-value-list/c
    (flat-rec-contract key-value-list
      empty?
      (cons/c any/c (cons/c any/c key-value-list))))
  (provide/contract
      [table? predicate/c]
   [table/c flat-contract?]
   [non-empty-table/c flat-contract?]
   [table-of/c (flat-contract/c flat-contract/c . -> . flat-contract?)]
   [non-empty-table-of/c
    (flat-contract/c flat-contract/c . -> . flat-contract?)]
      [make-ordered ([comparison/c] key-value-list/c . ->* . [table/c])]
   [make-hashed ([hash-fn/c equality/c] key-value-list/c . ->* . [table/c])]
   [make-unordered ([equality/c] key-value-list/c . ->* . [table/c])]
   [make-eq ([] key-value-list/c . ->* . [table/c])]
   [make-eqv ([] key-value-list/c . ->* . [table/c])]
   [make-equal ([] key-value-list/c . ->* . [table/c])]
   [sexp->ordered (comparison/c key-value-sexp/c . -> . table/c)]
   [sexp->hashed (hash-fn/c equality/c key-value-sexp/c . -> . table/c)]
   [sexp->unordered (equality/c key-value-sexp/c . -> . table/c)]
   [sexp->eq (key-value-sexp/c . -> . table/c)]
   [sexp->eqv (key-value-sexp/c . -> . table/c)]
   [sexp->equal (key-value-sexp/c . -> . table/c)]
   [alist->ordered (comparison/c key-value-alist/c . -> . table/c)]
   [alist->hashed (hash-fn/c equality/c key-value-alist/c . -> . table/c)]
   [alist->unordered (equality/c key-value-alist/c . -> . table/c)]
   [alist->eq (key-value-alist/c . -> . table/c)]
   [alist->eqv (key-value-alist/c . -> . table/c)]
   [alist->equal (key-value-alist/c . -> . table/c)]
   [lists->ordered (comparison/c key-list/c value-list/c . -> . table/c)]
   [lists->hashed (hash-fn/c equality/c key-list/c value-list/c . -> . table/c)]
   [lists->unordered (equality/c key-list/c value-list/c . -> . table/c)]
   [lists->eq (key-list/c value-list/c . -> . table/c)]
   [lists->eqv (key-list/c value-list/c . -> . table/c)]
   [lists->equal (key-list/c value-list/c . -> . table/c)]
      [keys (table/c . -> . (listof any/c))]
   [rename table-values values (table/c . -> . (listof any/c))]
   [to-sexp (table/c . -> . (listof (list/c any/c any/c)))]
   [to-alist (table/c . -> . (listof (cons/c any/c any/c)))]
   [rename table-empty? empty? (table/c . -> . boolean?)]
   [size (table/c . -> . natural-number/c)]
   [contains? (any/c table/c . -> . boolean?)]
   [lookup ([any/c table/c] [(-> any) (any/c . -> . any)] . opt-> . any)]
   [lookup/key
    ([any/c table/c] [(-> any) (any/c any/c . -> . any)] . opt-> . any)]
   [insert (any/c any/c table/c . -> . non-empty-table/c)]
   [rename table-remove remove (any/c table/c . -> . table/c)]
   [update (any/c (any/c any/c . -> . any) table/c . -> . table/c)]
   [update/value (any/c (any/c . -> . any) table/c . -> . table/c)]
   [update/insert
    (any/c (any/c any/c . -> . any) any/c table/c . -> . non-empty-table/c)]
   [update/insert/value
    (any/c (any/c . -> . any) any/c table/c . -> . non-empty-table/c)]
   [select (non-empty-table/c . -> . (values any/c any/c))]
   [select/key (non-empty-table/c . -> . any)]
   [select/value (non-empty-table/c . -> . any)]
   [clear (table/c . -> . table/c)]
   [rename table-fold fold
           ((any/c any/c any/c . -> . any) any/c table/c . -> . any)]
   [rename table-fold/key fold/key
           ((any/c any/c . -> . any) any/c table/c . -> . any)]
   [rename table-fold/value fold/value
           ((any/c any/c . -> . any) any/c table/c . -> . any)]
   [rename table-for-each for-each
           ((any/c any/c . -> . any) table/c . -> . void?)]
   [rename table-for-each/key for-each/key
           ((any/c . -> . any) table/c . -> . void?)]
   [rename table-for-each/value for-each/value
           ((any/c . -> . any) table/c . -> . void?)]
   [rename table-map map
           ((any/c any/c . -> . any) table/c . -> . table/c)]
   [rename table-map/key map/key
           ((any/c . -> . any) table/c . -> . table/c)]
   [rename table-map/value map/value
           ((any/c . -> . any) table/c . -> . table/c)]
   [rename table-filter filter
           ((any/c any/c . -> . any/c) table/c . -> . table/c)]
   [rename table-filter/key filter/key
           ((any/c . -> . any/c) table/c . -> . table/c)]
   [rename table-filter/value filter/value
           ((any/c . -> . any/c) table/c . -> . table/c)]
   [all? ((any/c any/c . -> . any/c) table/c . -> . boolean?)]
   [all?/key ((any/c . -> . any/c) table/c . -> . boolean?)]
   [all?/value ((any/c . -> . any/c) table/c . -> . boolean?)]
   [rename table-andmap andmap
           ((any/c any/c . -> . any/c) table/c . -> . boolean?)]
   [rename table-andmap/key andmap/key
           ((any/c . -> . any/c) table/c . -> . boolean?)]
   [rename table-andmap/value andmap/value
           ((any/c . -> . any/c) table/c . -> . boolean?)]
   [any? ((any/c any/c . -> . any/c) table/c . -> . boolean?)]
   [any?/key ((any/c . -> . any/c) table/c . -> . boolean?)]
   [any?/value ((any/c . -> . any/c) table/c . -> . boolean?)]
   [rename table-ormap ormap
           ((any/c any/c . -> . any/c) table/c . -> . boolean?)]
   [rename table-ormap/key ormap/key
           ((any/c . -> . any/c) table/c . -> . boolean?)]
   [rename table-ormap/value ormap/value
           ((any/c . -> . any/c) table/c . -> . boolean?)]
   [union
    ([table/c table/c] [(any/c any/c any/c . -> . any/c)] . opt-> . table/c)]
   [union/value
    ([table/c table/c] [(any/c any/c . -> . any/c)] . opt-> . table/c)]
   [intersection
    ([table/c table/c] [(any/c any/c any/c . -> . any/c)] . opt-> . table/c)]
   [intersection/value
    ([table/c table/c] [(any/c any/c . -> . any/c)] . opt-> . table/c)]
   [difference (table/c table/c . -> . table/c)]
   [subtable? ((any/c any/c . -> . boolean?) table/c table/c . -> . boolean?)]
   [rename table-equal? equal?
           ((any/c any/c . -> . boolean?) table/c table/c . -> . boolean?)]
   )
      (define (get-keys kvs)
    (if (null? kvs)
        null
        (cons (first kvs) (get-keys (rest (rest kvs))))))
      (define (get-values kvs)
    (if (null? kvs)
        null
        (cons (second kvs) (get-values (rest (rest kvs))))))
    
            (define lists->ordered make-ordered-table)
  (define (sexp->ordered compare sexp)
    (lists->ordered compare (map first sexp) (map second sexp)))
  (define (alist->ordered compare alist)
    (lists->ordered compare (map car alist) (map cdr alist)))
  (define (make-ordered compare . kvs)
    (lists->ordered compare (get-keys kvs) (get-values kvs)))
    
            (define lists->unordered make-unordered-table)
  (define (sexp->unordered equ? sexp)
    (lists->unordered equ? (map first sexp) (map second sexp)))
  (define (alist->unordered equ? alist)
    (lists->unordered equ? (map car alist) (map cdr alist)))
  (define (make-unordered equ? . kvs)
    (lists->unordered equ? (get-keys kvs) (get-values kvs)))
    
            (define lists->hashed make-hashed-table)
  (define (sexp->hashed hash equ? sexp)
    (lists->hashed hash equ? (map first sexp) (map second sexp)))
  (define (alist->hashed hash equ? alist)
    (lists->hashed hash equ? (map car alist) (map cdr alist)))
  (define (make-hashed hash equ? . kvs)
    (lists->hashed hash equ? (get-keys kvs) (get-values kvs)))
            (define lists->eq (curry lists->hashed eq-hash-code eq?))
  (define sexp->eq (curry sexp->hashed eq-hash-code eq?))
  (define alist->eq (curry alist->hashed eq-hash-code eq?))
  (define (make-eq . kvs)
    (lists->eq (get-keys kvs) (get-values kvs)))
            (define lists->eqv (curry lists->unordered eqv?))
  (define sexp->eqv (curry sexp->unordered eqv?))
  (define alist->eqv (curry alist->unordered eqv?))
  (define (make-eqv . kvs)
    (lists->eqv (get-keys kvs) (get-values kvs)))
            (define lists->equal (curry lists->hashed equal-hash-code equal?))
  (define sexp->equal (curry sexp->hashed equal-hash-code equal?))
  (define alist->equal (curry alist->hashed equal-hash-code equal?))
  (define (make-equal . kvs)
    (lists->equal (get-keys kvs) (get-values kvs)))
      (define (to-sexp table)
    (send table sexp))
      (define (to-alist table)
    (send table alist))
      (define (keys table)
    (send table keys))
      (define (table-values table)
    (send table values))
      (define (insert key value table)
    (send table insert key value))
          (define (lookup key table . rest)
    (send table lookup key . rest))
          (define (lookup/key key table . rest)
    (send table lookup/key key . rest))
      (define (table-remove key table)
    (send table remove key))
        (define (update key transform table)
    (send table update key transform))
        (define (update/value key transform table)
    (send table update/value key transform))
          (define (update/insert key transform value table)
    (send table update/insert key transform value))
          (define (update/insert/value key transform value table)
    (send table update/insert/value key transform value))
      (define (select table)
    (send table select))
      (define (select/key table)
    (send table select/key))
      (define (select/value table)
    (send table select/value))
      (define (table-empty? table)
    (send table empty?))
      (define (clear table)
    (send table clear))
      (define (size table)
    (send table size))
      (define (contains? key table)
    (send table contains? key))
      (define (table-fold combine init table)
    (send table fold combine init))
      (define (table-fold/key combine init table)
    (send table fold/key combine init))
      (define (table-fold/value combine init table)
    (send table fold/value combine init))
      (define (table-for-each action table)
    (send table for-each action))
      (define (table-for-each/key action table)
    (send table for-each/key action))
      (define (table-for-each/value action table)
    (send table for-each/value action))
      (define (table-map transform table)
    (send table map transform))
      (define (table-map/key transform table)
    (send table map/key transform))
      (define (table-map/value transform table)
    (send table map/value transform))
      (define (table-filter predicate table)
    (send table filter predicate))
      (define (table-filter/key predicate table)
    (send table filter/key predicate))
      (define (table-filter/value predicate table)
    (send table filter/value predicate))
      (define (all? predicate table)
    (send table all? predicate))
  (define table-andmap all?)
      (define (all?/key predicate table)
    (send table all?/key predicate))
  (define table-andmap/key all?/key)
      (define (all?/value predicate table)
    (send table all?/value predicate))
  (define table-andmap/value all?/value)
      (define (any? predicate table)
    (send table any? predicate))
  (define table-ormap any?)
      (define (any?/key predicate table)
    (send table any?/key predicate))
  (define table-ormap/key any?/key)
      (define (any?/value predicate table)
    (send table any?/value predicate))
  (define table-ormap/value any?/value)
              (define (union one two . rest)
    (send one union two . rest))
              (define (union/value one two . rest)
    (send one union/value two . rest))
              (define (intersection one two . rest)
    (send one intersection two . rest))
              (define (intersection/value one two . rest)
    (send one intersection/value two . rest))
        (define (difference one two)
    (send one difference two))
          (define (subtable? value=? one two)
    (send one subtable? value=? two))
          (define (table-equal? value=? one two)
    (send one equal? value=? two))
  )