#ifndef BQCD_C_DEFS_H
#define BQCD_C_DEFS_H
/*
!===============================================================================
!
! c_defs.h - data types and headers for C routines
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 2007-2017 Hinnerk Stueben
!
! This file is part of BQCD -- Berlin Quantum ChromoDynamics program
!
! BQCD is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.
!
! BQCD is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with BQCD.  If not, see <http://www.gnu.org/licenses/>.
!
!-------------------------------------------------------------------------------
*/

# define CAT(A,B) A ## B
# define CAT3(A,B,C) A ## B ## C
# define CAT4(A,B,C,D) A ## B ## C ## D
# define CAT5(A,B,C,D,E) A ## B ## C ## D ## E
# define CAT6(A,B,C,D,E,F) A ## B ## C ## D ## E ## F
# define CAT7(A,B,C,D,E,F,G) A ## B ## C ## D ## E ## F ## G
# define CAT8(A,B,C,D,E,F,G,H) A ## B ## C ## D ## E ## F ## G ## H
# define CAT9(A,B,C,D,E,F,G,H,I) A ## B ## C ## D ## E ## F ## G ## H ## I

# define STRCAT(A,B) CAT(A,B)
# define STRCAT3(A,B,C) CAT3(A,B,C)
# define STRCAT4(A,B,C,D) CAT4(A,B,C,D)
# define STRCAT5(A,B,C,D,E) CAT5(A,B,C,D,E)
# define STRCAT6(A,B,C,D,E,F) CAT6(A,B,C,D,E,F)
# define STRCAT7(A,B,C,D,E,F,G) CAT7(A,B,C,D,E,F,G)
# define STRCAT8(A,B,C,D,E,F,G,H) CAT8(A,B,C,D,E,F,G,H)
# define STRCAT9(A,B,C,D,E,F,G,H,I) CAT9(A,B,C,D,E,F,G,H,I)

# define STRING(s) SSTRING(s)
# define SSTRING(s) #s

# define DIM    4
# define NCOL   3
# define NDIRAC 4
# define NDIRAC2 2
# define NGEN   8
# define EVEN   0
# define ODD    1
# define FWD    0
# define BWD    1

# define SIZE_COMPLEX 2

# define FWD_BWD  2
# define EVEN_ODD 2

#ifdef LongLong
# define INT8 long long
#else
# define INT8 long
#endif


#ifdef PRECISION_R4
# define RKIND 4
typedef float REAL;
#else
# define RKIND 8
typedef double REAL;
#endif

typedef int INTEGER;
typedef struct { REAL r; REAL i; } COMPLEX;

typedef COMPLEX (*SPINCOL_FIELD)[NCOL][NDIRAC];
typedef COMPLEX (*REORDERED_GAUGE_FIELD)[NCOL][NCOL+NCOL];
typedef COMPLEX (*SC2_FLD)[NCOL][2];

# define Re(z) (z).r
# define Im(z) (z).i

static const REAL ZERO = 0;
static const REAL ONE  = 1;
static const REAL TWO  = 2;

# include "../include_auto/c_timing.h"

# define timing_bin_d_dag_xf timing_bin_d_xf
# define timing_bin_d_dag_xb timing_bin_d_xb
# define timing_bin_d_dag_yf timing_bin_d_yf
# define timing_bin_d_dag_yb timing_bin_d_yb
# define timing_bin_d_dag_zf timing_bin_d_zf
# define timing_bin_d_dag_zb timing_bin_d_zb
# define timing_bin_d_dag_t  timing_bin_d_t
# define timing_bin_d_dag    timing_bin_d

#ifdef TIMING

#ifdef NamesToLower
# define TIMING_START(bin) timing_start(&bin)
# define TIMING_STOP(bin)  timing_stop(&bin)
void timing_start(const int*);
void timing_stop(const int*);
#endif

#ifdef NamesToLower_
# define TIMING_START(bin) timing_start_(&bin)
# define TIMING_STOP(bin)  timing_stop_(&bin)
void timing_start_(const int*);
void timing_stop_(const int*);
#endif

#ifdef NamesToLower__
# define TIMING_START(bin) timing_start__(&bin)
# define TIMING_STOP(bin)  timing_stop__(&bin)
void timing_start__(const int*);
void timing_stop__(const int*);
#endif

#else

# define TIMING_START(bin)
# define TIMING_STOP(bin)

#endif  /* TIMING */

#ifdef TRACE

# define TRACE_ENTRY trace_entry_c(STRING(TRACE_NAME))
# define TRACE_RETURN trace_return_c()
void trace_entry_c(const char*);
void trace_return_c(void);

#else

# define TRACE_ENTRY
# define TRACE_RETURN

#endif  /* TRACE */

/* shift of pointers for using Fortran indexing */

# define shift_6pointers(a, b, c, d, e, f) a--; b--; c--; d--; e--; f--

# define shift_7pointers(a, b, c, d, e, f, g) a--; b--; c--; d--; e--; f--; g--

# define shift_8pointers(a, b, c, d, e, f, g, h) a--; b--; c--; d--; e--; f--; g--; h--


/* prototypes for Fortran Functions called from C */

#ifdef NamesToLower
# define ABBRUCH abbruch
# define GET_CLOCK get_clock
# define MY_PE my_pe
# define c_stack c_stack
#endif

#ifdef NamesToLower_
# define ABBRUCH abbruch_
# define GET_CLOCK get_clock_
# define MY_PE my_pe_
# define c_stack c_stack_
#endif

#ifdef NamesToLower__
# define ABBRUCH abbruch__
# define GET_CLOCK get_clock__
# define MY_PE my_pe__
# define c_stack c_stack__
#endif


/* prototypes for those functions */

void ABBRUCH(void);
double GET_CLOCK (void);
int MY_PE(void);
/*===========================================================================*/
#endif /* BQCD_C_DEFS_H */
