#include <stdlib.h>
#include <assert.h>
#include <stdio.h>

#include "vector.h"
#include "grid.h"

grid_t::grid_t(double min_x, double min_y, double min_z,
	       double max_x, double max_y, double max_z,
	       int nx, int ny, int nz) {
  
  grid_nx = nx;
  grid_ny = ny;
  grid_nz = nz;

  grid_min_x = min_x; 
  grid_min_y = min_y; 
  grid_min_z = min_z; 
  grid_max_x = max_x;
  grid_max_y = max_y;
  grid_max_z = max_z;

  assert(grid_max_x >= grid_min_x);
  assert(grid_max_y >= grid_min_y);
  assert(grid_max_z >= grid_min_z);
  assert(grid_nx > 0);
  assert(grid_ny > 0);
  assert(grid_nz > 0);

  grid_scale_x = (grid_max_x - grid_min_x)/grid_nx;
  grid_scale_y = (grid_max_y - grid_min_y)/grid_ny;
  grid_scale_z = (grid_max_z - grid_min_z)/grid_nz;

  // grid = new list<lava_t*>[grid_nx*grid_ny*grid_nz];

  grid = (list<lava_t*>**)calloc(sizeof(list<lava_t*>*),grid_nx*grid_ny*grid_nz);
  
  /*
  for (int i=0; i<grid_nx*grid_ny*grid_nz; i++)
    the_grid[i]=new list<lava_t>;
  */
}

list<lava_t*>* grid_t::cellptr(int x, int y, int z) {

  if ((x>=grid_nx) || (y>=grid_ny) || (z>=grid_nz) ||
      (x<0) || (y<0) || (z<0)) 
    return NULL;

  return grid[y*grid_nx*grid_ny + z*grid_nx + x];
}

void grid_t::whichcell(const vector &position, int *cell_x, int *cell_y, int *cell_z) {

  *cell_x = (int)(grid_nx * (position.x - grid_min_x) / (grid_max_x - grid_min_x));
  *cell_y = (int)(grid_ny * (position.y - grid_min_y) / (grid_max_y - grid_min_y));
  *cell_z = (int)(grid_nz * (position.z - grid_min_z) / (grid_max_z - grid_min_z));
  
}

void grid_t::add(lava_t *lava) {
  int x1, y1, z1;
  whichcell(lava->position,&x1,&y1,&z1);
  int cell = y1*grid_nx*grid_ny + z1*grid_nx + x1;
  if (grid[cell] == 0)
    grid[cell] = new list<lava_t *>;
  grid[cell]->push_front(lava);
}

void grid_t::update(const vector &old_position, const vector &new_position, lava_t *lava) {
  int x1, y1, z1, x2, y2, z2;
  whichcell(old_position,&x1,&y1,&z1);
  whichcell(new_position,&x2,&y2,&z2);
  if ((x1 != x2) || (y1 != y2) || (z1 != z2)) {
    list<lava_t*> *old_cell = cellptr(x1,y1,z1);
    list<lava_t*> *new_cell = cellptr(x2,y2,z2);
    if (old_cell) old_cell->remove(lava);
    if (new_cell) new_cell->push_front(lava);
  }
}

grid_t::~grid_t() {
  for (int i=0; i<grid_nx*grid_ny*grid_nz; i++)
    if (grid[i]) delete grid[i];
  free(grid);
  grid = NULL;
}









