#ifndef __EMB_LOCALIZEMUSIC_H__
#define __EMB_LOCALIZEMUSIC_H__

#include <cuda_profiler_api.h>
#include <cuComplex.h>

#include "gpu_common.h"
#include "android_hark.h"

#define MAX_CH_NUM 16
#define MAX_CH_NUM_2 (MAX_CH_NUM)*(MAX_CH_NUM)

//#if 0
//#define checkCudaErrors(arg) arg
//#else
//#define checkCudaErrors(call)                                                  \
//{                                                                    \
//	const cudaError_t error = call;                                  \
//	if (error != cudaSuccess)                                        \
//	{                                                                \
//		printf("Error: %s:%d, ", __FILE__, __LINE__);                \
//		printf("code:%d, reason: %s\n", error, cudaGetErrorString(error));   \
//		exit(1);                                                     \
//	}                                                                \
//}
//#endif

#if 1
// Macro to catch CUDA errors in CUDA runtime calls
#define CUDA_SAFE_CALL(call)                                          \
do {                                                                  \
	cudaError_t err = call;                                           \
	if (cudaSuccess != err) {                                         \
		fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n", \
		    __FILE__, __LINE__, cudaGetErrorString(err));             \
		exit(EXIT_FAILURE);                                           \
	}                                                                 \
} while (0)
#else
#define CUDA_SAFE_CALL(call) call
#endif


extern cuComplex *tmp_xx;
extern cuComplex *d_X;

extern cuComplex *d_Rxx;
extern cuComplex *d_R;
extern int *d_UsesFreq;
extern float *b, *z;
extern float *d_EigenValue;
extern cuComplex *d_E;
extern cuComplex *d_A;
extern float *d_MSSW;
extern float *d_Pavg;
extern float *d_Pavg_sum;

//temp
extern cuComplex *tmp_Rxx;
extern float *tmp_Pavg;

extern int g_lower;
extern int g_upper;

extern float ***Pavg_sum2;

//svd
extern float *d_bb; 
extern float *d_cc; 
extern float *d_tt; 
//extern float *d_ss; 
extern float *d_eps; 
extern cuComplex *d_TempCalc4;
extern cuComplex *d_TempCalc3;
extern float *d_REigenValue;



//for Multi GPU
//extern int process_id;



#ifdef __cplusplus
extern "C" {
#endif


void gpu_init(int pslength, int nb_channel, int *UsesFreq);
//void gpu_init2(int pslength, int nb_channel, int direction_num, int range_num,
//		COMPLEX_FLOAT ****AMatrix, float *MSSW);
//void gpu_init2(int pslength, int nb_channel, int height_num, int direction_num, int range_num,
//		COMPLEX_FLOAT *****AMatrix, float *MSSW);
void gpu_init2(int pslength, int nb_channel, int height_num, int direction_num, int range_num,
		COMPLEX_FLOAT *****AMatrix, float *MSSW,
		int window, int look_back, int look_ahead
		);

//void gpu_AddCorrelation(cuComplex *X, cuComplex *Rxx,
//		int win_num,
//		int pslength, int nb_channel);
void gpu_AddCorrelation(cuComplex *X, cuComplex *Rxx,
		int win_size, int win_num,
		int pslength, int nb_channel);

void gpu_NormalizeCorrelation(cuComplex *Rxx,
		int sum_count,
		int pslength, int nb_channel);

void gpu_MaxOfAbsValue(int pslength, int *UsesFreq, int nb_channel, cuComplex *Rxx, cuComplex *R);

void gpu_CalcAveragePower(float *EigenValue, cuComplex *E, cuComplex *A, int *UsesFreq, int NumSource, float *Pavg, float *MSSW, int enable_eigenvalue_weight, int nb_channel, int num_source, int direction_num, int range_num, int pslength);

void gpu_CalcAveragePower2(float *EigenValue, cuComplex *E, cuComplex *A, int *UsesFreq, int NumSource, float *Pavg, float *MSSW, int enable_eigenvalue_weight, int nb_channel, int num_source,
	      int height_num, int direction_num, int range_num, int pslength);

//void cpu_Evd(COMPLEX_FLOAT *a,
//	       	float *d,
//	       	COMPLEX_FLOAT *v,
//		float *b,
//		float *z,
//		int *UsesFreq,
//		int pslength,
//		int tf_channel_num
//		);
void gpu_Evd(cuComplex *a,
	       	float *d,
	       	cuComplex *v,
		float *b,
		float *z,
		int *UsesFreq,
		int pslength,
		int tf_channel_num
		);


//void cpu_Svd(COMPLEX_FLOAT **a, float *s, COMPLEX_FLOAT **u, COMPLEX_FLOAT **v,
//		int m, int n);
//void cpu_Svd(cuComplex *a, float *s, cuComplex *u, COMPLEX_FLOAT **v,
//void cpu_Svd(cuComplex *a, float *s, cuComplex *u, cuComplex *v,
//		int m, int n);
//void cpu_Svd(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//		int m, int n,
//		int *UsesFreq, int pslength
//		);
//void cpu_Svd(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//		int m, int n,
//		int *UsesFreq, int pslength,
//		float *bb, float *cc, float *tt
//		);

void gpu_Svd(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
		int m, int n,
		int *UsesFreq, int pslength
		);

//void cpu_Svd1(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//		int m, int n,
//		int *UsesFreq, int pslength,
//		float *bb, float *cc, float *tt
//		);
//void cpu_Svd2(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//		int m, int n,
//		int *UsesFreq, int pslength,
//		float *bb, float *cc, float *tt
//		);

void gpu_SortEigFvecAscending(float *ai, cuComplex *bi, float *af, cuComplex *bf,
	       int m, int nb_channel, int pslength);

#ifdef __cplusplus
}
#endif


#endif //__EMB_LOCALIZEMUSIC_H__
