/*
 * Relay
 * The program useis Bluez RFCOMM socket to relaying packets 
 * Data packets from child to parent node and 
 * Control packet from parent to child node 
 * 
 * (c) copyright 2005 heejune@snut.ac.kr 
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <getopt.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/poll.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>

#include "bluetooth.h"

#define DEFAULT_INPORT  "/dev/rfcomm0"
#define DEFAULT_OUTPORT  "/dev/rfcomm1"
//#define COMPORT1  "/dev/ttyS0"


static char *rfcomm_config_file = NULL;

static char *relay_state[] = {
	"Starting",     // when just booted 
	"Connecting",   // Try to connect parent 
	"ActiveCon",    // Connected with parent 
	"Listening",    // Waiting for incomming connection from child
	"PassiveCon",   // Connected with child
	"Idle",		// normal working without any connection  
	"Error"         // abnormal state 
};

static volatile sig_atomic_t user_stop = 0;

/* signal alarm */ 
static void sig_alrm(int sig)
{
	return;
}

/* ignore HUP signal */
static void sig_hup(int sig)
{
	return;
}

/* on CTRL-C, we stop job */
static void sig_term(int sig)
{
	user_stop= 1;
}

static void usage(void)
{
	printf("relay [config_file] %s\n"__DATE__);
}


typedef struct {

//	bdaddr_t  dest;
	int  dest;
	unsigned char data[1024];
} packet_t;

#define QSIZE 10
static packet_t pktQ[QSIZE];
static int qsize = 0;
static int qhead = 0;
static int qtail = 0;

#define TEST_PKT_LEN  32

#define RESP_OK ((unsigned int *){0xFFFFFFFF, 12, 0}) 
#define RESP_NOK ((unsigned int *){0xFFFFFFFF, 12, 1}) 

typedef enum{false = 0, true = 1} boolean; 
typedef enum{s_waiting= 0, s_sending = 1} state_t; 

static int incomming_handle(int fd)
{
	int n; 
	char buff[TEST_PKT_LEN];
	// RxRx request with timeout

	printf(" incomming - 1\n");
	n = read(fd,buff,TEST_PKT_LEN);
	printf(" incomming - 2\n");
	if(n < 0){
		perror("Cannot recieve");
	}else{
		printf("recieved: %d bytes\n", n);
	}
	//printf("type enter:");
	//getchar();
	
	// Tx response with timeout
	memset(buff,'1',TEST_PKT_LEN);
	n = write(fd,buff,TEST_PKT_LEN);
	if(n < 0){
		perror("Cannot response");
	}else{
		printf("return: %d bytes\n",n );
	}
	//fsync(fd); // flush it 
	
	close(fd);
}

static int outgoing_handle(int fd)
{
	char message[TEST_PKT_LEN];
	int n; 


	sleep(5);
	memset(message,'1',TEST_PKT_LEN);
	n = write(fd,message,TEST_PKT_LEN);
	if(n < 0){
		perror("Failed to send");
	}else{
		printf("Send %d\n", n);
	}
	//fsync(fd); // flush it 
	//getchar();

	n = read(fd,message,TEST_PKT_LEN);
	if(n< 0){	
		perror("Failed in echoed");
	}else{
		printf("Echoed %d\n", n);
	}
	//getchar();
	close(fd);
}

typedef struct {
	char *rfcomm;
	int x;
	int y;
	char *me;
	char *parent;
	char *child;
	int outdev;
	int indev;
} relay_t;
	
static int read_config_file(relay_t *pConfig, const char *filename)
{
	FILE *fptr = NULL;
	char line[128], key[64], strval[64]; 
	char *pline;
	int  inval;
	char *result;

	memset(line,0,128);
	memset(key,0,64);
	memset(strval,0,64);

	if(filename != NULL){
		fptr = fopen(filename,"r");
	}else{
		fptr = fopen("relay.conf","r");
	}
	if(fptr == NULL){
		perror("Cannot open relay.conf");
		return -1;
	}

	int lineno = 0;

	while(!feof(fptr)){
		lineno++;
		result = fgets(line,127,fptr);
		if(result == NULL){
			return;
		}	
		//printf("check:%s\n", line);

		// comment line 
		if(!strncmp("#",line,1)){
			continue;
		}

		// properties
		pline = line;
		pline= strtok(pline,"="); // key
		// values
		if(!strncmp("rfcomm",pline,6)){
			pline= strtok(NULL,"=");
		        pConfig->rfcomm = strdup(pline);	
		}else if(!strncmp("level",pline,4)){
			pline= strtok(NULL,"=");
			inval = atoi(pline);
		        pConfig->x = inval;	
		}else if(!strncmp("index",pline,5)){
			pline= strtok(NULL,"=");
			inval = atoi(pline);
		        pConfig->y = inval;	
		}else if(!strncmp("me",pline,2)){
			pline= strtok(NULL,"=");
		        pConfig->me = strdup(pline);	
		}else if(!strncmp("parent",pline,6)){
			pline= strtok(NULL,"=");
		        pConfig->parent = strdup(pline);	
		}else if(!strncmp("child",pline,5)){
			pline= strtok(NULL,"=");
		        pConfig->child = strdup(pline);	
		}else if(!strncmp("outdev",pline,6)){
			pline= strtok(NULL,"=");
			inval = atoi(pline);
		        pConfig->outdev = inval;	
		}else if(!strncmp("indev",pline,5)){
			pline= strtok(NULL,"=");
			inval = atoi(pline);
		        pConfig->indev = inval;	
		}else{ 
			printf("undefined at %d-th line : %s\n",lineno, line);
		}
		//getchar();
	}

} 


static void sig_usr1(int num){
	// notifying listening ok 
	return;

}

static void sig_usr2(int num){
	// notifying connection ok
	return;

}

/*  entrance of program */

int main(int argc, char *argv[]) 
{

        relay_t config;	
	bdaddr_t bdaddr;
	int i, opt, ctl, dev_id, show_all = 0;
	int outdev, indev;
	bdaddr_t *pInbdaddr, outbdaddr;
	int txargc = 3;
	char *txargv[] = {"relay","00:0b:24:01:0e:62","3"}; 
	int rxargc = 2;
	char *rxargv[] = {"relay","3"}; 
	int fdOut, fdIn;
	int fd;
	char message[128]; 
	int  nw;
	int n;
	state_t state;
	pid_t pid;
	int ret;
	char devname[128];
	char tmpstr[32];
 	char *env_init[] = {"LD_LIBRARY_PATH=/usr/blue/lib", NULL};



	signal(SIGUSR1, sig_usr1);
	signal(SIGUSR2, sig_usr2);
	// Setup configuration 
	// Default Local BA address
//	bacpy(&bdaddr, BDADDR_ANY);
	if(argc > 1){
		if(read_config_file(&config, argv[1]) < 0){
			exit(0); // configuration error 
		}
	}else{
		if(read_config_file(&config, NULL) < 0){
			exit(0); // configuration error 
		}
	}

	printf(" Config : x=%d, y=%d, me=%s, mom=%s, son=%s, in=%d, out=%d\n", config.x, config.y, config.me, config.parent, config.child, config.indev, config.outdev);

/*
	if(config.me != NULL){
		printf("user defined local bdaddr\n");
		str2ba(config.me,&bdaddr);
	}
*/

	sprintf(message,"this is message");

	// set alarm signal handler; not to be blocked  
	struct sigaction sa;
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = sig_alrm;
	sigaction(SIGALRM, &sa, NULL);

	
	// for test 
	if(config.x==2){
		state = s_sending;
	}else{
		state = s_waiting;
	}

	while(1){

	switch(state){

	case s_waiting:
		//printf("s_waiting ....\n");

		pid = fork();
		if(pid == 0){ // child 
			snprintf(tmpstr,31,"%d",config.indev);
			// execute the rfcomm program 
			printf("%s -i %s lsisten 3\n",config.rfcomm, config.me);
			//ret = execle(config.rfcomm,"relay","-i", config.me, "listen", "3",NULL, "LD_LIBRARY_PATH=\"/usr/blue/lib\"");
//			execle("/bin/ls","ls","-a",NULL,env_init);

			ret = execle(	"/usr/blue/bin/relay","relay",
					"-i", "00:0b:24:01:0e:62", 
					"listen", tmpstr, "3",NULL,
					env_init);
			fprintf(stderr, " child dies......\n");
			exit(0); // the child cannot proceed any more
		}else{
			printf("pausing .\n");
			// wait for connection
			pause();
			printf("escaped\n");

			snprintf(devname,32,"/dev/rfcomm%d",config.indev);
			printf(" rev via /dev/rfcomm%d\n",config.indev);
			printf("escaped2\n");
			fd = open(devname,O_RDWR);
			if(fd < 0)
				perror("Cannot open incomming fd"); 

				printf("escaped3\n");
				incomming_handle(fd);
			}

			// Stop the rfcomm connection 
			ret = kill(pid, SIGINT);
			if(ret < 0){
				perror("Error in killng listening conectin");
			}
			break;

	case s_sending: 

		pid = fork();
		if(pid == 0){ // child 
			snprintf(tmpstr,31,"%d",config.outdev);
			// execute the rfcomm program 
			fprintf(stderr, "connecting.... ......\n");
			ret = execle("/usr/blue/bin/relay", "relay","-i", "00:0b:24:01:0e:C7", "connect", tmpstr, "00:0b:24:01:0e:62","3",NULL,env_init);
			//ret = execle(config.rfcomm,"relay", "-i", config.me,  "connect", tmpstr, config.parent, "3",NULL, env_init);
			printf("die....... .\n");
			exit(0); // the child cannot proceed any more
		}else{

			// wait for connection
			printf("pausing .\n");
			pause();

			snprintf(devname,32,"/dev/rfcomm%d",config.outdev);
			printf(" sending via /dev/rfcomm%d\n",config.outdev);
			fd = open(devname,O_RDWR);
			if(fd < 0)
				perror("Cannot open outgoing fd"); 

			outgoing_handle(fd);
		}

		// Stop the rfcomm connection 
		ret = kill(pid, SIGINT);
		if(ret < 0){
			perror("kill error");
		}
		break;

	default:

		fprintf(stderr,"unknow state: %d\n", state);

	} // switch 	

	} /* while */

	return 0;
}


