#ifndef VSPAERO_TYPES_H
#define VSPAERO_TYPES_H

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <iostream>

int FWRITE(int    *Value, size_t Size, size_t Num, FILE *File);
int FWRITE(float  *Value, size_t Size, size_t Num, FILE *File);
int FWRITE(double *Value, size_t Size, size_t Num, FILE *File);
int FWRITE(char   *Value, size_t Size, size_t Num, FILE *File);

int FREAD(int     *Value, size_t Size, size_t Num, FILE *File);
int FREAD(float   *Value, size_t Size, size_t Num, FILE *File);
int FREAD(double  *Value, size_t Size, size_t Num, FILE *File);
int FREAD(char    *Value, size_t Size, size_t Num, FILE *File);

float FLOAT(double a);

template <typename T>
T Argument(T value) noexcept
{
  return value;
}

template <typename T>
T const * Argument(std::basic_string<T> const & value) noexcept
{
  return value.c_str();
}

///////////////////////////////////// CODIPACK ///////////////////////////////////////////

#ifdef CODIPACK

#include <codi.hpp>

#define VSPAERO_DOUBLE codi::RealReverse

float FLOAT(codi::RealReverse a);

int FWRITE(codi::RealReverse *Value, size_t Size, size_t Num, FILE *File);

int FREAD(codi::RealReverse  *Value, size_t Size, size_t Num, FILE *File);

double const  Argument(codi::RealReverse const & value) noexcept;

// OPENMP stuff for Codi

#pragma omp declare reduction(+: codi::RealReverse: \
     omp_out.gradient()+=omp_in.gradient(), \
     omp_out.value()+=omp_in.value())\
     initializer (omp_priv=codi::RealReverse(0.0))
     
///////////////////////////////////// NORMAL ///////////////////////////////////////////

#else

#define VSPAERO_DOUBLE double

#endif

template <typename ... Args>
void PRINTF(char const * const format,
            Args const & ... args) noexcept
{
  printf(format, Argument(args) ...);
}

template <typename ... Args>
void FPRINTF(FILE *stream, char const * const format,
            Args const & ... args) noexcept
{
  fprintf(stream, format, Argument(args) ...);
}

template <typename ... Args>
void SPRINTF(char *str, char const * const format,
            Args const & ... args) noexcept
{
  sprintf(str, format, Argument(args) ...);
}


#endif





