#ifndef SYSTEM_H
#define SYSTEM_H

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h> /* for int32_t */
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>


#define CAST_TO_UINT32(PTR)   ((uint32_t*)(PTR))
#define CAST_TO_INT32(PTR)    ((int32_t*)(PTR))
#define CAST_VAL_TO_UINT32(VAL)   ((uint32_t)(VAL))
#define CAST_VAL_TO_INT32(VAL)    ((int32_t)(VAL))
#define GET_BYTE0(A) ((uint8_t)(A))
#define GET_BYTE1(A) ((uint8_t)((A) >> 8))
#define GET_BYTE2(A) ((uint8_t)((A) >> 16))
#define GET_BYTE3(A) ((uint8_t)((A) >> 24))

//#define GET_BIT(PTR, BIT_NUM, OFFSET)      (((PTR)->bytes[((BIT_NUM) >> 3) + OFFSET] >> ((BIT_NUM) & 7)) & 1)
//#define SET_BIT(PTR, BIT_NUM, OFFSET, VAL) if(VAL) {(PTR)->bytes[((BIT_NUM) >> 3)+(OFFSET)] |= (1 << ((BIT_NUM) & 7));}\
// 					 else    {(PTR)->bytes[((BIT_NUM) >> 3)+(OFFSET)] &= (~(1 << ((BIT_NUM) & 7)));}
#define GET_BIT(BYTE, OFFSET)    ((BYTE >> OFFSET) & 1)
#define SET_BIT(BYTE, OFFSET)    BYTE = ((BYTE) | (1 << (OFFSET)))
#define CLEAR_BIT(BYTE, OFFSET)  BYTE = ((BYTE) & (~(1 << (OFFSET))))

#define SET_BYTE(PTR, BYTE_NUM,VAL)   (PTR)->bytes[BYTE_NUM] = VAL
#define GET_BYTE(PTR, BYTE_NUM)       ((uint32_t)(PTR->bytes[BYTE_NUM]))
#define GET_BYTE_PTR(PTR, BYTE_NUM)   (&(PTR->bytes[BYTE_NUM]))

#define GET_UINT32_PTR(PTR, BYTE_NUM)  (CAST_TO_UINT32(&((PTR)->bytes[BYTE_NUM])))
#define GET_INT32_PTR(PTR, BYTE_NUM)   (CAST_TO_INT32(&((PTR)->bytes[BYTE_NUM])))
#define GET_UINT32(PTR, BYTE_NUM)      (GET_BYTE((PTR),BYTE_NUM) | (GET_BYTE((PTR),BYTE_NUM+1) << 8) |  (GET_BYTE((PTR),BYTE_NUM+2) << 16) |  (GET_BYTE((PTR),BYTE_NUM+3) << 24))
#define GET_INT32(PTR, BYTE_NUM)       CAST_VAL_TO_INT32(GET_UINT32((PTR), BYTE_NUM))
#define SET_UINT32(PTR, BYTE_NUM, VAL) {SET_BYTE((PTR), BYTE_NUM,  GET_BYTE0(VAL));\
										SET_BYTE((PTR), (BYTE_NUM)+1,  GET_BYTE1(VAL));\
										SET_BYTE((PTR), (BYTE_NUM)+2,  GET_BYTE2(VAL));\
										SET_BYTE((PTR), (BYTE_NUM)+3,  GET_BYTE3(VAL));}
#define SET_INT32(PTR, BYTE_NUM, VAL)   SET_UINT32((PTR), BYTE_NUM, CAST_VAL_TO_UINT32(VAL))

#define IDX_EMPTY (0xffffffff)

#define SET_MAX(A, B)         (((A) > (B))?(A):(B))

/* general types*/
typedef int error_t;

//#include <stdint.h>
typedef enum {
  false = 0,
  true  = 1
} bool_t;

#include <stdint.h>
//typedef signed char    int8_t;
//typedef signed short   int16_t;
//typedef unsigned char  uint8_t;
//typedef unsigned short uint16_t;

//typedef int   		   int32_t;
/* bring this back at home*/
////typedef unsigned long long uint64_t;
//typedef unsigned int   uint32_t;
extern pthread_mutex_t print_mutex;
#define PRINT(fmt, ...)   {pthread_mutex_lock(&print_mutex);printf(fmt, ## __VA_ARGS__);pthread_mutex_unlock(&print_mutex);}

extern char mainlog[20];
typedef unsigned char  bool;
#ifdef Debug
#define LOG(fmt, ...){ \
	int curr_tid = pthread_self(); \
	char fname[20]; \
	FILE* file; \
	struct stat st; \
	stat(mainlog, &st); \
	if(st.st_size  > 1024 * 1024*1024/* 1GB*/){ \
		mainlog[8] = 't' + ((mainlog[8]+1 -'t') % 2); \
		file = fopen(mainlog, "w+"); \
		fclose(file); \
	} \
	if(curr_tid == maintid){ \
		strcpy(fname, mainlog); \
	} \
	else{ \
		int i; \
		for(i=0;i<NAND_CHIP_COUNT;i++){ \
			if(tids[i] == curr_tid){ \
				strcpy(fname, "log_chip0"); \
				fname[8] = '0'+i; \
			} \
		} \
	} \
	file = open_file(fname); \
	fprintf(file, "%s:%d. %s() - ", filename, __LINE__, __func__); \
	fprintf(file, fmt, ## __VA_ARGS__); \
	fclose(file); \
}
#else
#define LOG(fmt, ...)
#endif

#ifdef PROFILING
extern uint32_t hint_accessed;
extern uint32_t read_accessed;
#endif

#endif
