 # Dimension = {row} -> String
 # Metric = {row} -> Number
 # [Metric] = {row} -> [Number]
-
-aggregartion = {
-  sum: (values) ->
-    s = 0
-    s += v for v in values
-    return s
-
-  average: (values) ->
-    s = 0
-    s += v for v in values
-    return s / values.length
-}
 
 sortedUniq = (arr) ->
   u = []


  doPlot(
    svg
    -> {data, scale:{}, size}
    plot
  )
  return

facet.makeData = ({selector, size, dataSpec, plot}) ->
  dimensions = {}
  for name, dimensionSpec of dataSpec.dimensions
    dimensions[name] = make_dimension(name, dimensionSpec)

  metrics = {}
  for name, metricSpec of dataSpec.metrics
    metrics[name] = make_metric(name, metricSpec)



  return {
    selector
    size
    data
    plot
  }


    newObj[k] = v
  return newObj

makeArray = (obj) ->
  if obj? then (if obj.splice then obj else [obj]) else []

acc = (column) ->
  throw "no such column" unless column?
  return column if typeof column is 'function'
  return (d) -> d[column]

cross = (arrays) ->
  vectorName = []
  vectorValues = []
  retLength = 1
  for k,vs of arrays
    return [] unless vs.splice
    vectorName.push(k)
    vectorValues.push(vs)
    retLength *= vs.length

  return [] unless vectorValues.length

  ret = []
  i = 0
  while i < retLength
    row = {}
    k = i
    for vs,j in vectorValues
      t = k % vs.length
      row[vectorName[j]] = vs[t]
      k = Math.floor(k / vs.length)

    ret[i] = row
    i++

  return ret


window.tile = {
  vertical: (rect, datas) ->
    total = 0
    for d in datas
      total += d

    scale = rect.height / total
    rects = []
    y = 0
    for d in datas
      h = d * scale
      rects.push {
        x: 0
        y: y
        width: rect.width
        height: h
      }
      y += h

    return rects
}

# ------------------------------------------------------------------

# Valid:
# {name, column} = {name}
# {name, type: all }
facet.dimension = do ->
  binMap = {
    millisecond: 1
    second: 1000
    minute: 60 * 1000
    hour: 60 * 60 * 1000
    day: 24 * 60 * 60 * 1000
    week: 7 * 24 * 60 * 60 * 1000
  }
  return (name, {column, type, bin}) ->
    throw "name can not start with $  (#{name})" if name[0] is '$'
    column = name.toLowerCase() unless column
    switch type
      when 'all'
        fn = (row) -> '$all'
      when 'categorical'
        throw 'categorical dimension must have column' unless column
        fn = (row) -> row[column]
      when 'ordinal'
        throw 'ordinal dimension must have column' unless column
        fn = (row) -> row[column]
      when 'continuous'
        throw 'continuous dimension must have column' unless column
        throw 'continuous dimension must have bin' unless bin
        bin = binMap[bin] if binMap[bin]
        fn = (row) -> Math.floor(row[column] / bin)
      else
        throw 'must have a type'
    fn.$name = name
    return fn

# Valid:
# {column}
# {agg: 'count' }
facet.metric = do ->
  aggregartion = {
    sum: (values) ->
      sum = 0
      for v in values
        sum += v
      return sum

    average: (values) ->
      sum = 0
      for v in values
        sum += v
      return sum / values.length

    uniq: (values) ->
      seen = {}
      count = 0
      for v in values
        continue if seen[v]
        count++
        seen[v] = 1
      return count

    common: (values) ->
      counts = {}
      # to do
      return values[0]
  }
  return (name, {column, agg}) ->
    throw "name can not start with $  (#{name})" if name[0] is '$'
    column = name.toLowerCase() unless column
    if agg is 'const'
      fn = (rows) -> 1
    else if agg is 'count'
      fn = (rows) -> rows.length
    else if column
      a = aggregartion[agg]
      throw "invalid agg (#{agg})" unless a
      fn = (rows) -> a(rows.map((d) -> d[column]))
    else
      throw "needs agg == 'count' or column"
    fn.$name = name
    return fn


# combine =
#  sort: <dimension or metric name>
#  order: asc | desc
#  skip: <number>
#  limit: <number>
facet.data = (rows) ->
  splits = []
  dimensions = {}
  metrics = {}

  makeSac = ({split, apply, combine}, breakdown) -> (rows) ->
    buckets = {}
