#lang scheme/base
(require "depend.ss"
         "line.ss"
         "phrase.ss" 
         (rename-in "kvs.ss" 
                    (kvs-writertable header-writertable)
                    (kvs-writer-ref header-writer-ref)
                    )
         (only-in "kvs.ss" kv->string kvs->string)
         
         
         )
(define (header->string h)
  (string-append (kv->string h 
                             #:delim ": " 
                             #:encode-val (header-writer-ref (car h) identity))
                 (line-term/string)))
(define (headers->string headers (end? #t))
  (define (helper result)
    (string-append result 
                   (if end? 
                       (line-term/string)
                       "")))
  (helper (string-join (map header->string (kvs/list->kvlist headers)) "")))
(define (headers->input headers (end? #t))
  (open-input-abytes (headers->string headers end?)))
(define (string->header line)
  (define (helper match)
    (if match
        (let ((name (cadr match))
              (value (caddr match)))
          (cons name ((kvs-reader-ref name identity) value)))
        #f))
  (helper (regexp-match #px"^([^:]+)\\s*:\\s*(.+)$" line)))
(define p:header-field-char
  (char-when (lambda (c) 
               (and (char<=? (integer->char 33) c (integer->char 126))
                  (not (char=? c #\:))))))
(define p:header-def 
  (seq header <- (one-many p:header-field-char)
       (token #\:)
       (return header))) 
(define (read-header in) 
  (let-values (((v IN)
                (p:header-def (make-input in))))
    (if (failed? v)         #f
                (string->header (read-folded-line in)))))
(define (read-headers in) 
  (define (return headers)
        (let-values (((v IN)
                  ((bytes= (line-term/bytes)) (make-input in))))
      (unless (failed? v) 
        (read-folded-line in)))
    (reverse headers))
  (define (helper headers)
    (let ((header (read-header in))) 
      (if (not header)           (return headers) 
          (helper (cons header headers)))))
  (helper '())) 
(provide/contract 
 (header->string (-> kv? string?))
 (read-header (-> input-port? (or/c false/c kv?)))
 (read-headers (-> input-port? kvs/list?))
 (headers->string (->* (kvs/list?)
                       (boolean?)
                       string?))
 (headers->input (->* (kvs/list?)
                      (boolean?)
                      input-port?))
 )