#include 	<sys/time.h>
#include 	<sys/timeb.h>
#include    <sys/types.h>
#include    <sys/stat.h>
#include 	<sys/ioctl.h>
#include 	<sys/socket.h>
#include 	<sys/ipc.h>
#include 	<sys/shm.h>
#include 	<sys/shm.h>
#include 	<sys/mman.h>
#include 	<linux/wireless.h>
#include 	<linux/sockios.h>
#include 	<linux/socket.h>
#include 	<arpa/inet.h>
#include 	<netinet/in.h>

#include 	<unistd.h>
#include 	<stdarg.h>
#include    <stdio.h>      
#include    <stdlib.h>     
#include    <unistd.h>     
#include    <fcntl.h>      
#include    <termios.h>    
#include    <errno.h>      
#include 	<errno.h>
#include 	<string.h>
#include	<time.h>
#include	<ctype.h>
#include 	<ifaddrs.h>
#include 	"libwebsockets.h"
#include 	<lws_config.h>
#include	"hashmap.h"
#include    "SystemLogMessage.h"
#include 	"ShareMemory.h"
#include 	<pthread.h>
#include    "MessageHandler.h"
#include	"sqlite3.h"



#if 0
#define DEBUG_INFO(format, args...) StoreLogMsg("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define DEBUG_WARN(format, args...) StoreLogMsg("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define DEBUG_ERROR(format, args...) StoreLogMsg("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#endif

#define Debug
//#define ARRAY_SIZE(A)		(sizeof(A) / sizeof(A[0]))
#define PASS				1
#define FAIL				-1

typedef enum boolean { FALSE, TRUE } BOOL;

struct lws 								*wsi_client;
struct lws_context 						*context;
static int sendbuffer = 0;
extern int server_sign;
//extern int TransactionMessageAttemptsValue;
//extern int TransactionMessageRetryIntervalValue;
//extern int server_pending;

//extern struct OCPP16Data 				*ShmOCPP16Data;
extern void CheckSystemValue(void);
//extern int TransactionMessageAttemptsGet(void);
extern int FirstHeartBeatResponse(void);
extern void OCPP_get_TableAuthlocalAllData(void);
extern int TransactionMessageAttemptsGet(void);
extern int TransactionMessageRetryIntervalGet(void);
extern int GetOcppConnStatus(void);
extern void SetOcppConnStatus(uint8_t status);
extern int GetHeartBeatWithNOResponse(void);
extern void SetHeartBeatWithNOResponse(void);
//extern int InternetDisconnect(void);

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock_sentData = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t receiveData = PTHREAD_MUTEX_INITIALIZER;


//struct json_object 			*parsed_json;

//extern struct node Node;
//==========================================
// Function prototype
//==========================================
void trim(char *s);
int mystrcmp(char *p1,char *p2);
void substr(char *dest, const char* src, unsigned int start, unsigned int cnt);
void getSubStr(char *dest, char* src, char *split, int idx);
void split(char **arr, char *str, const char *del);
int strpos(char *source, char *substr, int skip);
int strposs(char *source, char *substr, int idx);
char *random_uuid( char buf[37] );
static int OCPP16Callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
char * strchr(const char *p, int ch);
void ReceivedMessage(void *in, size_t len);

struct StartTime
{
	unsigned int connect;
	unsigned int bootNotification;
}startTime;

#if 0
unsigned char *SendBuffer;
int SendBufLen=(1024*4);//(1024*3);
#endif
int SendBufLen=(1024*4);//(1024*3);
unsigned char SendBuffer[1024*4]={0};
static int ConnectionEstablished=0;
static int TransactionMessageResend = 1;
static int TransactionQueueInterval = 10;//3; // TransactionMessageAttempts
static int TransactionQueueNum = 0;
static int  OfflineTransaction = 0;
int defaultWaitingTime = 10; //10 second

//===============================
// OCPP SentQueue TransactionId
//===============================
static int SentQueueTransactionId[10]={0};


extern int BootNotificationInterval;
//char guid[37];
//map_t hashMap;
//data_struct_t* mapItem; --- remove for temporally
//data_struct_t mapItem[0]={0};
sqlite3 *db;
char *errMsg = NULL;

static char *createsql = "CREATE TABLE IF NOT EXISTS log_buffer("
              "idx integer primary key,"
	          "user_id text,"
	          "cmd_sn text,"
	          "charger_id text,"
	          "gun_type text,"
	          "gun_no text,"
	          "rfid_no text,"
	          "stime text,"
	          "etime text,"
	          "time_len text,"
	          "s_soc text,"
	          "e_soc text,"
	          "stop_reason text,"
	          "power text,"
	          "meter_before text,"
	          "meter_after text,"
	          "charge_price text,"
	          "reserve text,"
	          "surplus_before text,"
	          "surplus_after text,"
	          "service_price text,"
	          "is_pay text,"
	          "charge_strategy text,"
	          "charge_parameter text,"
	          "vin text,"
	          "vehicle_no text,"
	          "start_method text,"
	          "card_type text,"
	          "is_upload text,"
	          "guid text UNIQUE,"
	          "is_buf2OK text);";

#if 0
static char *createsChargingRecordsql = "CREATE TABLE IF NOT EXISTS ChargingRecord("
              "idx integer primary key,"
	          "gun_type text,"
	          "connectorId text,"
	          "idTag  text,"
		      "transactionId  text,"
	          "stime text,"
	          "etime text,"
	          "time_len text,"
	          "s_soc text,"
	          "e_soc text,"
	          "stop_reason text,"
	          "power text,"
	          "meter_before text,"
	          "meter_after text,"
	          "reservationId  text,"
	          "guid text UNIQUE);";
	          //"is_buf2OK text);";

#endif

static char *sqlOcppAuthCache = "create table if not exists ocpp_auth_cache (idx integer primary key,"
																"idtag text UNIQUE,"
																"parent_idtag text,"
																"expir_date text,"
																"status text);";

static char *sqlOcppAuthLocal = "create table if not exists ocpp_auth_local (idx integer primary key,"
								"idtag text UNIQUE,"
								"parent_idtag text,"
								"expir_date text,"
								"status text,"
								"version text);";

#if 0
static char *sqlInitialOcppAuthLocal = "insert or replace into ocpp_auth_local(idtag, parent_idtag, expir_date, status, version) values('PaHdImHiOnNG','none','2099-12-31T23:59:59.999Z','Accepted','0')";
#endif

int DiffTimeb(struct timeb ST, struct timeb ET)
{
	//return milli-second
	unsigned int StartTime,StopTime;

	StartTime=(unsigned int)ST.time;
	StopTime=(unsigned int)ET.time;
	return (StopTime-StartTime)*1000+ET.millitm-ST.millitm;
}

//=================================
// Common routine
//=================================
void trim(char *s)
{
    int i=0, j, k, l=0;

    while((s[i]==' ')||(s[i]=='\t')||(s[i]=='\n'))
        i++;

    j = strlen(s)-1;
    while((s[j]==' ')||(s[j]=='\t')||(s[j]=='\n'))
        j--;

    if(i==0 && j==strlen(s)-1) { }
    else if(i==0) s[j+1] = '\0';
    else {
        for(k=i; k<=j; k++) s[l++] = s[k];
        s[l] = '\0';
    }
}

int mystrcmp(char *p1,char *p2)
{
    while(*p1==*p2)
    {
        if(*p1=='\0' || *p2=='\0')
            break;
        p1++;
        p2++;
    }
    if(*p1=='\0' && *p2=='\0')
        return(PASS);
    else
        return(FAIL);
}

void substr(char *dest, const char* src, unsigned int start, unsigned int cnt)
{
	strncpy(dest, src + start, cnt);
	dest[cnt] = 0;
}

void getSubStr(char *dest, char* src, char *split, int idx)
{

	int start = (strposs(src,",",idx)+1);
	int cnt = (strposs(src,",",idx+1)-2)-(strposs(src,",",idx)+1);

	strncpy(dest, src + start, cnt);
	dest[cnt] = 0;
}

void split(char **arr, char *str, const char *del)
{
	char *s = strtok(str, del);

	while(s != NULL)
	{
		*arr++ = s;
		s = strtok(NULL, del);
	}
}

int strpos(char *source, char *substr, int skip)
{
   char stack[strlen(source)];
   strncpy(stack, source+skip, strlen(source)-skip);
   char *p = strstr(stack, substr);
   if (p)
      return p - stack+skip;
   return -1;
}

int strposs(char *source, char *substr, int idx)
{
   char stack[strlen(source)];
   int result=0;
   int count=0;

   while(count<=idx)
   {
	   memset(stack,0,sizeof stack);
	   strncpy(stack, source+result, strlen(source)-result);

	   int loc = strcspn(stack, substr);

	   if(loc>0)
		   result += (loc+1);
	   else
		   result = -1;

	   count++;
   }

   return result;
}

char *random_uuid( char buf[37] )
{
    const char *c = "89ab";
    char *p = buf;
    int n;
    for( n = 0; n < 16; ++n )
    {
        int b = rand()%255;
        switch( n )
        {
            case 6:
                sprintf(p, "4%x", b%15 );
            break;
            case 8:
                sprintf(p, "%c%x", c[rand()%strlen(c)], b%15 );
            break;
            default:
                sprintf(p, "%02x", b);
            break;
        }

        p += 2;
        switch( n )
        {
            case 3:
            case 5:
            case 7:
            case 9:
                *p++ = '-';
                break;
        }
    }
    *p = 0;
    return buf;
}


//==========================================
// Web socket tranceive routine
//==========================================
int SendData(struct lws *wsi)
{

    int n;
    int len;
    char *ret;

    unsigned char out[LWS_SEND_BUFFER_PRE_PADDING + 4096 + LWS_SEND_BUFFER_POST_PADDING] = {0};

    len = strlen((char *)SendBuffer);

    if(len == 0)
    return 0;

    memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, SendBuffer, len );
    ret = strstr((const char *)(out + LWS_SEND_BUFFER_PRE_PADDING), "Heartbeat");

    if(ret == NULL)
    {
    	DEBUG_OCPPMESSAGE_INFO(" SendData= %s\n", out + LWS_SEND_BUFFER_PRE_PADDING);
    }

    n = lws_write(wsi, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT);

    memset(SendBuffer, 0, len);
    return n;
}

static int OCPP16Callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{
	switch (reason)
	{
		case LWS_CALLBACK_PROTOCOL_INIT:
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_PROTOCOL_INIT\n");
			#endif

			break;
		case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH:
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH\n");
			#endif
			break;
		case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n");
			#endif
			break;
		case LWS_CALLBACK_WSI_DESTROY:
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_WSI_DESTROY\n");
			#endif
			server_sign = FALSE;
			break;
		case LWS_CALLBACK_LOCK_POLL:
			break;
		case LWS_CALLBACK_ADD_POLL_FD:
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_ADD_POLL_FD\n");
			#endif
			break;
		case LWS_CALLBACK_DEL_POLL_FD:
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_DEL_POLL_FD\n");
			#endif
			break;
		case LWS_CALLBACK_UNLOCK_POLL:
			break;
		case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
			break;
		case LWS_CALLBACK_WSI_CREATE:
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_WSI_CREATE\n");
			#endif
			break;
		case LWS_CALLBACK_GET_THREAD_ID:
			break;
		case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER\n");
			#endif
			break;
		case LWS_CALLBACK_CLIENT_ESTABLISHED://3
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_CLIENT_ESTABLISHED\n");
			#endif
			//connected
			ConnectionEstablished=1;
			break;
		case LWS_CALLBACK_CLIENT_CONNECTION_ERROR://1
			#ifdef Debug
			DEBUG_ERROR("LWS_CALLBACK_CLIENT_CONNECTION_ERROR:%s\n",in);
			#endif
			#ifdef SystemLogMessage
			DEBUG_ERROR("LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n");
			#endif
			//disconnected
			ConnectionEstablished=0;
			break;
		case LWS_CALLBACK_CLOSED://4
			#ifdef SystemLogMessage
			DEBUG_INFO("LWS_CALLBACK_CLOSED\n");
			ConnectionEstablished=0;
			#endif
			//disconnected

			break;
		case LWS_CALLBACK_CLIENT_WRITEABLE://10
			//if(need to send message and its relevant data already store into SendBuffer)
			#ifdef SystemLogMessage
			//DEBUG_INFO("LWS_CALLBACK_CLIENT_WRITEABLE\n");
			#endif
			SendData(wsi);
			break;
		case LWS_CALLBACK_CLIENT_RECEIVE://8
			((char *)in)[len] = '\0';

			//Print Out Adjudgement
			{
				char *ret, *ret1;
				ret = strstr((const char *)in, "currentTime");
				ret1 = strstr((const char *)in, "interval");
				if(!((ret != NULL)&&(ret1 == NULL)))
				{
					DEBUG_OCPPMESSAGE_INFO("Original Receive %s\n", (char *)in);
				}
			}

			char tempin[1024*4]={0};
			int c = 0;
			char *loc;
			char sstr[600]={ 0 };

		 	//**********Receive Message**********/
		  	c = 0;
		  	loc = strstr((const char *)in, "][2,");
		  	if(loc == NULL)
		  	{
		  		loc = strstr((const char *)in, "][3,");

		  		if(loc == NULL)
		  		{
		  			loc = strstr((const char *)in, "][4,");
		  		}

		  	}

		  	memset(sstr ,0, sizeof(sstr) );

		  	if(loc != NULL)
		  	{
		  		DEBUG_INFO("there are continuous second packet []\n");
		  		while (loc[1+c] != '\0')
		  		{
		  			sstr[c] = loc[1+c];
		  			c++;
		  		}

		  		sstr[c] = '\0';
		  		strcpy(tempin, sstr);
		  		DEBUG_INFO("Final Receive: %s\n", tempin);
		  	}
		  	else
		  	{
		  		strcpy(tempin,(char *)in);
		  	}

		  	ReceivedMessage((void *)tempin, len);

			break;

		default:
			#ifdef Debug
			DEBUG_INFO("OCPP16Callback:reason=%d\n", reason);
			#endif
			break;
	}


	return 0;
}

static struct lws_protocols protocols[] = {

	{
		"ocpp1.6",
		OCPP16Callback,
		10240,
		10240,
	},
	{
		"ocpp1.6",
		OCPP16Callback,
		10240,
		10240,
	},
	{
		NULL, NULL, 0		/* End of list */
	}
};


int ConnectWsServer()
{
	int result = PASS;
	struct lws_context_creation_info ContextInfo;
	struct lws_client_connect_info ConnInfo;
	int use_ssl=0;

	//lws_set_log_level(LLL_PARSER | LLL_HEADER, NULL);

	if(context!=NULL)
		lws_context_destroy(context);

	memset(&ContextInfo, 0, sizeof(struct lws_context_creation_info));
	ContextInfo.port = CONTEXT_PORT_NO_LISTEN;
	ContextInfo.iface = NULL;
	ContextInfo.ssl_private_key_password = NULL;
	ContextInfo.ssl_cert_filepath = NULL;
	ContextInfo.ssl_private_key_filepath = NULL;
	ContextInfo.ssl_ca_filepath = "/root/cacert.pem";
	ContextInfo.ssl_cipher_list = NULL; //use default one
	ContextInfo.gid = -1;
	ContextInfo.uid = -1;
	if(use_ssl)
		ContextInfo.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
	ContextInfo.protocols = protocols;
	ContextInfo.timeout_secs = 9999;//30;
	//if(ping pong enabled)
	ContextInfo.ws_ping_pong_interval = 30;//0 for none, else interval in seconds
	context = lws_create_context(&ContextInfo);
	if (context == NULL)
	{
		#ifdef SystemLogMessage
		DEBUG_ERROR("lws_create_context NG");
		#endif
		result = FAIL;
	}

	memset(&ConnInfo,0,sizeof(struct lws_client_connect_info));
	// fill up below information
	ConnInfo.context = context;

	if((strcmp((const char *)GetOcppServerURL(),"")==0) || (GetOcppPort() == 0) || (strcmp((const char *)GetOcppPath(),"")==0) )
	{
		result = FAIL;
		DEBUG_ERROR("OCPP URL is NULL or OCPP Port is zero or  OCPP Path is NULL\n");
		return result;
	}

	ConnInfo.address=(const char *)GetOcppServerURL();

	ConnInfo.port = GetOcppPort();

	ConnInfo.path=(const char *)GetOcppPath();
	ConnInfo.host=lws_canonical_hostname(context);
	ConnInfo.origin="origin";
	ConnInfo.protocol = protocols[1].name;
	ConnInfo.ietf_version_or_minus_one = -1;
	if(use_ssl)
		ConnInfo.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;;

	wsi_client = lws_client_connect_via_info(&ConnInfo);
	if (!wsi_client)
	{
		#ifdef SystemLogMessage
		DEBUG_ERROR("lws_client_connect_via_info NG");
		#endif
		result = FAIL;
	}

	return result;
}

//void createq();
int showfront(char *uuid, char *data);
int addq(char *uuid, char *data) ;
int delq();
int sentqueue();
void CheckTransactionPacket(char *uuid);
int queue_operation(int type, char *frontUUID, char *frontData);


int showfront(char *uuid, char *data) {

FILE *fp;
int result = FALSE; // 1: TRUE  0:FALSE
char str[1200]={0};
char sstr[50]={ 0 };//sstr[200]={ 0 };
int c = 0;
char *loc;
char rmFileCmd[100]={0};
struct stat stats;

stat("../Storage/OCPP", &stats);

// Check for directory existence
if (S_ISDIR(stats.st_mode) == 1)
{
	//DEBUG_INFO("\n OCPP directory exist \n");
}
else
{
	//DEBUG_INFO("\n OCPP directory not exist, create dir \n");
	sprintf(rmFileCmd,"mkdir -p %s","../Storage/OCPP");
	system(rmFileCmd);
}

memset(rmFileCmd, 0, sizeof rmFileCmd);

if((access("../Storage/OCPP/TransactionRelatedQueue",F_OK))!=-1)
{
	//DEBUG_INFO("TransactionRelatedQueue exist.\n");
}
else
{
	//DEBUG_INFO("TransactionRelatedQueue not exist\n");
	FILE *log = fopen("../Storage/OCPP/TransactionRelatedQueue", "w+");

	if(log == NULL)
	{
		DEBUG_INFO("Can't Create File TransactionRelatedQueue \n");
		return 0;
	}
	else
	{
		fclose(log);
	}
}


/* opening file for reading */
fp = fopen("../Storage/OCPP/TransactionRelatedQueue" , "r");
if(fp == NULL) {
	DEBUG_INFO("Error opening TransactionRelatedQueue file");
	return FALSE;
}

if(fgetc(fp)==EOF)
{
	//DEBUG_INFO("It is end of file");
	fclose(fp);
	memset(rmFileCmd, 0, sizeof rmFileCmd);
	sprintf(rmFileCmd,"rm -f %s","../Storage/OCPP/TransactionRelatedQueue");
	system(rmFileCmd);
	result = FALSE;

	return result;
}

if( fgets (str, 1200, fp)!=NULL ) {
	/* writing content to stdout */
	//DEBUG_INFO("str=%s",str);

	if ((str[0] == '\n')||(strcmp(str,"")==0))
	{
		DEBUG_INFO("It is a blank line");
		fclose(fp);
		memset(rmFileCmd, 0, sizeof rmFileCmd);
		sprintf(rmFileCmd,"rm -f %s","../Storage/OCPP/TransactionRelatedQueue");
		system(rmFileCmd);
		result = FALSE;

		return result;
	}
	else
	{
		 //puts(str);
		 /*********************uuid***************/
		 loc = strstr(str, "\"");
		 memset(sstr ,0, sizeof(sstr) );
		 c = 0;
		while (loc[1+c] != '\"')
		{
			sstr[c] = loc[1+c];
			c++;
		}
		sstr[c] = '\0';

		//DEBUG_INFO("\n uuid:%s", sstr);
		//DEBUG_INFO("\n data:%s", str);
		strcpy(uuid,sstr);
		strcpy(data,str);
		result = TRUE;
	}

	//return 1;
}
else
{
	//DEBUG_INFO("queue is null\n");
	strcpy(uuid,"");
	strcpy(data,"");
	result = FALSE;
	//return 0;
}
fclose(fp);
return result;

}

int addq(char *uuid, char *data) {
FILE *outfile;
char rmFileCmd[100]={0};
struct stat stats;
stat("../Storage/OCPP", &stats);
//DEBUG_INFO("addq\n");
// Check for directory existence
if (S_ISDIR(stats.st_mode) == 1)
{
	//DEBUG_INFO("\n OCPP directory exist \n");
}
else
{
	//DEBUG_INFO("\n OCPP directory not exist, create dir \n");
	sprintf(rmFileCmd,"mkdir -p %s","../Storage/OCPP");
	system(rmFileCmd);
}

memset(rmFileCmd, 0, sizeof rmFileCmd);

if((access("../Storage/OCPP/TransactionRelatedQueue",F_OK))!=-1)
{
	//DEBUG_INFO("TransactionRelatedQueue exist.\n");
}
else
{
	//DEBUG_INFO("TransactionRelatedQueue not exist\n");
	FILE *log = fopen("../Storage/OCPP/TransactionRelatedQueue", "w+");

	if(log == NULL)
	{
		DEBUG_INFO("Can't Create File TransactionRelatedQueue \n");
		return 0;
	}
	else
	{
		fclose(log);
	}
}

// open file for writing
outfile = fopen ("../Storage/OCPP/TransactionRelatedQueue", "a");
//DEBUG_INFO("data=%s\n",data);
fputs(data, outfile);
fputs("\n", outfile);
fclose (outfile);
TransactionQueueNum = TransactionQueueNum + 1;
return 0;

}

int delq() {
char tempfile[] = "../Storage/OCPP/temp.json";
FILE *infile;
FILE *outfile;
int  resultRename=0;
char filename[60]={0};
char rmFileCmd[100]={0};
struct stat stats;
stat("../Storage/OCPP", &stats);

DEBUG_INFO("delq()\n");
// Check for directory existence
if (S_ISDIR(stats.st_mode) == 1)
{
	//DEBUG_INFO("\n OCPP directory exist \n");
}
else
{
	//DEBUG_INFO("\n OCPP directory not exist, create dir \n");
	sprintf(rmFileCmd,"mkdir -p %s","../Storage/OCPP");
	system(rmFileCmd);
}

memset(rmFileCmd, 0, sizeof rmFileCmd);

if((access("../Storage/OCPP/TransactionRelatedQueue",F_OK))!=-1)
{
	//DEBUG_INFO("TransactionRelatedQueue exist.\n");
}
else
{
	//DEBUG_INFO("TransactionRelatedQueue not exist\n");
	FILE *log = fopen("../Storage/OCPP/TransactionRelatedQueue", "w+");

	if(log == NULL)
	{
		DEBUG_INFO("log is NULL\n");
		return 0;
	}
	else
	{
		fclose(log);
	}
}

// open file for writing
strcpy(filename, "../Storage/OCPP/TransactionRelatedQueue");
infile = fopen ("../Storage/OCPP/TransactionRelatedQueue", "r");
outfile = fopen (tempfile, "w");

/*检测到文件结束标识返回1,否则返回0。*/
//DEBUG_INFO("feof(infile) =%d\n",feof(infile));
int c;
c = fgetc(infile);
//printf("file c:%d\n",c);
rewind(infile);

if(c == EOF)
{
	//DEBUG_INFO("TransactionRelatedQueue is  NULL\n");

	fclose(infile);
	fclose(outfile);

	sprintf(rmFileCmd,"rm -f %s",tempfile);
	system(rmFileCmd);
}
else
{
	char buf[1200]={0};

	int i = 0;
	//DEBUG_INFO("Orignal File is not NULL\n");
	while (fgets(buf, sizeof(buf), infile) != NULL)
	{
		//printf("Orignal File get strings \n");
		buf[strlen(buf) - 1] = '\0'; // eat the newline fgets() stores

		if(i==0)
		{
			TransactionQueueNum = TransactionQueueNum - 1;
			TransactionQueueInterval = 0;
			TransactionMessageResend = 1;
		}

		if(i != 0)
			fprintf(outfile,"%s\n", buf);

		i = i + 1;
	}

	fclose(infile);
	fclose(outfile);

	sprintf(rmFileCmd,"rm -f %s",filename);
	system(rmFileCmd);

	resultRename = rename(tempfile, filename);


	if(resultRename == 0)
	{
		//DEBUG_INFO("TransactionRelatedQueue file renamed successfully");
	}
	else
	{
		//DEBUG_INFO("Error: unable to rename the TransactionRelatedQueue file");
	}


}

return 0;
}

int showqueue() {
char rmFileCmd[100]={0};
struct stat stats;
stat("../Storage/OCPP", &stats);

// Check for directory existence
if (S_ISDIR(stats.st_mode) == 1)
{
	//DEBUG_INFO("\n OCPP directory exist \n");
}
else
{
	//DEBUG_INFO("\n OCPP directory not exist, create dir \n");
	sprintf(rmFileCmd,"mkdir -p %s","../Storage/OCPP");
	system(rmFileCmd);
}

memset(rmFileCmd, 0, sizeof rmFileCmd);

if((access("../Storage/OCPP/TransactionRelatedQueue",F_OK))!=-1)
{
	//DEBUG_INFO("TransactionRelatedQueue exist.\n");
}
else
{
	//DEBUG_INFO("TransactionRelatedQueue not exist\n");
	FILE *log = fopen("../Storage/OCPP/TransactionRelatedQueue", "w+");

	if(log == NULL)
	{
		DEBUG_INFO("log is NULL\n");
		return 0;
	}
	else
	{
		fclose(log);
	}
}

FILE *fp = fopen("../Storage/OCPP/TransactionRelatedQueue", "r");
char line[1200]={0};
// check if file exist (and you can open it) or not
if (fp == NULL) {
	DEBUG_INFO("can open file TransactionRelatedQueue!");
  return 0;
}

while(fgets(line, sizeof line, fp) != NULL) {
	DEBUG_INFO("%s\n", line);
}

fclose(fp);
return 0;

}

int sentqueue(){
FILE *fp;
int result = FALSE; // 1: TRUE  0:FALSE
int temptransactionId = 0;
int tempconnectorId = 0;
int gunIndex = 0;
char guid[37]={0};
char tempdata[65]={0};
char key_value[65]={0};
int IsStopTransaction = FALSE;
char str[1200]={0};
char strcomposite[1200]={0};
char rmFileCmd[100]={0};
struct stat stats;
char sstr[28]={ 0 };
int c = 0;
char *loc;

DEBUG_INFO("sentqueue\n");
stat("../Storage/OCPP", &stats);

// Check for directory existence
if (S_ISDIR(stats.st_mode) == 1)
{
	//DEBUG_INFO("\n OCPP directory exist \n");
}
else
{
	//DEBUG_INFO("\n OCPP directory not exist, create dir \n");
	sprintf(rmFileCmd,"mkdir -p %s","../Storage/OCPP");
	system(rmFileCmd);
}

memset(rmFileCmd, 0, sizeof rmFileCmd);

/* opening file for reading */
fp = fopen("../Storage/OCPP/TransactionRelatedQueue" , "r");
if(fp == NULL) {
	DEBUG_INFO("Error opening file");
	return FALSE;
}

if( fgets (str, 1200, fp)!=NULL ) {

	/* writing content to stdout */

	//*********************StopTransaction***************************/
	loc = strstr(str, "StopTransaction");
	c = 0;
	memset(sstr ,0, sizeof(sstr) );
	if(loc != NULL)
	{
		IsStopTransaction = TRUE;
    }


	//*********************connectorId***************************/
	loc = strstr(str, "connectorId");
	c = 0;
	memset(sstr ,0, sizeof(sstr) );
	if(loc != NULL)
	{
		while (loc[strlen("connectorId")+2+c] != ',')
		{
			sstr[c] = loc[strlen("connectorId")+2+c];
			c++;
		}
		sstr[c] = '\0';
		tempconnectorId = atoi(sstr);

		//DEBUG_INFO("\n tempconnectorId:%d\n", tempconnectorId);
	}


	//*********************StartTransaction***************************/
	loc = strstr(str, "StartTransaction");
	c = 0;
	memset(sstr ,0, sizeof(sstr) );
	if(loc != NULL)
	{
		//DEBUG_INFO("\n sent queue StartTransaction\n");
		if(tempconnectorId > 0)
		{
			sprintf(tempdata, "StartTransaction,%d", (tempconnectorId-1));
		}
		else if(tempconnectorId == 0)
		{
			sprintf(tempdata, "StartTransaction,%d", 0);
		}


		memset(sstr ,0, sizeof(sstr) );
		//DEBUG_INFO("\n 0-0. sent queue str=%s\n",str);

		c=0;
		while (str[4+c] != '\"')
		{
		  	sstr[c] = str[4+c];
		  	c++;
		}
		sstr[c] = '\0';
		strcpy(guid, sstr);
		//DEBUG_INFO("\n 0. sent queue sstr=%s\n",sstr);



		if(hashmap_operation(1, guid, key_value) == TRUE)
		{
			//DEBUG_INFO("\n 1. sent queue guid=%s\n",guid);
		}
		else
		{
			hashmap_operation(0, guid, tempdata);
			//DEBUG_INFO("\n 2. sent queue guid=%s\n",guid);

		}
	}


	//****************transactionId********************/
	 c=0;
	 loc = strstr(str, "transactionId");
	 memset(sstr ,0, sizeof(sstr) );
	 if(loc != NULL)
	 {

		 while ((loc[strlen("transactionId")+2+c] != '}') && (loc[strlen("transactionId")+2+c] != ','))
		 {
			sstr[c] = loc[strlen("transactionId")+2+c];
			c++;
		 }

		sstr[c] = '\0';
		temptransactionId = atoi(sstr);
		//puts(str);
		//DEBUG_INFO("\n uuid:%s", "");
		//DEBUG_INFO("\n data:%s", str);
		if(IsStopTransaction == TRUE)
		{
			for(int i=0; i <10; i++)
			{
				//DEBUG_INFO("\n StopTransaction i:%d\n", i);
				//DEBUG_INFO("\n StopTransaction SentQueueTransactionId[i]:%d\n", SentQueueTransactionId[i]);
				//DEBUG_INFO("\n sStopTransaction temptransactionId:%d\n", temptransactionId);
				if(SentQueueTransactionId[i] == temptransactionId)
				{
					tempconnectorId = i;
					gunIndex = i;
					break;
				}


			}
		}
		else
		{
			if(tempconnectorId > 0)
			{
				SentQueueTransactionId[tempconnectorId-1] = temptransactionId;
				gunIndex = tempconnectorId-1;
			}
		}

		//DEBUG_INFO("\n gunIndex=%d \n",gunIndex);
		//DEBUG_INFO("\n temptransactionId=%d \n",temptransactionId);
		//DEBUG_INFO("\n GetTransactionId(gunIndex)=%d \n",GetTransactionId(gunIndex));

		if((GetTransactionId(gunIndex) != 0)&&(temptransactionId != GetTransactionId(gunIndex)))
		{
			strncpy(strcomposite,str, (loc-str)+2+strlen("transactionId"));
			sprintf(strcomposite+((loc-str)+2+strlen("transactionId")),"%d",GetTransactionId(gunIndex));
			strcat(strcomposite, loc+strlen("transactionId")+2+c);
			LWS_Send(strcomposite);
		}
		else
		{
			LWS_Send(str);
		}

		if((IsStopTransaction == TRUE)&&(GetTransactionId(gunIndex) != 0))
		{
			SetTransactionIdZero(gunIndex);
		}

	 }
	 else
	 {
		 LWS_Send(str);
	 }

	result = TRUE;
	//return 1;
}
else
{
	//DEBUG_INFO("queue is null\n");

	result = FALSE;
	//return 0;
}
fclose(fp);
//DEBUG_INFO("sentqueue end\n");
return result;
}

//
void* processTransactionQueue(void* data) {
	char frontUUID[100] ={0};
	char frontData[1200/*1024*4*/] ={0};
	int queueNotEmpty = 0;

	while(1)
	{
		if(FirstHeartBeatResponse() == 1)
		{
			memset(frontUUID, 0, sizeof(frontUUID));
			memset(frontData, 0, sizeof(frontData));
			queueNotEmpty = 0;

			queueNotEmpty = queue_operation(1,frontUUID, frontData);//showfront(frontUUID, frontData);    ---> remove temporally

			if((queueNotEmpty == 1) && (GetOcppConnStatus() == 1))
			{
				if((OfflineTransaction == 1) && (TransactionQueueNum != 0))
				{
					TransactionQueueInterval = 10;//2;
					sleep(TransactionQueueInterval);
					sendbuffer = 1;
					DEBUG_INFO("test 1\n");
				}
				else
				{
					OfflineTransaction = 0;
					if(TransactionMessageResend < TransactionMessageAttemptsGet()) //
					{
						DEBUG_INFO("TransactionMessageResend=%d\n",TransactionMessageResend);
						DEBUG_INFO("TransactionMessageAttemptsGet=%d\n",TransactionMessageAttemptsGet());
						DEBUG_INFO("processTransactionQueue queue is not empty!\n");

						TransactionQueueInterval= TransactionMessageRetryIntervalGet()* TransactionMessageResend;
						DEBUG_INFO("TransactionQueueInterval =%d\n",TransactionQueueInterval);
						sendbuffer = 1;
						TransactionMessageResend = TransactionMessageResend + 1;
						DEBUG_INFO("After ADD,TransactionMessageResend=%d\n",TransactionMessageResend);

						sleep(TransactionQueueInterval);


					}
					else
					{
						queue_operation(2,"","");   //// delete item
						TransactionQueueInterval = 0;
						TransactionMessageResend = 1;
						sleep(TransactionQueueInterval);
					}
				}


			}
			else if((queueNotEmpty == 1) && (GetOcppConnStatus() == 0))
			{
				OfflineTransaction = 1;
			}
			else
			{
				TransactionQueueInterval = 0;//10;
				sleep(TransactionQueueInterval);
			}
		}
		usleep(5000);
	}
  pthread_exit(NULL); //
  return 0;
}


void CheckTransactionPacket(char *uuid)
{
	char frontUUID[100]={0};
	char frontData[1200]={0};
	int queueNotEmpty = 0;
	int cmpResult = 0;

	//queue_operation(0,"","");//showqueue(); ---> remove temporally
	queueNotEmpty = queue_operation(1,frontUUID, frontData);//showfront(frontUUID, frontData);  ---> remove temporally

	if(queueNotEmpty == 1)
	{
		cmpResult = strcmp(frontUUID, uuid);
		//cmpResult = strcmp(frontData, uuid);

		if (cmpResult == 0)
		{
			DEBUG_INFO("TransactionPacket Compare All right!\n");
			DEBUG_INFO("frontUUID=%s\n",frontUUID);
			DEBUG_INFO("uuid=%s\n",uuid);
			queue_operation(2,"","");//delq(); ---> remove temporally
			TransactionQueueInterval = 0;
			TransactionMessageResend = 1;
		}

	}

}

/* type: 0 (showqueue ); type: 1(showfront); type: 2(delq) type: 3 (sentqueue)  type: 4 (addq) type: 5(store queue to /Storage/OCPP/ )*/
int queue_operation(int type, char *frontUUID, char *frontData)
{

	pthread_mutex_unlock(&lock_sentData);
	pthread_mutex_lock(&lock_sentData);
	int result=0;
	if(type == 0)   				// show items in queue
			result = showqueue();
	else if(type  == 1)   			// show first item
			result = showfront(frontUUID, frontData);
	else if(type == 2)   			// delete item
			result = delq();
	else if(type == 3)          	// sent items in queue
			result = sentqueue();
	else if(type == 4)         		// add items to the queue
		   result = addq(frontUUID, frontData);

	pthread_mutex_unlock(&lock_sentData);

	return result;
}

char * strchr(const char *p, int ch)
{
    char c;

    c = ch;
    for (;; ++p) {
        if (*p == c)
            return ((char *)p);
        if (*p == '\0')
            return (NULL);
    }
    /* NOTREACHED */
    return NULL;
}

int removeMessageSentFile(void)
{
char rmFileCmd[100]={0};
struct stat stats;

//
stat("../Storage/OCPP", &stats);
// Check for directory existence
if (S_ISDIR(stats.st_mode) == 1)
{
	//DEBUG_INFO("\n OCPP directory exist \n");
}
else
{
	DEBUG_INFO("\n directory not exist, create dir \n");
	sprintf(rmFileCmd,"mkdir -p %s","../Storage/OCPP");
	system(rmFileCmd);
}

memset(rmFileCmd, 0, sizeof rmFileCmd);

if((access("../Storage/OCPP/MessageSent",F_OK))!=-1)
{
	DEBUG_INFO("MessageSent file exist.\n");
	sprintf(rmFileCmd,"rm -f %s","../Storage/OCPP/MessageSent");
	system(rmFileCmd);
}
memset(rmFileCmd, 0, sizeof rmFileCmd);
return 0;
}


#define SystemLogMessage
//================================================
// Main process
//================================================
int main(void)
{
	char rmFileCmd[100]={0};
	struct stat stats;
	pthread_t t;
	#ifdef SystemLogMessage
	DEBUG_INFO("Initialization...\n");
	#endif

	if(ProcessShareMemory()== FAIL)
	{
		return FAIL;
	}

	//Create OCPP dir
	stat("../Storage/OCPP", &stats);

	// Check for directory existence
	if (S_ISDIR(stats.st_mode) == 1)
	{
		//DEBUG_INFO("\n OCPP directory exist \n");
	}
	else
	{
		DEBUG_INFO("\n OCPP directory not exist, create dir \n");
		sprintf(rmFileCmd,"mkdir -p %s","../Storage/OCPP");
		system(rmFileCmd);
	}

	memset(rmFileCmd, 0, sizeof rmFileCmd);

	//Create Process: Resend Transaction
	pthread_create(&t, NULL, processTransactionQueue, NULL); //

	sqlite3_config(SQLITE_CONFIG_URI,1);

	if(sqlite3_open("file:/../Storage/OCPP/charger.db", &db))
	{
		#ifdef Debug
		DEBUG_INFO( "Can't open database: %s\n", sqlite3_errmsg(db));
		#endif
		sqlite3_close( db );
		exit(0);
	}
	else
	{
		#ifdef Debug
		DEBUG_INFO( "Opened database successfully\n");
		#endif
	}

	 //Create Table log buffer
	int rc =sqlite3_exec(db, createsql, 0, 0, &errMsg);
	if (SQLITE_OK != rc)
	{
		#ifdef Debug
		DEBUG_INFO( "Create log buffer table error message: %s\n", errMsg);
		#endif

		return 0;
	}
	else
	{
		#ifdef Debug
		DEBUG_INFO( "Opened log buffer table successfully\n");
		#endif
	}

	 // Create Table OcppAuthCache
	rc =sqlite3_exec(db, sqlOcppAuthCache, 0, 0, &errMsg);
	if (SQLITE_OK != rc)
	{
		#ifdef Debug
		DEBUG_INFO( "Create OcppAuthCache error message: %s\n", errMsg);
		#endif
		return 0;
	}
	else
	{
		#ifdef Debug
		DEBUG_INFO( "Opened OcppAuthCache table successfully\n");
		#endif
	}

	 // Create Table OcppAuthLocal
	rc =sqlite3_exec(db, sqlOcppAuthLocal, 0, 0, &errMsg);
	if (SQLITE_OK != rc)
	{
		#ifdef Debug
		DEBUG_INFO( "Create Table OcppAuthLocal error %s\n",errMsg);
		#endif
		return 0;
	}
	else
	{
		#ifdef Debug
		DEBUG_INFO( "Opened OcppAuthLocal table successfully\n");
		#endif
	}

	initialConfigurationTable();
	removeMessageSentFile();
	//queryAllData();
	OCPP_get_TableAuthlocalAllData();

	for(;;)
	{
		while(ConnectionEstablished==0)
		{
			SetOcppConnStatus(FALSE);

			if((time((time_t*)NULL)-startTime.connect)>=60)
			{
				#ifdef Debug
				DEBUG_INFO("Execute ConnectWsServer\n");
				#endif
				ConnectWsServer();
				startTime.connect=time((time_t*)NULL);
			}

			// Check System Value, process offline Transaction
			CheckSystemValue();
			lws_service(context, 10000);//timeout_ms
		}

		if(( (BootNotificationInterval != 0  && ((time((time_t*)NULL)-startTime.bootNotification)>=BootNotificationInterval) )  || ((time((time_t*)NULL)-startTime.bootNotification)>=defaultWaitingTime) ) && ((server_sign == FALSE)/*|| (server_pending == TRUE)*/))
		{
			//hashmapForMessageNew();
			sendBootNotificationRequest();
			startTime.bootNotification=time((time_t*)NULL);
		}

		if(server_sign == TRUE)
		{
			if(sendbuffer == 1)
			{
				queue_operation(3, "", "");//sentqueue()
				sendbuffer = 0;

			}

			SetOcppConnStatus(TRUE);
			// Check System Value
			CheckSystemValue();
			if(GetHeartBeatWithNOResponse() >= 3)
			{
				lws_context_destroy(context);
				ConnectionEstablished=0;
				context = NULL;
				SetHeartBeatWithNOResponse();
			}
		}

		lws_service(context, 100);//timeout_ms
	}


	pthread_join(t, NULL); //
	//hashmapForMessageFree();
	return FAIL;
}