#ifndef BOX_H
#define BOX_H

#include "futile_cst.h"
#include <stdbool.h>
#include "at_domain.h"

F_DEFINE_TYPE(cell);
F_DEFINE_TYPE(box_iterator);

f90_box_iterator_pointer f90_box_iterator_copy_constructor(const f90_box_iterator* other);

f90_box_iterator_pointer f90_box_iterator_type_new(int i,
  int j,
  int k,
  const int (*i23),
  const int (*i3e),
  const int (*i3s),
  const int (*ind),
  const int (*inext)[3],
  f90_cell_pointer (*mesh),
  const int (*nbox)[2][3],
  const double (*oxyz)[3],
  const double (*rxyz)[3],
  const double (*rxyz_nbox)[3],
  const int (*subbox)[2][3],
  const double (*tmp)[3],
  const bool (*whole));

void f90_box_iterator_free(f90_box_iterator_pointer self);

f90_box_iterator_pointer f90_box_iterator_empty(void);

f90_cell_pointer f90_cell_copy_constructor(const f90_cell* other);

f90_cell_pointer f90_cell_type_new(const f90_domain* dom,
  const double habc[3][3],
  const double hgrids[3],
  size_t ndim,
  const int ndims[3],
  double volume_element);

void f90_cell_free(f90_cell_pointer self);

f90_cell_pointer cell_null(void);

f90_box_iterator_pointer box_iter(const f90_cell* mesh,
  const int (*nbox)[2][3],
  const double (*origin)[3],
  const int (*i3s),
  const int (*n3p),
  const bool (*centered),
  const double (*cutoff));

void box_nbox_from_cutoff(const f90_cell* mesh,
  int out_nbox[2][3],
  const double oxyz[3],
  double cutoff,
  const bool (*inner));

bool box_next_z(f90_box_iterator* bit);

bool box_next_y(f90_box_iterator* bit);

bool box_next_x(f90_box_iterator* bit);

bool box_next_point(f90_box_iterator* boxit);

f90_cell_pointer cell_new(const f90_domain* dom,
  const int ndims[3],
  const double hgrids[3]);

double cell_r(const f90_cell* mesh,
  int i,
  int dim);

double box_iter_square_gd(const f90_box_iterator* bit);

void box_iter_closest_r(const f90_box_iterator* bit,
  double out_r[3],
  const double rxyz[3],
  const bool (*orthorhombic));

double box_iter_distance(const f90_box_iterator* bit,
  const double rxyz0[3]);

void nullify_box_iterator(f90_box_iterator* boxit);

void box_iter_set_nbox(f90_box_iterator* bit,
  const int (*nbox)[2][3],
  const double (*oxyz)[3],
  const double (*cutoff));

void box_iter_expand_nbox(f90_box_iterator* bit);

void box_iter_rewind(f90_box_iterator* bit);

void box_iter_split(f90_box_iterator* boxit,
  int ntasks,
  int itask);

void box_iter_merge(f90_box_iterator* boxit);

#endif
