 	   Creator
 	   Metadata
 	   Model
-	   ])
- (:import [org.joda.time
-	   DateMidnight
 	   ])
  )
 


;;----------------------------------------

(def median-length (/ max-length 2))
(def median-weight (/ max-weight 2))

(def longer-whales 
     (dfilter whales (str "length>" median-length) '(:length) #(> % median-length)))

(def heavier-whales
     (dfilter whales (str "weight>" median-weight) '(:weight) #(> % median-weight)))

;;----------------------------------------
;; demonstrate transformation - only selecting a subset of the
;; attributes from one model into another. We may support synthetic
;; attributes...
;;----------------------------------------

(def longer-whales-weight
     (dtransform longer-whales "weight" :time :version :time :version :weight))

(def #^Model heavier-whales-length
     (dtransform heavier-whales "length" :time :version :time :version :length))

;;----------------------------------------
;; demonstrate transformation - a synthetic field - metric tons per metre
;;----------------------------------------

(dtransform
 whales
 "tonsPerMetre"
 :time
 :version 
 :time
 :version 
 (list
  :tonsPerMetre
  Number
  '(:weight :length)
  (fn [weight length] (if (= length 0) 0 (/ weight length))))
 )

;;----------------------------------------
;; try a transformation on top of a filtration
;; e.g. select time, version, length from whales where type="narwhal"
;;----------------------------------------

(def narwhals-length
     (dtransform 
      (dfilter 
       whales
       "type=narwhal" 
       '(:type)
       #(= "narwhal" %))
      "length"
      :time
      :version
      :time
      :version
      :length)
     )

;;----------------------------------------
;; demonstrate reduction (sum)
;;----------------------------------------

(dcount whales "whales")
(dsum whales :length "whales")
(dsum whales :weight "whales")
(dcount heavier-whales-length "heavier-whales")
(dsum heavier-whales-length :length "heavier-whales")
(dsum longer-whales-weight :weight "longer-whales")
(dcount longer-whales-weight "longer-whales")

;;----------------------------------------
;; demonstrate splitting [and more reduction] - a pivot...
;;----------------------------------------

;; PROBLEM - 
;; tgt-model values must be same shape as intermediate model values...
;; EITHER: we prearrange the shape (preferred - complex - how do do this?)
;; OR: we could construct the tgt mode lazily (simpler - but concurrency issues)

;; (defn dpivot [#^Model src-model #^Keyword split-key #^boolean mutable #^String tgt-model-name #^IFn tgt-model-hook
;; 	      #^Keyword key-key #^Keyword version-key & attribute-key-types]
;;   (let [tgt-metadata (class-metadata
;; 		      (name (gensym "org.dada.demo.core.Pivot"))
;; 		      Object
;; 		      key-key
;; 		      version-key
;; 		      attribute-key-types)
;; 	tgt-model (model tgt-model-name tgt-metadata)]
;;     (insert *metamodel* tgt-model)
;;     (dsplit
;;      src-model
;;      split-key
;;      mutable
;;      (fn [#^Model model value]
;; 	 (connect (dcount model String value tgt-metadata) tgt-model)
;; 	 (tgt-model-hook model value)
;; 	 )
;;      ))
;;   )

(let [union-metadata (class-metadata
		      "org.dada.demo.whales.TypeCount"
		      Object
		      :key
		      :version
		      [:key String :version Integer :count Integer])
      union-model (model "Whales.union(count(split(type)))" union-metadata)
      ]
  (insert *metamodel* union-model)
  (dsplit
   whales
   :type
   false
   (fn [#^Model model value]
       (connect (dcount model String value union-metadata) union-model)
       (dsum model :length value)
       (dsum model :weight value)
       model ; TODO: do we really need to be able to override the model ? should threading go here ?
       )
   ))

(def #^NavigableSet dates (TreeSet.
	    (list
	    (DateMidnight. 2000 1 1)
	    (DateMidnight. 2001 1 1)
	    (DateMidnight. 2002 1 1)
	    (DateMidnight. 2003 1 1)
	    (DateMidnight. 2004 1 1)
	    (DateMidnight. 2005 1 1)
	    (DateMidnight. 2006 1 1)
	    (DateMidnight. 2007 1 1)
	    (DateMidnight. 2008 1 1)
	    (DateMidnight. 2009 1 1))))

(def year-names (map (fn [day] (.toString day "yyyy")) dates))

(eval (list 'deftype 'pivot-type (apply vector 'type 'version (map (fn [year-name] (symbol year-name)) year-names))))

(def attribute-names (apply collection "type" "version" year-names))

(import org.dada.core.Creator)
(import org.dada.core.Getter)
(import org.dada.core.GetterMetadata)

(def pivot-metadata
     (GetterMetadata.
      (proxy [Creator] [] (create [args] (apply pivot-type args)))
      (collection "type" "version") ;; key-attribute-names
      (apply collection String Integer (repeat 10 DateMidnight)) ;; attribute-types
      attribute-names
      (apply collection
	     (map
	      (fn [name]
		  (let [key (keyword (symbol name))]
		    (proxy [Getter] [] (get [instance] (key instance)))))
	      attribute-names))))

(def survey-metadata (class-metadata
		      (name (gensym "org.dada.demo.whales.Survey"))
		      Object
		      :time
		      :version
		      [:time DateMidnight :version Integer :count Integer]))

(def pivot-model (model (str (.getName whales) ".pivot(count(time))") pivot-metadata))
(insert *metamodel* pivot-model)

(dsplit
 whales
 :type
 false
 (fn [#^Model type-model type]
     (let [survey-model (model (str (.getName type-model) ".count(time)") survey-metadata)]
       (insert *metamodel* survey-model)
       ;; need some sort of transform here...'
       ;;(connect survey-model pivot-model)
       (dsplit
	type-model
	:time
	false
	(fn [time] (list (or (.lower dates time) time)))
	identity
	(fn [#^Model time-model time]
	    (connect (dcount time-model DateMidnight time survey-metadata) survey-model)
	    time-model))
       )
     type-model)
 )

;; TODO: Reducers need to support variable length set of attribute keys



(def attributes
     (list 
      :time Date
      :version (Integer/TYPE)
      :type String
      :length (Float/TYPE)
