/*
!> @file
!!  Routines to read YAML position files.
!! @author
!!    Copyright (C) 2007-2012 BigDFT group 
!!    This file is distributed under the terms of the
!!    GNU General Public License, see ~/COPYING file
!!    or http://www.gnu.org/copyleft/gpl.txt .
!!    For the list of contributors, see ~/AUTHORS 
*/

#ifndef ATOMS_YAML_H
#define ATOMS_YAML_H

typedef enum
  {
    POSINP_BC_FREE,       /* 0, 0, 0 */
    POSINP_BC_WIRE_Z,     /* 0, 0, 1 */
    POSINP_BC_WIRE_Y,     /* 0, 1, 0 */
    POSINP_BC_SURFACE_YZ, /* 0, 1, 1 */
    POSINP_BC_WIRE_X,     /* 1, 0, 0 */
    POSINP_BC_SURFACE_XZ, /* 1, 0, 1 */
    POSINP_BC_SURFACE_XY, /* 1, 1, 0 */
    POSINP_BC_PERIODIC,   /* 1, 1, 1 */
    POSINP_N_BC
  } PosinpBC;

typedef enum
  {
    POSINP_CELL_UNITS_BOHR,
    POSINP_CELL_UNITS_ANGSTROEM,
    POSINP_CELL_N_UNITS
  } PosinpCellUnits;
typedef enum
  {
    POSINP_COORD_UNITS_BOHR,
    POSINP_COORD_UNITS_ANGSTROEM,
    POSINP_COORD_UNITS_REDUCED,
    POSINP_COORD_N_UNITS
  } PosinpCoordUnits;
typedef enum
  {
    POSINP_FORCE_UNITS_HARTREE_PER_BOHR,
    POSINP_FORCE_UNITS_EV_PER_ANGSTROEM,
    POSINP_FORCE_N_UNITS
  } PosinpForceUnits;
typedef enum
  {
    POSINP_ENERG_UNITS_HARTREE,
    POSINP_ENERG_UNITS_EV,
    POSINP_ENERG_UNITS_RYDBERG,
    POSINP_ENERG_N_UNITS
  } PosinpEnergUnits;
typedef enum
  {
    POSINP_FROZEN_FREE,
    POSINP_FROZEN_FULL,
    POSINP_FROZEN_Y,
    POSINP_FROZEN_XZ,
    POSINP_N_FROZEN
  } PosinpFrozenType;
typedef enum
  {
    POSINP_TYPE_INT,
    POSINP_TYPE_DBL,
    POSINP_TYPE_INT_ARR,
    POSINP_TYPE_DBL_ARR,
    POSINP_TYPE_STR,
    POSINP_TYPE_DICT
  } PosinpTypeId;
typedef struct _PosinpDictEntry PosinpDictEntry;
typedef struct _PosinpDict PosinpDict;

struct _PosinpDict
{
  unsigned int len;
  PosinpDictEntry *items;
};
struct _PosinpDictEntry
{
  char *key;
  PosinpTypeId type;
  union
  {
    int ival;
    struct
    {
      unsigned int len;
      int *arr;
    } iarr;
    double dval;
    struct
    {
      unsigned int len;
      double *arr;
    } darr;
    char *str;
    PosinpDict dict;
  } value;
};

#define POSINP_SIGMA_SIZE 3
typedef double PosinpSigma[POSINP_SIGMA_SIZE];
typedef struct _PosinpPole
{
  double q0;
  double q1[3];
  double q2[5];
} PosinpPole;
typedef struct _PosinpAtoms
{
  /* The cell. */
  PosinpBC BC;
  PosinpCellUnits Units;
  double acell[3], angdeg[3];

  /* The positions. */
  unsigned int nat, ntypes;
  PosinpCoordUnits units;
  double *rxyz;
  char **atomnames;
  
  /* Per atoms data. */
  unsigned int *iatype, *ifrztyp;
  int *igspin, *igchg;
  PosinpDict *props;

  /* The forces. */
  PosinpForceUnits funits;
  double fnrm, maxval;
  double *fxyz;

  /* External potential. */
  PosinpCoordUnits punits;
  unsigned int npots;
  char **potnames;
  double *pxyz;
  PosinpSigma *psigma;
  PosinpPole *ppoles;

  /* Additional data. */
  char *comment;
  PosinpEnergUnits eunits;
  double energy;
  unsigned int converged;
  double gnrm_wfn;
} PosinpAtoms;

typedef struct _PosinpList PosinpList;
struct _PosinpList
{
  PosinpList *next;
  PosinpAtoms *data;
};

void posinp_yaml_parse(PosinpList **out, const char *filename, char **message);
void posinp_yaml_free_list(PosinpList *lst);

PosinpDict* posinp_yaml_parse_properties(const char *buffer, char **message);
void posinp_yaml_free_properties(PosinpDict *dict);

#endif
