#include "box.h"
#include <config.h>
#include <string.h>

void FC_FUNC_(bind_f90_box_iterator_copy_constructor, BIND_F90_BOX_ITERATOR_COPY_CONSTRUCTOR)(f90_box_iterator_pointer*,
  const f90_box_iterator*);
f90_box_iterator_pointer f90_box_iterator_copy_constructor(const f90_box_iterator* other)
{
  f90_box_iterator_pointer out_self;
  FC_FUNC_(bind_f90_box_iterator_copy_constructor, BIND_F90_BOX_ITERATOR_COPY_CONSTRUCTOR)
    (&out_self, other);
  return out_self;
}

void FC_FUNC_(bind_f90_box_iterator_type_new, BIND_F90_BOX_ITERATOR_TYPE_NEW)(f90_box_iterator_pointer*,
  const int*,
  const int*,
  const int*,
  const int*,
  const int*,
  const int*,
  const int*,
  const int*,
  f90_cell_pointer*,
  const int*,
  const double*,
  const double*,
  const double*,
  const int*,
  const double*,
  const int*);
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))
{
  f90_box_iterator_pointer out_self;
  int whole_conv = whole ? *whole : 0;
  FC_FUNC_(bind_f90_box_iterator_type_new, BIND_F90_BOX_ITERATOR_TYPE_NEW)
    (&out_self, &i, &j, &k, i23, i3e, i3s, ind, inext ? *inext : NULL, mesh, nbox ? *nbox[0] : NULL, oxyz ? *oxyz : NULL, rxyz ? *rxyz : NULL, rxyz_nbox ? *rxyz_nbox : NULL, subbox ? *subbox[0] : NULL, tmp ? *tmp : NULL,  whole ? &whole_conv : NULL);
  return out_self;
}

void FC_FUNC_(bind_f90_box_iterator_free, BIND_F90_BOX_ITERATOR_FREE)(f90_box_iterator_pointer*);
void f90_box_iterator_free(f90_box_iterator_pointer self)
{
  FC_FUNC_(bind_f90_box_iterator_free, BIND_F90_BOX_ITERATOR_FREE)
    (&self);
}

void FC_FUNC_(bind_f90_box_iterator_empty, BIND_F90_BOX_ITERATOR_EMPTY)(f90_box_iterator_pointer*);
f90_box_iterator_pointer f90_box_iterator_empty(void)
{
  f90_box_iterator_pointer out_self;
  FC_FUNC_(bind_f90_box_iterator_empty, BIND_F90_BOX_ITERATOR_EMPTY)
    (&out_self);
  return out_self;
}

void FC_FUNC_(bind_f90_cell_copy_constructor, BIND_F90_CELL_COPY_CONSTRUCTOR)(f90_cell_pointer*,
  const f90_cell*);
f90_cell_pointer f90_cell_copy_constructor(const f90_cell* other)
{
  f90_cell_pointer out_self;
  FC_FUNC_(bind_f90_cell_copy_constructor, BIND_F90_CELL_COPY_CONSTRUCTOR)
    (&out_self, other);
  return out_self;
}

void FC_FUNC_(bind_f90_cell_type_new, BIND_F90_CELL_TYPE_NEW)(f90_cell_pointer*,
  const f90_domain*,
  const double*,
  const double*,
  const size_t*,
  const int*,
  const double*);
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)
{
  f90_cell_pointer out_self;
  FC_FUNC_(bind_f90_cell_type_new, BIND_F90_CELL_TYPE_NEW)
    (&out_self, dom, habc[0], hgrids, &ndim, ndims, &volume_element);
  return out_self;
}

void FC_FUNC_(bind_f90_cell_free, BIND_F90_CELL_FREE)(f90_cell_pointer*);
void f90_cell_free(f90_cell_pointer self)
{
  FC_FUNC_(bind_f90_cell_free, BIND_F90_CELL_FREE)
    (&self);
}

void FC_FUNC_(bind_cell_null, BIND_CELL_NULL)(f90_cell_pointer*);
f90_cell_pointer cell_null(void)
{
  f90_cell_pointer out_me;
  FC_FUNC_(bind_cell_null, BIND_CELL_NULL)
    (&out_me);
  return out_me;
}

void FC_FUNC_(bind_box_iter, BIND_BOX_ITER)(f90_box_iterator_pointer*,
  const f90_cell*,
  const int*,
  const double*,
  const int*,
  const int*,
  const int*,
  const double*);
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))
{
  f90_box_iterator_pointer out_boxit;
  int centered_conv = centered ? *centered : 0;
  FC_FUNC_(bind_box_iter, BIND_BOX_ITER)
    (&out_boxit, mesh, nbox ? *nbox[0] : NULL, origin ? *origin : NULL, i3s, n3p,  centered ? &centered_conv : NULL, cutoff);
  return out_boxit;
}

void FC_FUNC_(bind_box_nbox_from_cutoff, BIND_BOX_NBOX_FROM_CUTOFF)(const f90_cell*,
  int*,
  const double*,
  const double*,
  const int*);
void box_nbox_from_cutoff(const f90_cell* mesh,
  int out_nbox[2][3],
  const double oxyz[3],
  double cutoff,
  const bool (*inner))
{
  int inner_conv = inner ? *inner : 0;
  FC_FUNC_(bind_box_nbox_from_cutoff, BIND_BOX_NBOX_FROM_CUTOFF)
    (mesh, out_nbox[0], oxyz, &cutoff,  inner ? &inner_conv : NULL);
}

void FC_FUNC_(bind_box_next_z, BIND_BOX_NEXT_Z)(int*,
  f90_box_iterator*);
bool box_next_z(f90_box_iterator* bit)
{
  int out_ok;
  FC_FUNC_(bind_box_next_z, BIND_BOX_NEXT_Z)
    (&out_ok, bit);
  return out_ok;
}

void FC_FUNC_(bind_box_next_y, BIND_BOX_NEXT_Y)(int*,
  f90_box_iterator*);
bool box_next_y(f90_box_iterator* bit)
{
  int out_ok;
  FC_FUNC_(bind_box_next_y, BIND_BOX_NEXT_Y)
    (&out_ok, bit);
  return out_ok;
}

void FC_FUNC_(bind_box_next_x, BIND_BOX_NEXT_X)(int*,
  f90_box_iterator*);
bool box_next_x(f90_box_iterator* bit)
{
  int out_ok;
  FC_FUNC_(bind_box_next_x, BIND_BOX_NEXT_X)
    (&out_ok, bit);
  return out_ok;
}

void FC_FUNC_(bind_box_next_point, BIND_BOX_NEXT_POINT)(int*,
  f90_box_iterator*);
bool box_next_point(f90_box_iterator* boxit)
{
  int out_box_next_point;
  FC_FUNC_(bind_box_next_point, BIND_BOX_NEXT_POINT)
    (&out_box_next_point, boxit);
  return out_box_next_point;
}

void FC_FUNC_(bind_cell_new, BIND_CELL_NEW)(f90_cell_pointer*,
  const f90_domain*,
  const int*,
  const double*);
f90_cell_pointer cell_new(const f90_domain* dom,
  const int ndims[3],
  const double hgrids[3])
{
  f90_cell_pointer out_mesh;
  FC_FUNC_(bind_cell_new, BIND_CELL_NEW)
    (&out_mesh, dom, ndims, hgrids);
  return out_mesh;
}

void FC_FUNC_(bind_cell_r, BIND_CELL_R)(double*,
  const f90_cell*,
  const int*,
  const int*);
double cell_r(const f90_cell* mesh,
  int i,
  int dim)
{
  double out_t;
  FC_FUNC_(bind_cell_r, BIND_CELL_R)
    (&out_t, mesh, &i, &dim);
  return out_t;
}

void FC_FUNC_(bind_box_iter_square_gd, BIND_BOX_ITER_SQUARE_GD)(double*,
  const f90_box_iterator*);
double box_iter_square_gd(const f90_box_iterator* bit)
{
  double out_box_iter_square_gd;
  FC_FUNC_(bind_box_iter_square_gd, BIND_BOX_ITER_SQUARE_GD)
    (&out_box_iter_square_gd, bit);
  return out_box_iter_square_gd;
}

void FC_FUNC_(bind_box_iter_closest_r, BIND_BOX_ITER_CLOSEST_R)(const f90_box_iterator*,
  double*,
  const double*,
  const int*);
void box_iter_closest_r(const f90_box_iterator* bit,
  double out_r[3],
  const double rxyz[3],
  const bool (*orthorhombic))
{
  int orthorhombic_conv = orthorhombic ? *orthorhombic : 0;
  FC_FUNC_(bind_box_iter_closest_r, BIND_BOX_ITER_CLOSEST_R)
    (bit, out_r, rxyz,  orthorhombic ? &orthorhombic_conv : NULL);
}

void FC_FUNC_(bind_box_iter_distance, BIND_BOX_ITER_DISTANCE)(double*,
  const f90_box_iterator*,
  const double*);
double box_iter_distance(const f90_box_iterator* bit,
  const double rxyz0[3])
{
  double out_box_iter_distance;
  FC_FUNC_(bind_box_iter_distance, BIND_BOX_ITER_DISTANCE)
    (&out_box_iter_distance, bit, rxyz0);
  return out_box_iter_distance;
}

void FC_FUNC_(bind_nullify_box_iterator, BIND_NULLIFY_BOX_ITERATOR)(f90_box_iterator*);
void nullify_box_iterator(f90_box_iterator* boxit)
{
  FC_FUNC_(bind_nullify_box_iterator, BIND_NULLIFY_BOX_ITERATOR)
    (boxit);
}

void FC_FUNC_(bind_box_iter_set_nbox, BIND_BOX_ITER_SET_NBOX)(f90_box_iterator*,
  const int*,
  const double*,
  const double*);
void box_iter_set_nbox(f90_box_iterator* bit,
  const int (*nbox)[2][3],
  const double (*oxyz)[3],
  const double (*cutoff))
{
  FC_FUNC_(bind_box_iter_set_nbox, BIND_BOX_ITER_SET_NBOX)
    (bit, nbox ? *nbox[0] : NULL, oxyz ? *oxyz : NULL, cutoff);
}

void FC_FUNC_(bind_box_iter_expand_nbox, BIND_BOX_ITER_EXPAND_NBOX)(f90_box_iterator*);
void box_iter_expand_nbox(f90_box_iterator* bit)
{
  FC_FUNC_(bind_box_iter_expand_nbox, BIND_BOX_ITER_EXPAND_NBOX)
    (bit);
}

void FC_FUNC_(bind_box_iter_rewind, BIND_BOX_ITER_REWIND)(f90_box_iterator*);
void box_iter_rewind(f90_box_iterator* bit)
{
  FC_FUNC_(bind_box_iter_rewind, BIND_BOX_ITER_REWIND)
    (bit);
}

void FC_FUNC_(bind_box_iter_split, BIND_BOX_ITER_SPLIT)(f90_box_iterator*,
  const int*,
  const int*);
void box_iter_split(f90_box_iterator* boxit,
  int ntasks,
  int itask)
{
  FC_FUNC_(bind_box_iter_split, BIND_BOX_ITER_SPLIT)
    (boxit, &ntasks, &itask);
}

void FC_FUNC_(bind_box_iter_merge, BIND_BOX_ITER_MERGE)(f90_box_iterator*);
void box_iter_merge(f90_box_iterator* boxit)
{
  FC_FUNC_(bind_box_iter_merge, BIND_BOX_ITER_MERGE)
    (boxit);
}

