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

void FC_FUNC_(bind_f90_domain_copy_constructor, BIND_F90_DOMAIN_COPY_CONSTRUCTOR)(f90_domain_pointer*,
  const f90_domain*);
f90_domain_pointer f90_domain_copy_constructor(const f90_domain* other)
{
  f90_domain_pointer out_self;
  FC_FUNC_(bind_f90_domain_copy_constructor, BIND_F90_DOMAIN_COPY_CONSTRUCTOR)
    (&out_self, other);
  return out_self;
}

void FC_FUNC_(bind_f90_domain_type_new, BIND_F90_DOMAIN_TYPE_NEW)(f90_domain_pointer*,
  const double*,
  const double*,
  const double*,
  const int*,
  const double*,
  const double*,
  const double*,
  const int*,
  const double*,
  const int*);
f90_domain_pointer f90_domain_type_new(const double abc[3][3],
  const double acell[3],
  const double angrad[3],
  const int bc[3],
  double detgd,
  const double gd[3][3],
  const double gu[3][3],
  bool orthorhombic,
  const double uabc[3][3],
  int units)
{
  f90_domain_pointer out_self;
  int orthorhombic_conv = orthorhombic;
  FC_FUNC_(bind_f90_domain_type_new, BIND_F90_DOMAIN_TYPE_NEW)
    (&out_self, abc[0], acell, angrad, bc, &detgd, gd[0], gu[0], &orthorhombic_conv, uabc[0], &units);
  return out_self;
}

void FC_FUNC_(bind_f90_domain_free, BIND_F90_DOMAIN_FREE)(f90_domain_pointer*);
void f90_domain_free(f90_domain_pointer self)
{
  FC_FUNC_(bind_f90_domain_free, BIND_F90_DOMAIN_FREE)
    (&self);
}

void FC_FUNC_(bind_domain_null, BIND_DOMAIN_NULL)(f90_domain_pointer*);
f90_domain_pointer domain_null(void)
{
  f90_domain_pointer out_dom;
  FC_FUNC_(bind_domain_null, BIND_DOMAIN_NULL)
    (&out_dom);
  return out_dom;
}

void FC_FUNC_(bind_domain_new, BIND_DOMAIN_NEW)(f90_domain_pointer*,
  const f90_f_enumerator*,
  const f90_f_enumerator*,
  const f90_f_enumerator*,
  const f90_f_enumerator*,
  const double*,
  const double*,
  const double*,
  const double*,
  const double*);
f90_domain_pointer domain_new(const f90_f_enumerator* units,
  const f90_f_enumerator* bc[3],
  const double (*abc)[3][3],
  const double (*alpha_bc),
  const double (*beta_ac),
  const double (*gamma_ab),
  const double (*acell)[3])
{
  f90_domain_pointer out_dom;
  FC_FUNC_(bind_domain_new, BIND_DOMAIN_NEW)
    (&out_dom, units, bc[0], bc[1], bc[2], abc ? *abc[0] : NULL, alpha_bc, beta_ac, gamma_ab, acell ? *acell : NULL);
  return out_dom;
}

void FC_FUNC_(bind_change_domain_bc, BIND_CHANGE_DOMAIN_BC)(f90_domain_pointer*,
  const f90_domain*,
  const char*,
  size_t);
f90_domain_pointer change_domain_bc(const f90_domain* dom_in,
  char geocode)
{
  f90_domain_pointer out_dom;
  size_t geocode_chk_len = 1;
  FC_FUNC_(bind_change_domain_bc, BIND_CHANGE_DOMAIN_BC)
    (&out_dom, dom_in, &geocode, geocode_chk_len);
  return out_dom;
}

void FC_FUNC_(bind_units_enum_from_str, BIND_UNITS_ENUM_FROM_STR)(f90_f_enumerator_pointer*,
  const char*,
  const size_t*,
  size_t);
f90_f_enumerator_pointer units_enum_from_str(const char* str)
{
  f90_f_enumerator_pointer out_units;
  size_t str_chk_len, str_len = str_chk_len = str ? strlen(str) : 0;
  FC_FUNC_(bind_units_enum_from_str, BIND_UNITS_ENUM_FROM_STR)
    (&out_units, str, &str_len, str_chk_len);
  return out_units;
}

void FC_FUNC_(bind_geocode_to_bc, BIND_GEOCODE_TO_BC)(int*,
  const char*,
  size_t);
void geocode_to_bc(int out_bc[3],
  char geocode)
{
  size_t geocode_chk_len = 1;
  FC_FUNC_(bind_geocode_to_bc, BIND_GEOCODE_TO_BC)
    (out_bc, &geocode, geocode_chk_len);
}

void FC_FUNC_(bind_domain_geocode, BIND_DOMAIN_GEOCODE)(char*,
  const f90_domain*);
char domain_geocode(const f90_domain* dom)
{
  char out_dom_geocode;
  FC_FUNC_(bind_domain_geocode, BIND_DOMAIN_GEOCODE)
    (&out_dom_geocode, dom);
  return out_dom_geocode;
}

void FC_FUNC_(bind_domain_volume, BIND_DOMAIN_VOLUME)(double*,
  const double*,
  const f90_domain*);
double domain_volume(const double acell[3],
  const f90_domain* dom)
{
  double out_cell_volume;
  FC_FUNC_(bind_domain_volume, BIND_DOMAIN_VOLUME)
    (&out_cell_volume, acell, dom);
  return out_cell_volume;
}

void FC_FUNC_(bind_rxyz_ortho, BIND_RXYZ_ORTHO)(const f90_domain*,
  double*,
  const double*);
void rxyz_ortho(const f90_domain* dom,
  double out_rxyz_ortho[3],
  const double rxyz[3])
{
  FC_FUNC_(bind_rxyz_ortho, BIND_RXYZ_ORTHO)
    (dom, out_rxyz_ortho, rxyz);
}

void FC_FUNC(bind_distance, BIND_DISTANCE)(double*,
  const f90_domain*,
  const double*,
  const double*);
double distance(const f90_domain* dom,
  const double r[3],
  const double c[3])
{
  double out_d;
  FC_FUNC(bind_distance, BIND_DISTANCE)
    (&out_d, dom, r, c);
  return out_d;
}

void FC_FUNC_(bind_closest_r, BIND_CLOSEST_R)(const f90_domain*,
  double*,
  const double*,
  const double*);
void closest_r(const f90_domain* dom,
  double out_r[3],
  const double v[3],
  const double center[3])
{
  FC_FUNC_(bind_closest_r, BIND_CLOSEST_R)
    (dom, out_r, v, center);
}

void FC_FUNC_(bind_domain_set_from_dict, BIND_DOMAIN_SET_FROM_DICT)(f90_dictionary_pointer*,
  f90_domain*);
void domain_set_from_dict(f90_dictionary_pointer dict,
  f90_domain* dom)
{
  FC_FUNC_(bind_domain_set_from_dict, BIND_DOMAIN_SET_FROM_DICT)
    (&dict, dom);
}

void FC_FUNC_(bind_domain_merge_to_dict, BIND_DOMAIN_MERGE_TO_DICT)(f90_dictionary_pointer*,
  const f90_domain*);
void domain_merge_to_dict(f90_dictionary_pointer dict,
  const f90_domain* dom)
{
  FC_FUNC_(bind_domain_merge_to_dict, BIND_DOMAIN_MERGE_TO_DICT)
    (&dict, dom);
}

void FC_FUNC_(bind_dotp_gu, BIND_DOTP_GU)(double*,
  const f90_domain*,
  const double*,
  const double*);
double dotp_gu(const f90_domain* dom,
  const double v1[3],
  const double v2[3])
{
  double out_dotp_gu;
  FC_FUNC_(bind_dotp_gu, BIND_DOTP_GU)
    (&out_dotp_gu, dom, v1, v2);
  return out_dotp_gu;
}

void FC_FUNC_(bind_dotp_gu_add2, BIND_DOTP_GU_ADD2)(double*,
  const f90_domain*,
  const double*,
  double*);
double dotp_gu_add2(const f90_domain* dom,
  const double v1[3],
  double* v2_add)
{
  double out_dotp;
  FC_FUNC_(bind_dotp_gu_add2, BIND_DOTP_GU_ADD2)
    (&out_dotp, dom, v1, v2_add);
  return out_dotp;
}

void FC_FUNC_(bind_dotp_gu_add1, BIND_DOTP_GU_ADD1)(double*,
  const f90_domain*,
  double*,
  const double*);
double dotp_gu_add1(const f90_domain* dom,
  double* v1_add,
  const double v2[3])
{
  double out_dotp;
  FC_FUNC_(bind_dotp_gu_add1, BIND_DOTP_GU_ADD1)
    (&out_dotp, dom, v1_add, v2);
  return out_dotp;
}

void FC_FUNC(bind_square, BIND_SQUARE)(double*,
  const f90_domain*,
  const double*);
double square(const f90_domain* dom,
  const double v[3])
{
  double out_square;
  FC_FUNC(bind_square, BIND_SQUARE)
    (&out_square, dom, v);
  return out_square;
}

void FC_FUNC_(bind_square_add, BIND_SQUARE_ADD)(double*,
  const f90_domain*,
  double*);
double square_add(const f90_domain* dom,
  double* v_add)
{
  double out_square;
  FC_FUNC_(bind_square_add, BIND_SQUARE_ADD)
    (&out_square, dom, v_add);
  return out_square;
}

void FC_FUNC_(bind_dotp_gd, BIND_DOTP_GD)(double*,
  const f90_domain*,
  const double*,
  const double*);
double dotp_gd(const f90_domain* dom,
  const double v1[3],
  const double v2[3])
{
  double out_dotp_gd;
  FC_FUNC_(bind_dotp_gd, BIND_DOTP_GD)
    (&out_dotp_gd, dom, v1, v2);
  return out_dotp_gd;
}

void FC_FUNC_(bind_dotp_gd_add2, BIND_DOTP_GD_ADD2)(double*,
  const f90_domain*,
  const double*,
  double*);
double dotp_gd_add2(const f90_domain* dom,
  const double v1[3],
  double* v2_add)
{
  double out_dotp;
  FC_FUNC_(bind_dotp_gd_add2, BIND_DOTP_GD_ADD2)
    (&out_dotp, dom, v1, v2_add);
  return out_dotp;
}

void FC_FUNC_(bind_dotp_gd_add1, BIND_DOTP_GD_ADD1)(double*,
  const f90_domain*,
  double*,
  const double*);
double dotp_gd_add1(const f90_domain* dom,
  double* v1_add,
  const double v2[3])
{
  double out_dotp;
  FC_FUNC_(bind_dotp_gd_add1, BIND_DOTP_GD_ADD1)
    (&out_dotp, dom, v1_add, v2);
  return out_dotp;
}

void FC_FUNC_(bind_dotp_gd_add12, BIND_DOTP_GD_ADD12)(double*,
  const f90_domain*,
  double*,
  double*);
double dotp_gd_add12(const f90_domain* dom,
  double* v1_add,
  double* v2_add)
{
  double out_dotp;
  FC_FUNC_(bind_dotp_gd_add12, BIND_DOTP_GD_ADD12)
    (&out_dotp, dom, v1_add, v2_add);
  return out_dotp;
}

void FC_FUNC_(bind_square_gd, BIND_SQUARE_GD)(double*,
  const f90_domain*,
  const double*);
double square_gd(const f90_domain* dom,
  const double v[3])
{
  double out_square_gd;
  FC_FUNC_(bind_square_gd, BIND_SQUARE_GD)
    (&out_square_gd, dom, v);
  return out_square_gd;
}

void FC_FUNC_(bind_square_gd_add, BIND_SQUARE_GD_ADD)(double*,
  const f90_domain*,
  double*);
double square_gd_add(const f90_domain* dom,
  double* v_add)
{
  double out_square;
  FC_FUNC_(bind_square_gd_add, BIND_SQUARE_GD_ADD)
    (&out_square, dom, v_add);
  return out_square;
}

void FC_FUNC_(bind_angstroem_units, BIND_ANGSTROEM_UNITS)(f90_f_enumerator_pointer*);
f90_f_enumerator_pointer angstroem_units(void)
{
  f90_f_enumerator_pointer out_self;
  FC_FUNC_(bind_angstroem_units, BIND_ANGSTROEM_UNITS)
    (&out_self);
  return out_self;
}

void FC_FUNC_(bind_periodic_bc, BIND_PERIODIC_BC)(f90_f_enumerator_pointer*);
f90_f_enumerator_pointer periodic_bc(void)
{
  f90_f_enumerator_pointer out_self;
  FC_FUNC_(bind_periodic_bc, BIND_PERIODIC_BC)
    (&out_self);
  return out_self;
}

void FC_FUNC_(bind_free_bc, BIND_FREE_BC)(f90_f_enumerator_pointer*);
f90_f_enumerator_pointer free_bc(void)
{
  f90_f_enumerator_pointer out_self;
  FC_FUNC_(bind_free_bc, BIND_FREE_BC)
    (&out_self);
  return out_self;
}

void FC_FUNC_(bind_atomic_units, BIND_ATOMIC_UNITS)(f90_f_enumerator_pointer*);
f90_f_enumerator_pointer atomic_units(void)
{
  f90_f_enumerator_pointer out_self;
  FC_FUNC_(bind_atomic_units, BIND_ATOMIC_UNITS)
    (&out_self);
  return out_self;
}

void FC_FUNC_(bind_double_precision_enum, BIND_DOUBLE_PRECISION_ENUM)(f90_f_enumerator_pointer*);
f90_f_enumerator_pointer double_precision_enum(void)
{
  f90_f_enumerator_pointer out_self;
  FC_FUNC_(bind_double_precision_enum, BIND_DOUBLE_PRECISION_ENUM)
    (&out_self);
  return out_self;
}

void FC_FUNC_(bind_nanometer_units, BIND_NANOMETER_UNITS)(f90_f_enumerator_pointer*);
f90_f_enumerator_pointer nanometer_units(void)
{
  f90_f_enumerator_pointer out_self;
  FC_FUNC_(bind_nanometer_units, BIND_NANOMETER_UNITS)
    (&out_self);
  return out_self;
}

