"""
Take user input data and run it through the grid and tile rendering pipeline
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import json
import numpy as np
import lucid.scratch.atlas_pipeline.render_tile as render_tile
import lucid.scratch.atlas_pipeline.grid as grid
from tensorflow import gfile

# TODO: this is where we would distribute the tile processing
def run(render, aggregate, params, metadata, layout):
  
  gfile.MakeDirs("{directory}".format(**params))

  layers = params["n_cells"]
  for n_layer in layers:
    params["n_layer"] = n_layer
    tiles = grid.grid(metadata, layout, params)

    # TODO: write out summary? might be useful for the client-side renderer
    summary = summarize(tiles, params, layout)
    print("summary", summary)
    etiles = grid.enumerate_tiles(tiles)
    for i,t in enumerate(etiles):
      ti = t[0]
      tj = t[1]
      tile = t[2] 
      cells = grid.tile_cells(tile)

      print("aggregate tile", i+1, "/", len(etiles))
      tile_json = render_tile.aggregate_tile(cells, ti, tj, aggregate, params, metadata, layout, summary)
      filename = "{directory}/{name}-tile_{n_layer}_{n_tile}_{ti}_{tj}.json".format(ti=ti, tj=tj, **params)
      print("saving", filename)
      with gfile.Open(filename, 'w') as f:
        json.dump(tile_json, f)

      print("render tile", i+1, "/", len(etiles))
      tile_img = render_tile.render_tile(cells, ti, tj, render, params, metadata, layout, summary)
      filename = "{directory}/{name}-tile_{n_layer}_{n_tile}_{ti}_{tj}.png".format(ti=ti, tj=tj, **params)
      print("saving", filename)
      with gfile.Open(filename, 'w') as f:
        tile_img.save(f)

def summarize(tiles, params, layout):
  # calculate summary statistics that may be useful for rendering
  # e.g. max point density, bounds of x and y
  # we can also track the parameters for convenience
  summary = {
  }
  x = layout["x"]
  y = layout["y"]
  summary["x_min"] = np.min(x)
  summary["x_max"] = np.max(x)
  summary["y_min"] = np.min(y)
  summary["y_max"] = np.max(y)
  # the size of a cell in layout coordinate space
  summary["x_bin"] = abs(summary["x_max"] - summary["x_min"])/params["n_layer"]
  summary["y_bin"] = abs(summary["y_max"] - summary["y_min"])/params["n_layer"]

  # maximum density of a cell
  max_density = 0
  min_density = float("inf")
  num_cells = 0
  total_count = 0
  for t in grid.enumerate_tiles(tiles):
    tile = t[2] 
    cells = grid.tile_cells(tile) 
    keys = cells.keys()
    for i,key in enumerate(keys):
      num_cells += 1
      num_points = len(cells[key]["gi"])
      total_count += num_points
      if num_points > max_density:
        max_density = num_points
      if num_points < min_density:
        min_density = num_points
  summary["max_density"] = max_density
  summary["min_density"] = min_density
  summary["num_cells"] = num_cells
  summary["total_count"] = total_count
  # TODO: enable summarizing of meta attributes?
  return summary

@@ -786,16 +786,26 @@
 , layout
+, metadata
 )%0A    pr
@@ -1754,24 +1754,34 @@
 rams, layout
+, metadata
 ):%0A  # calcu
@@ -2408,39 +2408,283 @@
 )%0A  
-num_cells = 0%0A  total_count = 0
+user_max_density = 0%0A  user_min_density = float(%22inf%22)%0A%0A  num_cells = 0%0A  total_count = 0%0A  def density(cell, metadata):%0A    return len(cell%5B%22gi%22%5D)%0A  # if the user doesn't provide a scale function its just the density%0A  user_density = params.get(%22density_function%22, density)%0A
 %0A  f
@@ -2870,19 +2870,23 @@
 oints = 
-l
+d
 en
+sity
 (cells%5Bk
@@ -2888,24 +2888,94 @@
 lls%5Bkey%5D
-%5B%22gi%22%5D
+, metadata)%0A      user_num_points = user_density(cells%5Bkey%5D, metadata
 )%0A
+      %0A
       to
@@ -2990,32 +2990,74 @@
 t += num_points%0A
+      user_total_count += user_num_points%0A
       if num_poi
@@ -3182,118 +3182,386 @@
 s%0A  
-summary%5B%22max_density%22%5D = max_density%0A  summary%5B%22min_density%22%5D = min_density%0A  summary%5B%22num_cells%22%5D = num_cells
+    if user_num_points %3E user_max_density:%0A        user_max_density = user_num_points%0A      if user_num_points %3C user_min_density:%0A        user_min_density = user_num_points%0A  summary%5B%22max_density%22%5D = max_density%0A  summary%5B%22min_density%22%5D = min_density%0A  summary%5B%22total_count%22%5D = total_count%0A  summary%5B%22user_max_density%22%5D = max_density%0A  summary%5B%22user_min_density%22%5D = min_density
 %0A  s
@@ -3560,32 +3560,37 @@
 sity%0A  summary%5B%22
+user_
 total_count%22%5D = 
@@ -3601,16 +3601,56 @@
 l_count%0A
+  summary%5B%22user_num_cells%22%5D = num_cells%0A
   # TODO

allow user to specify density function for atlas pipeline