#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?])