 (ns bytebuf.spec
   (:refer-clojure :exclude [type read])
   (:require [bytebuf.types :as types]
+            [bytebuf.proto :as proto :refer [IStaticSize]]
             [bytebuf.buffer :as buffer]))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn associative-static-spec
  [data dict types]
  (reify
    ISpecSize
    (size [_]
      (reduce #(+ %1 (types/size %2)) 0 types))
    (size [_ data]
      (reduce #(+ %1 (types/size %2)) 0 types))

    IReadableSpec
    (read [_ buff]
      (reduce (fn [acc [name t]]
                (assoc acc name (types/read t buff)))
              {}
              data))

    IWritableSpec
    (write [_ buff data']
      (reduce (fn [buff [fieldname type]]
                (let [value (get data' fieldname nil)]
                  (types/write type buff value)
                  buff))
              buff data))

    IAssocReadableSpec
    (read-field [_ buff field]
      (let [ftype (get dict field)
            startpos (reduce (fn [acc [key val]]
                               (if (= key field)
                                 (reduced acc)
                                 (+ acc (types/size val))))
                             0 data)]
        ;; Set the buffer position
        (buffer/seek buff startpos)
        (types/read ftype buff)))))

(defn associative-dynamic-spec
  [])

;; (defprotocol ISpec
;;   (type [_] "Get the type of spec."))

(defprotocol IReadableSpec
  (read [_ buff start] "Read all data from buffer."))

(defprotocol IWritableSpec
  (write [_ buff start data] "Read all data from buffer."))

;; (defprotocol IAssocReadableSpec
;;   (read-field [_ buff field] "Read one concrete field from buffer."))

;; (defprotocol IAssocWritableSpec
;;   (write-field [_ buff field data] "Read one concrete field from buffer."))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Types implementation
