#ifndef COMMON_H
#define COMMON_H

#include <stdarg.h>
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include "cJSON.h"

#define DEFAULT_SERVER_PORT 4433
#define DEFAULT_MBOX_PORT 8423
#define str(x) #x
#define xstr(x) str(x)

#define MAX_CONTEXT_LEN (100)

#ifndef UNUSED
#define UNUSED(X) ((void)(x))
#endif

#define MAXSTRLEN (1024)

/* error codes are made of two parts
 * the low 16 bits is a global enum for the type of error
 * the high 16 bits is a local enum that only means something
 * specific to the function that was called.
 * So, an error opening a file will produce a global error FILE_NOT_READABLE
 * but the local error will be used by the function to indicate which file and/or why
 */
#define MKERROR(eGlobalStatus,eLocalStatus) (((eLocalStatus)<<16 & 0xFFFF0000)|((eGlobalStatus)0x0000FFFF))
#define GETLOCALERROR(error,dest) ((dest)=(((error)>>16)&0xFFFF))
#define GETGLOBALERROR(error,dest) ((dest)=(error)&0xFFFF)
typedef enum eERROR_CODES {
	SUCCESS=0,
	INVALID_COMMAND_LINE_ARGS,
	FILE_NOT_FOUND,
	FILE_NOT_READABLE,
	FILE_NOT_WRITABLE,
	FILE_PARSE_ERROR,
	INVALID_POINTER,
	INTEGER_OUT_OF_RANGE,
	ARRAY_OVERFLOW,
	MEMORY_ALLOCATION_FAILURE,
	ERROR_IN_LIBRARY_CALL,
	NETWORK_CONNECT_FAIL,
	ERROR_INTERRUPT,
} ERROR_STATUS;

#define ID_CLIENT (1u)
#define ID_SERVER (2u)
#define ID_MIDDLEBOX_MIN (4u)
#define ID_MIDDLEBOX_MAX (255u)



/*function to wait for a specific FILE to be ready for reading*/
ERROR_STATUS
COMMON_ReadWaitFile(FILE *phF);
/*function to wait for a specific File Descriptor (file, socket, pipe) to be ready for reading*/
ERROR_STATUS
COMMON_ReadWaitFD(int iFD);
ERROR_STATUS
COMMON_ReadProxyListFile(SSL *ptSSL,
		const char *sFilename);
ERROR_STATUS
COMMON_InitProxySet(SSL *ptSSL);
ERROR_STATUS
COMMON_InitMulticontextSet(SSL *ptSSL);
ERROR_STATUS
COMMON_AppendProxy(SSL *ptSSL,
		const char *psProxyURL);
ERROR_STATUS
COMMON_SetServer(SSL *ptSSL,
		const char *psURL);
ERROR_STATUS
COMMON_AppendContext(SSL *ptSSL,
		const char *psContextDesc);
ERROR_STATUS COMMON_SetProxyAccessPermissionByID(SSL *ptSSL, int iSliceID, int iMiddleboxNum,
							int bGrantRead, int bGrantWrite);
ERROR_STATUS COMMON_TcpConnect(int *piSocket, const char *sHost, int iPort);
void COMMON_LogErrorAndExit(int iExitCode, FILE *pLog, const char *csFmtStr, ...);
void COMMON_CheckLogErrorAndExit(int iExitCode, FILE *pLog, const char *csFmtStr, ...);
void COMMON_Log(FILE *pLog, const char *csFmtStr, ...);
void COMMON_CheckLog(int iExitCode, FILE *pLog, const char *csFmtStr, ...);

ERROR_STATUS COMMON_InitializeSSLCtx(SSL_CTX **pptCtx,
		const char *sMyKeyfile, const char *sMyPassword,
		const char *sCAKeysFile,
		unsigned int iID); /*todo - check the name of this in spec - the byte that identifies the middlebox number, client or server*/
void COMMON_DestroyCtx(SSL_CTX *ptCtx);

char* COMMON_WriteJSONFile (cJSON* data, char* source);
cJSON* COMMON_ReadJSONFile (char* filename);

//char* COMMON_GetPrintableBuffer (char* inputBuf, int inputBufLen, int* wasBase64Encoded);

int COMMON_Base64Encode(const unsigned char* buffer, size_t length, char** b64text); 
int COMMON_Base64Decode(char* b64message, unsigned char** buffer, size_t* length); 

char* COMMON_CallExternalProcess(const char* commandString, unsigned int* lengt);

char* COMMON_MakeNullTerminatedCopy (const char* buf, const unsigned int length);
void COMMON_PrintCertificateDetails (X509* cert);

#endif
