////////////////////////////////////////////////////////////////////////////////////////
//////  This is BankofAmericansystem.c 
//////  It¡¯s the bank center program, working in the user space. 
/////////////////////////////////////////////////////////////////////////////////////////

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <time.h>
#include <rtai_sched.h>
#include <rtai_fifos.h>
#include <rtai.h>
#include <sys/mman.h>
#include <sys/stat.h>



//#define N 20    // the total amount of accounts
int N=0;		// the total amount of accounts
int timecount=0;
//int intopen=0;      //open the interest system
#define PORT1 2000
#define PORT2 1900
RTIME period;
struct depositor
{
	char num[20];   //account number
	char name[20];  //account name
	char per[20];	 //custom ID
	char sec[20];		 // account password
	float mon;		 // the amount of balance
};


char buffer[200]; // global buffer
void error(const char *msg)
{
	perror(msg);
	exit(0);
}
void menu();
struct depositor *  reads();
void save(struct depositor *,int n);
void add();
void del();
void change();
void show();
void showall();
void deposit();
void withdraw();
void* setspeaker(void);
void* Bankshow();  // thread 1
void* ATMserver(); // thread 2
void* Bankinterest();// thread3
void* ConnectCheck();// thread4
void* timerclock(void);// thread 5
void main()
{
	pthread_t thread1, thread2,thread3,thread4;
	pthread_create(&thread1,NULL,Bankshow,NULL);
	pthread_create(&thread2,NULL,ATMserver,NULL);
	pthread_create(&thread3,NULL,Bankinterest,NULL);
	pthread_create(&thread4,NULL,ConnectCheck,NULL);
	pthread_join(thread1,NULL);
	pthread_join(thread2,NULL);
	pthread_join(thread3,NULL);
	pthread_join(thread4,NULL);
	return;
}
void* Bankinterest(void)
				{
	float interest=0.01;
	char flag;
	int fd_read,i=0,n=0;
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	fd_read = open("/dev/rtf/1",O_RDWR);  // talk to the kernal
	while(1)
	{
		if((n=read(fd_read,&flag,sizeof(flag)))<0)
		{
			printf("Read Fifo error!");
		}

		if(flag='@')
		{
		//	printf("get the flag '@', change the interest...\n");
			dep=reads();
			n=N;
			for(i=0;i<n;i++)
			{
				dep[i].mon=dep[i].mon*(1+interest);
			}
			save(dep,n);
		}

	}
}




void* ATMserver(void) //thread 2 connect ATM with TCP socket
{

	struct depositor acp;
	struct depositor *acppt=&acp;
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	struct depositor Nobody;
	strcpy(Nobody.num,"0000");
	int sockfd;
	int new_fd;
	int on=1;
	int n=0,i=0;
	//char IP[50];
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	int sin_size;
	sockfd = socket(AF_INET,SOCK_STREAM,0);// create a socket
	if (sockfd < 0)                          // sockfd is the descriptor of this socket
		error("Error opening socket");
	bzero(&server_addr,sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // any IP is able to connect
	server_addr.sin_port = htons(PORT1);
	// set the option of socket
	setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	n=bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr_in));
	if (n < 0)
		error("ERROR binding socket");
	n=listen(sockfd,5);
	if (n < 0)
		error("ERROR listening socket");
	//printf("wait!!!!!\n");
	n=new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size);
	if (n < 0)
		error("ERROR accepting socket");

//	printf("Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));
	while(1)
	{


		n=read(new_fd,&acp,sizeof(struct depositor));
		if (n < 0)
			error("ERROR reading from socket");
	//	printf("receive the message: number:%s\n",acp.num);
	//	printf("receive the message password:%s\n",acp.sec);
		dep=reads();
		n=N;
		for(i=0;i<n;i++)
			if(strcmp(acp.num,dep[i].num)==0 && strcmp(acp.sec,dep[i].sec)==0) break;
		if(i>=n)// if its wrong, send the 0000;
		{

			n=write(new_fd,&Nobody,sizeof(struct depositor));
			if (n < 0)
				error("ERROR writing from socket");
		}
		else
		{
		//	printf("receive name:%s",acp.name);
			if(strcmp(acp.name,"Check")==0)    // this is checking message
			{
		//		printf("herer1");
				n=write(new_fd,&dep[i],sizeof(struct depositor));
				if(n < 0)
					error("ERROR writing from socket");
			}
			else{
		//		printf("herer2");
				dep[i]=acp; // change the information of the database
				save(dep,n);
			}
		}

	}
	close(sockfd);
	pthread_exit(NULL);
}
/////////////////////////////////////////////////////
////this is a thread. in the thread, build up a socket to connect the ATM, and receive
//// signal from ATM, if it doesn't receive the signal for 5s
//// then turn on the buzzer to alarm
///////////////////////////////////////////////////////
void* ConnectCheck()
{
	struct timeval tv;
	struct timeval tz;
	period=start_rt_timer(nano2count(1000000));  // period is 1ms
	unsigned long timestamp=0,pretime=0,temp;
	int sockfd;
	int new_fd;
	int on=1;
	int n=0;
	char flag;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	int sin_size;
	sockfd = socket(AF_INET,SOCK_STREAM,0);// create a socket
	if (sockfd < 0)                          // sockfd is the descriptor of this socket
		error("Error opening socket");
	bzero(&server_addr,sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // any IP is able to connect
	client_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // any IP is able to connect
	server_addr.sin_port = htons(PORT2);
	// set the option of socket
	setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	n=bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr_in));
	if (n < 0)
		error("ERROR binding socket");
	n=listen(sockfd,5);
	if (n < 0)
		error("ERROR listening socket");
	//printf("wait!!!!!\n");
	n=new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size);
	if (n < 0)
		error("ERROR accepting socket");
	// printf("im here to come TMD      \n");
//	printf("Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));

	gettimeofday(&tv,&tz);
	pretime=tv.tv_sec*1000000+tv.tv_usec;


	pthread_t thread5;
	pthread_create(&thread5,NULL,timerclock,NULL);

	while(1)
		{

		//    printf("im here to come       \n");
			n=read(new_fd,&flag,sizeof(flag));
			if (n < 0)
				error("ERROR reading from socket");
		//	printf("get the flag %c       \n", flag);
			if (flag=='#')
			{
				timecount=0;
				gettimeofday(&tv,&tz);
				timestamp=tv.tv_sec*1000000+tv.tv_usec;
				temp=timestamp-pretime;
				pretime=timestamp;
			//	printf("diff: %lu usec\n", temp);
			}

		}

}
void* timerclock(void)
{
	RT_TASK* rttask1 = rt_task_init(nam2num("thrd2"), 0, 512, 256);
	rt_task_make_periodic(rttask1, rt_get_time(), 1000*period);  /// per 1s
	while(1)
	{
		timecount=timecount+1;
		if(timecount>5)        /// 5s
		{
			printf("time out =5s set up the buzzer!");

		 setspeaker();
		}
		rt_task_wait_period();
	}

}
void * setspeaker(void)
{
	int fd,i;
	unsigned long *ptr,*pfdr,*pfddr;
	fd=open("/dev/mem", O_RDWR);       //the name of registers to map
	ptr = mmap(NULL, getpagesize(),PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x80840000);
	// use mmap function to map the registers to memory,
	//  ptr points to the beginning address of the registers
	pfdr = ptr + 0x0c;    // pfdr points to the address of portf data register
	pfddr = pfdr + 0x01;  // pfddr points to the address of portf data direction register
	*pfddr = *pfddr|0x02;  // set the Portf1 of DDR 1,so direction is output
	while(1)    // in this endless loop, Portf1 of DR is setted up and down
	{
		*pfdr=*pfdr|0x02;       //Portf1 of DR is set 1
		msync(ptr,getpagesize(),MS_ASYNC);  //refresh the registers
	//	for(i=1;i<10000;i++);     // pending // change to sleep
        rt_sleep(500);
		*pfdr=*pfdr&0xfd;        //Portf1 of DR is set 0
		msync(ptr,getpagesize(),MS_ASYNC);  //refresh the registers
	//	for(i=1;i<10000;i++);     //pending
		rt_sleep(500);

	}
}


void* Bankshow(void)  // thread 1
		{
	int n;
	while(1)
	{
		menu();
		printf(" Please choose your operation:");
		scanf("%d",&n);

		switch(n)
		{
		case 1: add();break;
		case 2: show();break;
		case 3: del();break;
		case 4: change();break;
		case 5: deposit();break;
		case 6: withdraw();break;
		case 7: exit(0);
		case 8: showall(); break;
		default:  printf("Error number. Please choose again.\n ");
		}
	}
		}
void deposit()
{
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	char number[20];
	char t[20];
	int n,i;
	float cash;
	dep=reads();
	n=N;
	//printf("N=%d",N);
	printf("\n Please enter the account number and password:\n ");
	printf("Account number:");
	scanf("%s",number);
	printf("Password:    ");
	scanf("%s",t);
	for(i=0;i<n;i++)
		if(strcmp(number,dep[i].num)==0) break;
	if(i>=n)
	{
		printf("Can't find this account.\n");
		return;
	}
	else
	{
		if(strcmp(t,dep[i].sec)==0)
		{
			printf("Please enter the amount of cash to deposit:");
			scanf("%f", &cash);
			dep[i].mon+=cash;
		}
		else
		{
			printf("The password is not correct.\n");
			return;
		}
	}
	save(dep,n);
	printf("\n Deposit cash successfully.\n");
}
void withdraw()
{
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	char number[20];
	char t[20];
	int n,i;
	float cash;
	dep=reads();
	n=N;
	//printf("N=%d",N);
	printf("\n Please enter the account number and password:\n ");
	printf("Account number:");
	scanf("%s",number);
	printf("Password:    ");
	scanf("%s",t);
	for(i=0;i<n;i++)
		if(strcmp(number,dep[i].num)==0) break;
	if(i>=n)
	{
		printf("Can't find this account.\n");
		return;
	}
	else
	{
		if(strcmp(t,dep[i].sec)==0)
		{
			printf("Please enter the amount of cash to deposit:");
			scanf("%f", &cash);
			if ((dep[i].mon)>=cash)
			{
				dep[i].mon-=cash;
			}
			else
			{
				printf("Sorry! Insufficient Balance!");
				return;
			}
		}
		else
		{
			printf("The password is not correct.\n");
			return;
		}
	}
	save(dep,n);
	printf("\n Deposit cash successfully.\n");
}
void add()  // create an account and add it to the file
{
	FILE *fp;
	int i=0,n=0;
	struct depositor dep;
	struct depositor *deptotal=(struct depositor *)malloc(sizeof(struct depositor)*20);
	deptotal=reads();
	n=N;
	if((fp=fopen("Account.dat","a"))==NULL)
	{
		if((fp=fopen( "Account.dat","w"))==NULL)
		{
			printf("No account space available.\n");
			return ;
		}
	}
	printf("\n Please enter the account number: \n");
	scanf("%s",dep.num);
	for(i=0;i<n;i++)
	{
		if (strcmp(dep.num,deptotal[i].num)==0)
		{
			printf("Sorry!This account has existed.");
			return;
		}
	}
	fprintf(fp,"\n%s\n",dep.num);   // write into the file
	printf("Please enter the account name: \n");
	scanf("%s",dep.name);
	fprintf(fp,"\n%s\n",dep.name);
	printf("Please enter the account ID: \n");
	scanf("%s",dep.per);
	fprintf(fp,"\n%s\n",dep.per);
	printf("Please enter the account password: \n");
	scanf("%s",dep.sec);
	fprintf(fp,"\n%s\n",dep.sec);
	printf("Please enter the amount of money: \n");
	scanf("%f",&dep.mon);
	fprintf(fp,"\n%f\n",dep.mon);
	if(dep.mon<100 )
	{	 printf("\n = The amount of money is below $100. \n");
	return ;
	}
	printf("\n Create the account successfully.\n");
	fclose(fp);
}
void del()  // delete an account from the file
{


	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	char number[20];
	char t[20];
	int n,i,j;
	dep=reads();
	n=N;
	//printf("N=%d",N);
	printf("\n Please enter the account number and password:\n ");
	printf("Account number:");
	scanf("%s",number);
	printf("Password:    ");
	scanf("%s",t);

	for(i=0;i<n;i++)
		if(strcmp(number,dep[i].num)==0) break;
	if(i>=n)
	{
		printf("Can't find this account.\n");
		return;
	}
	else
	{
		if(strcmp(t,dep[i].sec)==0)
		{
			for(j=i+1;j<n;j++)
				*(dep+j-1)=*(dep+j);
			save(dep,n-1);
			printf("Delete the account successfully.\n");
		}
		else
		{
			printf("The password is not correct.\n");
			return;
		}
	}

}

struct depositor * reads() //read the information of the account
														{
	FILE *fp;
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	int i=0;
	if((fp=fopen("Account.dat","r"))==NULL)
	{
		printf("Error opening the file.\n");
		return 0;
	}
	else
	{
		for(i=0;!feof(fp);i++)
			fscanf(fp,"\n%s %s %s %s %f\n", dep[i].num,dep[i].name,dep[i].per,dep[i].sec,&(dep[i].mon));
		N=i;
	}
	fclose(fp);
	return dep;
														}
void save(struct depositor *deptmp,int n) // save the information of the account
{
	int i=0;
	FILE *fp;
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	dep=deptmp;


	if((fp=fopen("Account.dat","w"))==NULL)
	{
		printf("Error opening the file.\n");
		return ;
	}
	else
	{
		for(i=0;i<n;i++)
			fprintf(fp,"\n%s %s  %s %s %f\n",dep[i].num,dep[i].name,dep[i].per,dep[i].sec,dep[i].mon);
	}
	fclose(fp);
}

void show() // show the balance of the account
{
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	int i=0,n=0;
	char number[20];
	char t[20];
	dep=reads();
	n=N;
	printf("\n Please enter the account number and password:\n");

	printf("Account number:");
	scanf("%s",number);
	printf("Password:    ");
	scanf("%s",t);
	for(i=0;i<n;i++)
		if (strcmp(number,dep[i].num)==0 && strcmp(t,dep[i].sec)==0) break;
	if (i>=n || strcmp(t,dep[i].sec)!=0)
	{
		printf("\n Wrong account number or Wrong password.\n");
		return ;
	}
	else

	{ printf("*************the balance of the account*********\n");
	printf("Balance: \n");
	printf("\n $%11.2f \n", dep[i].mon);
	printf("**************************************************\n");
	}
}
void showall() // show the balance of the account
{
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	int i=0,n=0;

	dep=reads();
	n=N;
	for(i=0;i<n;i++)
	{
		printf("********the account %d ********\n", i);
		printf("the number   is %s\n", dep[i].num );
		printf("the name     is %s\n", dep[i].name );
		printf("the ID       is %s\n", dep[i].per );
		printf("the password is %s\n", dep[i].sec );
		printf("the balance  is $%11.2f\n", dep[i].mon );

	}

}
void change()  // change the password
{
	struct depositor *dep=(struct depositor *)malloc(sizeof(struct depositor)*20);
	int n=0,i=0;
	char t[20];
	char number[20];

	printf("\n Please enter the account number and password:\n ");
	printf("Account number:");
	scanf("%s",number);
	printf("Password:    ");
	scanf("%s",t);
	dep=reads();
	n=N;
	for(i=0;i<n;i++)
		if(strcmp(number,dep[i].num)==0 && strcmp(t,dep[i].sec)==0)
			break;
	if(i>=n||strcmp(t,dep[i].sec)!=0)
	{
		printf("\n Wrong account number or Wrong password.\n");
		return;
	}
	printf("\n Please enter the new password:\n");
	scanf("%s",dep[i].sec);
	save(dep,n);
	printf("\n Change the password successfully.\n");
}

void menu()  // show the menu
{

	printf("\n\n ************* Welcome to Bank Of America ******************* ");
	printf("\n                   1   Create an account");
	printf("\n                   2   Show the balance");
	printf("\n                   3   delete the account ");
	printf("\n                   4   change the password");
	printf("\n                   5   Deposit cash");
	printf("\n                   6   Withdraw cash");
	printf("\n                   7   Quit");
	printf("\n ************************************************************ \n");

}