#ifndef HNBODY_OPTS_H
#define HNBODY_OPTS_H
/**
  \file

  $Id: opts.h,v 1.20 2015/02/15 21:18:19 rauch Exp $

  \author Kevin P. Rauch

  \brief Enumerations and functions related to \hnb input and output files.

*/
#include "hnbody/kernel.h"

#ifdef mu_os_mswin
#define getopt mu_getopt
#define optarg mu_optarg
#define optind mu_optind
#define optopt mu_optopt
#endif

#ifdef __cplusplus
extern "C" {
namespace HNBODY {
#endif

/** \brief Maximum number of columns allowed in InputOrder, OutputOrder, etc. */
#define HNB_ORDER_MAX 32


/** \brief Output file classes. */
typedef enum hnb_class_enum {
  HNB_SAVE,     /**< Save   file. */
  HNB_ENERGY,   /**< Energy file. */
  HNB_OUTPUT,   /**< Output file. */
  HNB_STATE,    /**< State  file. */
  HNB_BAD_CLASS /**< Explicit invalid value. */
} hnb_class_t;

/**
  \brief Output file formats.
  \warning Numerical values are fixed by the file type spec---do not change!
*/
typedef enum hnb_format_enum {
  HNB_TEXT=0,           /**< Text (ASCII)     format. */
  HNB_FLOAT=1,          /**< Single precision format. */
  HNB_DOUBLE=2,         /**< Double precision format. */
  HNB_SMARTFLOAT=3,     /**< Optimized single precision format. */
  HNB_BAD_FORMAT        /**< Explicit invalid value. */
} hnb_format_t;

/** \brief Output file coordinate systems. */
typedef enum hnb_coord_enum {
  HNB_BARY,     /**< Barycentric reference frame. */
  HNB_BODY,     /**< Bodycentric reference frame. */
  HNB_JACOBI,   /**< Jacobi (hierarchical barycentric) reference frame. */
  HNB_BAD_COORD /**< Explicit invalid value. */
} hnb_coord_t;


/** \brief Input (a.k.a. option) file tags. */
typedef enum hnb_option_enum {
  val_true, val_yes, val_false, val_no,

  name_integ, val_symp, val_BS, val_RK,
  name_integcoord, name_coordzwp,
  val_jac, val_regular, val_baryc, val_bodyc, val_modified,
  val_kd, val_dk, val_sd,
  name_corr, val_O2, val_O4, val_O6, val_O8, val_O12, val_rev,
  name_tiptoe, name_enc, name_prune,
  name_thread, name_thrtiming,

  name_dzH, name_dzZ, name_M, name_dM,
  name_N, name_nH, name_nL, name_nZ, val_auto,
  name_aunit, val_deg, val_rad,
  name_munit, val_g, val_Msun,
  name_lunit, val_m, val_AU, val_ua, val_pc,
  name_tunit, val_s, val_h, val_d, val_yr,

  name_incoord, name_iorder, val_mass, val_rcapt, val_renc,
  val_semi, val_peridist, val_ecc, val_incl,
  val_longasc, val_longperi, val_argperi,
  val_meanlong, val_truelong, val_meanlati, val_truelati,
  val_meananom, val_trueanom, val_time, val_epoch, val_timeperi,
  val_x1, val_x2, val_x3, val_v1, val_v2, val_v3,
  val_idtag, val_jindex, val_smult,

  name_J2, name_J4, name_J6, name_obRadius, name_postn,

  name_ptype, name_ltype, val_hwps, val_lwps, val_zwps,
  name_hwp, name_lwp, name_zwp, name_fixhwp,

  name_tinit, name_tfinal,

  name_outfile, name_outhead, name_outint, name_outcoord, name_outdig,
    name_outdata, name_outtype, name_outorder,
  name_stfile, name_sthead, name_stint, name_stcoord, name_stdig,
    name_stdata, name_sttype, name_storder,
  name_savfile, name_savint, name_savlimit,
  name_ergfile, name_erghead, name_ergint, name_ergdata,
  val_steps, val_double, val_float, val_smart, val_text,

  name_infile, name_include, NOPTAGS, MULTITAGS, FLOATVAL
} hnb_option_tag;


/** \brief Option values data structure. */
typedef struct hnb_option_struct {
  hnb_option_tag integ, integcoord, coordzwp, corr;
  hnb_integ_t hninteg;
  hnb_integcoord_t icoord, icoordZ;
  int ltype, fixedh, tiptoe, enc, prune, postn;
  int nthreads, lcycle, lmax, wcycle, wmax;
  double acc, dzH, dzZ;

  double M, dm, J2, J4, J6, obRad;

  double rad, Msun, AU, d;

  hnb_coord_t incoord;
  hnb_option_tag iorder[HNB_ORDER_MAX], ptype;
  int nitags, icart, imass, N, nH, nL, nZ, nhtot, nltot, nztot, ncap, setM;
  int *idtag, kid, *jindex, kindex, *smult, kmult;
  double *icond;

  char *infile, *outfile, *stfile, *savfile, *ergfile;
  hnb_option_tag outtypes[3], sttypes[3],
             outorder[HNB_ORDER_MAX], storder[HNB_ORDER_MAX];
  int notags, nstags, outhead, sthead, erghead, outdig, stdig;
  int tfsteps, outsteps, ststeps, savsteps, ergsteps;
  double tinit, tfinal, outint, stint, savint, savlimit, ergint;
  hnb_format_t outdata, stdata, ergdata;
  hnb_coord_t outcoord, stcoord;

} hnb_options_t;


/** \brief \hnb Command Line Interface options. */
typedef struct hnb_cli_struct {
  const char *logfile, *recfile, *savefile;
  int bench, help, quiet, version;
  double tcpu;
  FILE* log;
} hnb_cli_t;


DLLSPEC extern void hnb_blank_cli(hnb_cli_t *cli);
DLLSPEC extern void hnb_blank_options(hnb_options_t *opts);
DLLSPEC extern void hnb_fill_options(hnb_options_t *opts);
DLLSPEC extern void hnb_free_options(hnb_options_t *opts);
DLLSPEC extern void hnb_read_option_array(hnb_options_t *opts,
    const char *array[],FILE *logfile);
DLLSPEC extern void  hnb_read_option_file(hnb_options_t *opts,
    const char *file, FILE *logfile);
DLLSPEC extern void  hnb_exec(hnb_data_t *sys, const hnb_options_t *opts,
    FILE *logfile, const char *save);

DLLSPEC extern int
  hnb_interface(hnb_options_t *opts, hnb_cli_t *cli, int argc, char *argv[],
    void (*custom)(FILE *f, const char *prefix));
DLLSPEC extern int
  hnb_opts_driver(hnb_options_t *opts, const hnb_cli_t *cli,
    hnb_extra_t kick, hnb_extra_t shift, hnb_drift_t drift,
    hnb_derivs_t derivs, hnb_energy_t energy);

DLLSPEC extern double
  hnb_benchmark(const hnb_options_t *opts, hnb_extra_t kick,
    hnb_extra_t shift, hnb_drift_t drift, hnb_derivs_t derivs, double maxcpu);

DLLSPEC extern hnb_data_t
 *hnb_opts_init(hnb_options_t *opts, hnb_extra_t ekick, hnb_extra_t eshift,
    hnb_drift_t edrift, hnb_derivs_t ederivs, hnb_energy_t energy);


#ifdef __cplusplus
}  // namespace HNBODY
}  // extern "C"
#endif

#endif  /* HNBODY_OPTS_H */
