#lang scheme/base
(require net/url
         scheme/contract
         (only-in srfi/1/list append-map))
(define-struct csv () #:transparent)
(define-struct (sheet csv) (rows) #:transparent)
(define-struct (row csv) (cells) #:transparent)
(define-struct (cell csv) (value) #:transparent)
(define (create-sheet . rows)
  (make-sheet (normalize rows)))
(define (create-row . cells)
  (make-row (normalize cells)))
(define create-cell
  make-cell)
(define (normalize data)
  (cond [(null? data) null]
        [(pair? data) (append-map normalize data)]
        [else         (list data)]))
(define (quotable-value? val)
  (or (boolean? val)
      (number? val)
      (string? val)
      (symbol? val)
      (bytes? val)
      (url? val)))
(define rows/c
  (flat-rec-contract row-or-row-list/c
    row? 
    (listof row-or-row-list/c)))
(define cells/c
  (flat-rec-contract cell-or-cell-list/c
    cell?
    (listof cell-or-cell-list/c)))
(provide/contract
 [struct csv         ()]
 [struct (sheet csv) ([rows (listof row?)])]
 [struct (row csv)   ([cells (listof cell?)])]
 [struct (cell csv)  ([value quotable-value?])]
 [create-sheet       (->* () () #:rest (listof rows/c) sheet?)]
 [create-row         (->* () () #:rest (listof cells/c) row?)]
 [create-cell        (-> quotable-value? cell?)]
 [quotable-value?    procedure?])