#include <stdio.h>
#include "vga_ball.h"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include "usbkeyboard.h"
#include <math.h>
#include <time.h>

#define N0	0
#define N1	1
#define N2	2
#define N3	3
#define N4	4
#define N5	5
#define N6	6
#define N7	7
#define N8	8
#define N9	9
#define BRICK_W  64
#define BRICK_H  32
#define BALL_R   8
#define PADDLE_W 90
#define PADDLE_H 20
#define PADDLE_R 10
#define PADDLE_L 70
/* version with both mouse and keyboard control */

int				vga_ball_fd;
double				h_location;
struct libusb_device_handle	*keyboard;
uint8_t				endpoint_address;
struct usb_keyboard_packet	packet;
int				transferred;
char				keystate[12];
int				brick_status[7][10];
double				speed_paddle, ball_h=312.0, ball_v=440.0, speed_h, speed_v;
double				t_speed;
int             audio_choose;
int finalstatus = 0;

hardware_p data = { 0, 0, 0, 0, 0 };
libusb_device_handle 		*mouse;     //a mouse device handle
unsigned char 			datain[1024]="\0";
int				size;
int reset = 1;
int lives = 3;
int game_start = 0;
int level = 1;
int score = 0;

pthread_t keyboard_thread;
pthread_t mouse_thread;
void *keyboard_thread_f( void * );
void *mouse_thread_f( void * );

double absoluteDouble(double x){
	if (x < 0)
		return (0-x);
	else
		return (x);
}


double square(double x){
	return x*x;
}
int getscore1(int x){
	int y = (int)(x/100);
	return y;
}
int getscore2(int x){
	int y = (int)(x-100*getscore1(x))/10;
	return y;
}
int getscore3(int x){
	int y = x % 10;
	return y;
}
int lives2bin(int lives){
	if (lives == 3)
		return 7;
	else if(lives==2)
		return 6;
	else if (lives==1)
		return 4;
	else
		return 0;
}

/* Read and print the background color */
void print_alldata_color()
{
	vga_ball_arg_t vla;

	if ( ioctl( vga_ball_fd, VGA_BALL_READ_alldata, &vla ) )
	{
		perror( "ioctl(VGA_BALL_READ_alldata) failed" );
		return;
	}
	printf( "%02x %02x %02x\n",
		vla.alldata.red, vla.alldata.green, vla.alldata.blue );
}

// fresh the display
void set_alldata( const hardware_p *c )
{
	vga_ball_arg_t vla;
	vla.alldata = *c;
	if ( ioctl( vga_ball_fd, VGA_BALL_WRITE_alldata, &vla ) )
	{
		perror( "ioctl(VGA_BALL_SET_alldata) failed" );
		return;
	}
}


unsigned short convert2bin( int x[10] )
{
	unsigned short	y=0;
	int		i=0, j=0, k;
	for ( i = 0; i < 10; i++ )
	{
		k = 1;
		for ( j = 0; j < i; j++ )
			k = k * 2;
		y = y + x[i] * k;
	}
	return(y);
}

/* newly developed function */
/* return flag = 0 if not hit on the brick */
/* return flag = 1 if hit on the brick from top or bottom */
/* return flag = 2 if hit on the brick from left or right */
/* return flag = 3 if hit on the brick corner*/
/* use the flag to determine the ball velocity change */
/* the corresponding brick status should be changed into 0 */
// notice
int hitOnBrick( int brick_width, int brick_height, int brick_h, int brick_v, int ball_radius, 
                double *p_ball_h, double *p_ball_v, 
                double *p_corner_theta, int *p_audio_choose ){
	double	n_ball_h		= *p_ball_h + BALL_R;
	double	n_ball_v		= *p_ball_v + BALL_R;
	double   n_corner_theta= *p_corner_theta; 
	int     flag;
	int     n_audio_choose= *p_audio_choose;
	// hit on top 1
	if (n_ball_h >= brick_h && n_ball_h <= brick_h + brick_width 
		&& n_ball_v >= brick_v - ball_radius && n_ball_v < brick_v + brick_height ){
		flag = 1;
		n_audio_choose = 2;
	}
	// hit on bottom 2
	else if (n_ball_h >= brick_h && n_ball_h <= brick_h + brick_width 
		&& n_ball_v < brick_v + brick_height + ball_radius && n_ball_v > brick_v){
		flag = 2;
		n_audio_choose = 2;
	}
	// hit from left 3
	else if (n_ball_v >= brick_v && n_ball_v <= brick_v + brick_height 
		&& n_ball_h >= brick_h - ball_radius && n_ball_h < brick_h + brick_width ){
		flag = 3;
		n_audio_choose = 2;
	}
	// hit from right 4
	else if (n_ball_v >= brick_v && n_ball_v <= brick_v + brick_height 
		&& n_ball_h < brick_h + brick_width + ball_radius && n_ball_h > brick_h ){
		flag = 4;
		n_audio_choose = 2;
	}
	// corner right bottom 5
	else if (square(n_ball_h-(brick_h+brick_width))+square(n_ball_v-(brick_v+brick_height)) 	< square(ball_radius)	){
		flag = 5;
		n_audio_choose = 2;
		n_corner_theta = atan((brick_v+brick_height-n_ball_v)/(brick_h+brick_width-n_ball_h));
	}
	// corner right top	6
	else if ( square(n_ball_h-(brick_h+brick_width))+square(n_ball_v-brick_v) 					< square(ball_radius) ){
		flag = 6;
		n_audio_choose = 2;
		n_corner_theta = atan((brick_v-n_ball_v)/(brick_h+brick_width-n_ball_h));
	}
	// corner left top	7
	else if ( square(n_ball_h-brick_h)+square(n_ball_v-brick_v) 								< square(ball_radius)	){
		flag = 7;
		n_audio_choose = 2;
		n_corner_theta = atan((brick_v-n_ball_v)/(brick_h-n_ball_h));
	}
	// corner left bottom	8
	else if ( square(n_ball_h-brick_h)+square(n_ball_v-(brick_v + brick_height)) 				< square(ball_radius)	){
		flag = 8;
		n_audio_choose = 2;
		n_corner_theta = atan((brick_v+brick_height-n_ball_v)/(brick_h-n_ball_h));
	}
	// doesn't hit on the brick 0
	else{
		flag = 0;
	}
	*p_audio_choose = n_audio_choose;
	*p_corner_theta = n_corner_theta;
	
	return flag;
}


void hitOnWall(double *p_ball_h, double *p_ball_v, double *p_speed_h, double *p_speed_v, int *p_audio_choose){
	double	n_ball_h		= *p_ball_h + BALL_R;
	double	n_ball_v		= *p_ball_v + BALL_R;
	double	n_speed_h		= *p_speed_h;
	double	n_speed_v		= *p_speed_v;
	int     n_audio_choose  = *p_audio_choose;
	// hit from top
	if (n_ball_v + n_speed_v <= BALL_R + BRICK_H){
		n_speed_v = 0 - n_speed_v;
		n_audio_choose = 1;
	}

	if (n_ball_h + BALL_R + n_speed_h >= 640 || n_ball_h + n_speed_h <= BALL_R ){
		n_speed_h = 0 - n_speed_h;
		n_audio_choose = 1;
	}


	*p_ball_h	= n_ball_h - BALL_R;
	*p_ball_v	= n_ball_v - BALL_R;
	*p_speed_h	= n_speed_h;
	*p_speed_v	= n_speed_v;
	*p_audio_choose = n_audio_choose;
}


int hitOnPaddle(double *p_ball_h, double *p_ball_v, double *p_speed_v, int *p_audio_choose, 
				double *p_paddle_position, double *p_paddle_speed, int *p_game_status, double *p_corner_theta){
	double	n_ball_h		= *p_ball_h + BALL_R;
	double	n_ball_v		= *p_ball_v + BALL_R;
	double  n_paddle_speed= *p_paddle_speed;
	double  n_paddle_x0 = 	*p_paddle_position + n_paddle_speed;
	double  n_paddle_y0 =   455.0;
	double  n_speed_v   = *p_speed_v;
	double  n_corner_theta = *p_corner_theta;
	int     n_audio_choose= *p_audio_choose;
	int     n_game_status = *p_game_status;
	int     flag;

	// center of the left half circle
	double  n_paddle_x1 = n_paddle_x0 + PADDLE_R;
	double  n_paddle_y1 = n_paddle_y0 + PADDLE_R;
	
	// center of the right half circle
	double  n_paddle_x2 = n_paddle_x1 + PADDLE_L;
	double  n_paddle_y2 = n_paddle_y1;
	

	// same as hit on brick, return the ball status flag
	// hit from the top
	if (speed_v > 0 && n_ball_v <= 474 - 0.5 * PADDLE_H ){
		if (n_ball_h >= n_paddle_x1 && n_ball_h <= n_paddle_x2 && n_ball_v >= n_paddle_y0 - BALL_R &&  n_ball_v <= n_paddle_y0){
			flag = 9;
			n_audio_choose = 1;
		}
		else if (square(n_ball_h-n_paddle_x1)+square(n_ball_v-n_paddle_y1) < square(BALL_R + PADDLE_R)
		&&  square(n_ball_h-n_paddle_x1)+square(n_ball_v-n_paddle_y1) > square(PADDLE_R)){
			flag = 10;
			n_corner_theta = atan((n_paddle_y1-n_ball_v)/(n_paddle_x1-n_ball_h));
			n_audio_choose = 1;
		}
		else if (square(n_ball_h-n_paddle_x2)+square(n_ball_v-n_paddle_y2) < square(BALL_R + PADDLE_R)
		&&  square(n_ball_h-n_paddle_x1)+square(n_ball_v-n_paddle_y1) > square(PADDLE_R)){
			flag = 11;
			n_corner_theta = atan((n_paddle_y2-n_ball_v)/(n_paddle_x2-n_ball_h));
			n_audio_choose = 1;
		}
	}
	

	if (n_ball_v >= 488){
		lives -= 1;
		game_start = 0;
		printf("%d lives left!\n",lives);


		if (lives == 0){
			n_game_status = 0;
			finalstatus = 2;
			printf("GAME OVER\n");
		}
		else{
			reset = 1;
		}

	}

	*p_ball_h	= n_ball_h - BALL_R;
	*p_ball_v	= n_ball_v - BALL_R;

	*p_audio_choose = n_audio_choose;
	*p_game_status = n_game_status;
	*p_corner_theta = n_corner_theta;

	return flag;

}


// according to flag change the velocity of ball and also the brick status
void changeVelocityAndBrickStatus(int flag, double *p_speed_h, double *p_speed_v, int *brick_status, double *p_corner_theta ){
	double   n_corner_theta  = *p_corner_theta;
	double	n_speed_h		= *p_speed_h;
	double	n_speed_v		= *p_speed_v;
	double  n_speed_h_temp;
	double  n_speed_v_temp; 
	// hit from top
	if (flag == 1){
		if (n_speed_v > 0)
			n_speed_v = 0 - n_speed_v;
		*brick_status = 0; 
		printf("changed vertical velocity\n");
	}
	// hit from bottom
	else if (flag == 2){
		if (n_speed_v < 0)
			n_speed_v = 0 - n_speed_v;
		*brick_status = 0; 
		printf("changed vertical velocity\n");
	}
	// hit from left
	else if (flag == 3){
		if (n_speed_h > 0)
			n_speed_h = 0 - n_speed_h;
		*brick_status = 0;
		printf("changed horizontal velocity\n");
	}
	// hit from right
	else if (flag == 4){
		if (n_speed_h < 0)
			n_speed_h = 0 - n_speed_h;
		*brick_status = 0;
		printf("changed horizontal velocity\n");
	}
	else if (flag == 5 || flag == 6 || flag == 7 || flag == 8){
		n_speed_h_temp  = n_speed_h;
		n_speed_v_temp  = n_speed_v; 
		printf("original speed_h is %f, original speed_v is %f\n", n_speed_h, n_speed_v);
		n_speed_h = 0.0-cos(2.0*n_corner_theta)*n_speed_h_temp-sin(2.0*n_corner_theta)*n_speed_v_temp;
		n_speed_v = 0.0-sin(2.0*n_corner_theta)*n_speed_h_temp+cos(2.0*n_corner_theta)*n_speed_v_temp;
		*brick_status = 0;
		printf("hit on the corner\n angle is %f\n", n_corner_theta);
		printf("speed_h is %f, speed_v is %f\n", n_speed_h, n_speed_v);
	}


	*p_corner_theta = n_corner_theta;
	*p_speed_h	= n_speed_h;
	*p_speed_v	= n_speed_v;
}

// change velocity after hitting on the paddle
void changeVelocityHitPaddle(int flag, double *p_speed_h, double *p_speed_v, double *p_speed_paddle, double *p_corner_theta ){
	double  n_corner_theta  = *p_corner_theta;
	double	n_speed_h		 = *p_speed_h;
	double	n_speed_v		 = *p_speed_v;
	double  n_speed_h_temp;
	double  n_speed_v_temp; 
	double  n_speed_paddle   = *p_speed_paddle;

	if (flag == 9){
		if (n_speed_v > 0)
			n_speed_v = 0 - n_speed_v;
		printf("detect hit on paddle top\n");
	}
	else if (flag == 10 || flag == 11){
		n_speed_h_temp  = n_speed_h;
		n_speed_v_temp  = n_speed_v; 
		printf("detect hit on paddle side\n");
		printf("original speed_h is %f, original speed_v is %f\n", n_speed_h, n_speed_v);
		n_speed_h = 0.0-cos(2.0*n_corner_theta)*n_speed_h_temp-sin(2.0*n_corner_theta)*n_speed_v_temp;
		n_speed_v = 0.0-sin(2.0*n_corner_theta)*n_speed_h_temp+cos(2.0*n_corner_theta)*n_speed_v_temp;
		printf("hit on the corner\n angle is %f\n", n_corner_theta);
		printf("speed_h is %f, speed_v is %f\n", n_speed_h, n_speed_v);
	}

	*p_corner_theta = n_corner_theta;
	*p_speed_h	= n_speed_h;
	*p_speed_v	= n_speed_v;
}

int levelPass(int n_brick_status[7][10]){
	int a, b;
	int temp = 1; // pass the level if it returns 1
	for (a=0; a<7; a++)
		for (b=0; b<10; b++){
			if (n_brick_status[a][b] !=0){
				temp = 0;
				break;
			}
		}
	return temp;
}

void velocityConstrain(double *p_speed_h, double *p_speed_v, double constrainSpeedV){
	double n_speed_h = *p_speed_h;
	double n_speed_v = *p_speed_v;
	double n_speed = sqrt(square(n_speed_h)+square(n_speed_v));
	if (absoluteDouble(n_speed_v) < constrainSpeedV){
			if (n_speed_v < 0 && n_speed_h < 0 ){
				n_speed_v = 0 - constrainSpeedV;
				n_speed_h = 0 - sqrt(square(n_speed)-square(n_speed_v));
			}
			else if (n_speed_v < 0 && n_speed_h >= 0 ){
				n_speed_v = 0 - constrainSpeedV;
				n_speed_h = sqrt(square(n_speed)-square(n_speed_v));
			}
			else if (n_speed_v >= 0 && n_speed_h < 0 ){
				n_speed_v = constrainSpeedV;
				n_speed_h = 0 - sqrt(square(n_speed)-square(n_speed_v));
			}
			else{
				n_speed_v = constrainSpeedV;
				n_speed_h = sqrt(square(n_speed)-square(n_speed_v));
			}
	}
	*p_speed_h = n_speed_h;
	*p_speed_v = n_speed_v;

}



int main()
{
	vga_ball_arg_t	vla;
	int		err;
	double  corner_theta;
	int     brick_width = BRICK_W;
	int     brick_height = BRICK_H;
	int     ball_radius  = BALL_R;
	int     paddle_length= PADDLE_W;
	int     brick_h, brick_v;
	int     game_status;
	int 	flag[7][10];
	int     count = 0;

	int     flag_paddle = 0;
	int     level_reset = 1;

	// initialize


	speed_paddle= 0;
	ball_h		= 312;
	ball_v		= 440;
	speed_h		= 0.5;
	speed_v		= -0.2;
	h_location	= 275;
	game_status = 1;
	


	/* Open the keyboard */
	if ( (keyboard = openkeyboard( &endpoint_address ) ) == NULL )
	{
		fprintf( stderr, "Did not find a keyboard\n" );
		exit( 1 );
	}
	libusb_device **devs;          //pointer to pointer of device, used to retrieve a list of devices
	libusb_context *ctx = NULL;    //a libusb session
	int r;                         //for return values
	ssize_t cnt;                   //holding number of devices in list
    	r = libusb_init(&ctx);         //initialize a library session
    	if(r < 0) {
	printf("%s  %d\n", "Init Error", r); //there was an error
        return 1;
    	}
    	libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation
    	cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
	if(cnt < 0) {
		printf("%s\n", "Get Device Error"); //there was an error 
	}
	
	mouse = libusb_open_device_with_vid_pid(ctx, 16700, 12314); //open mouse
	if(mouse == NULL) {
			printf("%s\n", "Cannot open device");
	    	libusb_free_device_list(devs, 1); //free the list, unref the devices in it
	    	libusb_exit(ctx);                 //close the session
	    	return 0;
	} 
	else {
		printf("%s\n", "Device opened");
		libusb_free_device_list(devs, 1);                     //free the list, unref the devices in it
		if(libusb_kernel_driver_active(mouse, 0) == 1) { //find out if kernel driver is attached
			printf("%s\n", "Kernel Driver Active");
			if(libusb_detach_kernel_driver(mouse, 0) == 0) //detach it
				printf("%s\n", "Kernel Driver Detached!");
		}
		r = libusb_claim_interface(mouse, 0);            //claim interface 0 (the first) of device (mine had just 1)
		if(r < 0) {
			printf("%s\n", "Cannot Claim Interface");
			return 1;
		}
	}
	printf("%s\n", "Claimed Interface");

	pthread_create( &keyboard_thread, NULL, keyboard_thread_f, NULL );
	pthread_create( &mouse_thread, NULL, mouse_thread_f, NULL );
    
	// 0 bgm; 
	// 1 bgm + hit_wall
    // 2 bgm + hit_brick
	data.audio_choose	= 0 ; 


	
	// filename corresponding to vga_ball
	static const char filename[] = "/dev/vga_ball";


	if ( (vga_ball_fd = open( filename, O_RDWR ) ) == -1 ) /* opened some file */
	{
		fprintf( stderr, "could not open %s\n", filename );
		return(-1);
	}
	while(1){
		level_reset = 1;
		level =1;
		game_status = 1;
		lives = 3;
		finalstatus = 0 ;
		score = 0;



	// game start
	while ( game_status )
	{

		// choose level
		if (level_reset == 1){
				// default status of the bricks are 0
			for ( int i = 0; i < 7; i++ )
				for ( int j = 0; j < 10; j++ ){
					brick_status[i][j] = 0;
				}


			// the status of bricks can be initialized to generate different levels of game
			// Don't display any bricks in the first row
			for ( int i = 3; i <= 5; i++ )
				for ( int j = 2; j <= 7; j++ )
					brick_status[i][j] = 1;
			reset = 1;
			level_reset = 0;
		}
		
		if (level_reset == 2){
				// default status of the bricks are 0
			for ( int i = 0; i < 7; i++ )
				for ( int j = 0; j < 10; j++ ){
					brick_status[i][j] = 0;
				}

			for ( int i = 2; i <= 6 ; i++ )
				for ( int j = 1; j <= 8; j++ )
					brick_status[i][j] = 1;
			reset = 1;
			level_reset = 0;
		}

		// when player die or pass through a level, reset is set to 1
		if(reset){
		// if the player don't press on keyboard or mouse, the game doesn't start
			while (!game_start)
			{
				;
			}
			printf("RESET\n");
			speed_paddle= 0;
			ball_h		= 312;
			ball_v		= 440;
			// different level has different speed
			if (level == 1){

			   
			    srand( (unsigned)time( NULL ) );  
	       	    int seed=rand()%6;
	       	    double speed_h_range[6] = {0.4,-0.4,0.3,-0.3,0.2,-0.2};
	       	    double speed_v_range[6] = {0.2,-0.2,-0.33,-0.33,-0.4,-0.4};


				speed_h		= speed_h_range[seed];
				speed_v		= speed_v_range[seed];
			}
			else if (level == 2)
			{
			    srand( (unsigned)time( NULL ) );  
	       	    int seed=rand()%6;
	       	    double speed_h_range[6] = {0.4,-0.4,0.3,-0.3,0.2,-0.2};
	       	    double speed_v_range[6] = {0.2,-0.2,-0.33,-0.33,-0.4,-0.4};


				speed_h		= speed_h_range[seed]*1.2;
				speed_v		= speed_v_range[seed]*1.2;
			}
			
			h_location	= 275;
			game_status = 1;
			reset = 0;
		}

		/*
		 * set_alldata_color(&colors[i % COLORS ]);
		 * print_alldata_color();
		 */
		audio_choose = 0;
		count = 0;
		// if at corner, the paddle will not move at all
		// else the speed of paddle is set to a constant number

		// Don't display any bricks in the first row

		flag_paddle = 0;

		for ( int i = 0; i < 7; i++ )
			for ( int j = 0; j < 10; j++ )
				flag[i][j]=0;

		if (h_location + t_speed < 0)
   			h_location = 0;
  		else if (h_location + t_speed + PADDLE_W >= 639)
   			h_location = 639 - PADDLE_W;
  		else
   			h_location += t_speed; 

		// determine whether hit on the brick
		// i represents line
		// j represents column
		for ( int i = 0; i < 7; i++ )
			for ( int j = 0; j < 10; j++ )
				if (brick_status[i][j]==1){
					brick_h = brick_width*j;
					brick_v = brick_height*i;
					flag[i][j] = hitOnBrick(brick_width, brick_height, brick_h, brick_v, ball_radius, &ball_h, &ball_v, &corner_theta, &audio_choose);
					if (flag[i][j]!=0){
						score += (1-i%2) + 1;
						// printf("score = %d\n",score);
						// printf("score1 = %d\n",getscore1(score));
		    //             printf("score2 = %d\n",getscore2(score));
		    //             printf("score3 = %d\n",getscore3(score));
						count += 1;
					}
				}

		// if only one brick get hit				
		if (count == 1){
			for ( int i = 0; i < 7; i++ )
				for ( int j = 0; j < 10; j++ )
					changeVelocityAndBrickStatus(flag[i][j], &speed_h, &speed_v, &brick_status[i][j], &corner_theta);

		}
		// if more than 1 brick get hit, we don't use corner one
		else if (count > 1){
			for ( int i = 0; i < 7; i++ )
				for ( int j = 0; j < 10; j++ )
					if (flag[i][j]==1 || flag[i][j]==2 || flag[i][j]==3 || flag[i][j]==4)
						changeVelocityAndBrickStatus(flag[i][j], &speed_h, &speed_v, &brick_status[i][j], &corner_theta);
		}


		// refresh the score now
		// if one brick get hit, score +3, if 2 get hit in a single loop +9 and so on


		// determine whether hit on the left and right and top wall and change the velocity
		hitOnWall(&ball_h, &ball_v, &speed_h, &speed_v, &audio_choose);

		// determine whether paddle catches the ball and give the game status
		flag_paddle = hitOnPaddle(&ball_h, &ball_v, &speed_v, &audio_choose, &h_location, &speed_paddle, &game_status, &corner_theta);

		changeVelocityHitPaddle(flag_paddle, &speed_h, &speed_v, &speed_paddle, &corner_theta);
		
		// in case the situation a very small vertical velocity is generated.
		velocityConstrain(&speed_h, &speed_v, 0.02);

		ball_h += speed_h;
		ball_v += speed_v;



				// check whether level is finished
		if (levelPass(brick_status)){
			level += 1;
			game_start = 0;
			if(level > 2){
				finalstatus = 1;
				game_status = 0;
				printf("GAME FINISHED\n");
				data.gamestatus = finalstatus;
			}
			level_reset = level; 
		}

		/* //////////// WRITE DATA ////////////// */




		data.paddle_left	=(int) h_location;
		data.ball_h		    = (int) ball_h;
		data.ball_v		    = (int) ball_v;
		data.brick_status0	= convert2bin( brick_status[0] );
		data.brick_status1	= convert2bin( brick_status[1] );
		data.brick_status2	= convert2bin( brick_status[2] );
		data.brick_status3	= convert2bin( brick_status[3] );
		data.brick_status4	= convert2bin( brick_status[4] );
		data.brick_status5	= convert2bin( brick_status[5] );
		data.brick_status6	= convert2bin( brick_status[6] );
		data.audio_choose   = audio_choose;
		data.heart_status = lives2bin(lives);
		data.score1 = getscore1(score);
		data.score2 = getscore2(score);
		data.score3 = getscore3(score);
		data.gamestatus = finalstatus;

		set_alldata( &data );



		usleep( 1200 );
		if(game_status == 0){
			usleep(1200000);
			break;
		}
	}

 usleep(3000);
}

	/* Terminate the blink thread */
	pthread_cancel( keyboard_thread );
	pthread_cancel( mouse_thread );
	/* Wait for the network thread to finish */
	pthread_join( keyboard_thread, NULL );
	pthread_join( mouse_thread, NULL );
	return(0);
}

void *keyboard_thread_f( void *ignored )
{
	printf( "thread started\n" );

	vga_ball_arg_t vla;


	while ( 1 )
	{


		libusb_interrupt_transfer( keyboard, endpoint_address,
					   (unsigned char *) &packet, sizeof(packet),
					   &transferred, 0 );

		if ( transferred == sizeof(packet) ){
			sprintf( keystate, "%02x %02x %02x", packet.modifiers, packet.keycode[0],
				 packet.keycode[1] );


			if ( packet.keycode[0] == 0x50 )        /* LEFTARROW Pressed */

			{
				t_speed = -0.5;
				//printf( "LEFTARROW Pressed\n" );
			}
			else if ( packet.keycode[0] == 0x4f ){  /* RIGHTARROW Pressed */
				//printf( "RIGHTARROW Pressed\n" );
				t_speed = 0.5;
			}
			else if (packet.keycode[0] == 0x28 ){
				game_start = 1;
			}
			else{
				//printf( "else\n" );
				t_speed = 0;
			}
		}
		else{
			printf( "else\n" );
			t_speed = 0;
		}

	if (h_location + t_speed < 0)
		h_location = 0;
  	else if (h_location + t_speed + PADDLE_W >= 639)
   		h_location = 639 - PADDLE_W;
  	else
   		h_location += t_speed; 	

/* //////////// WRITE DATA ////////////// */
		
		data.audio_choose = audio_choose;
		data.paddle_left	= (int) h_location;
		data.ball_h		= (int) ball_h;
		data.ball_v		= (int) ball_v;
		data.brick_status0	= convert2bin( brick_status[0] );
		data.brick_status1	= convert2bin( brick_status[1] );
		data.brick_status2	= convert2bin( brick_status[2] );
		data.brick_status3	= convert2bin( brick_status[3] );
		data.brick_status4	= convert2bin( brick_status[4] );
		data.brick_status5	= convert2bin( brick_status[5] );
		data.brick_status6	= convert2bin( brick_status[6] );
		data.heart_status   = lives2bin(lives);
		data.score1 = getscore1(score);
		data.score2 = getscore2(score);
		data.score3 = getscore3(score);
		data.gamestatus = finalstatus;
		
		set_alldata( &data );

	}
}

void *mouse_thread_f( void *ignored )
{
	printf( "mouse thread started\n" );

	vga_ball_arg_t vla;


	while ( 1 )
	{


		libusb_interrupt_transfer( mouse, 0x81,
					   datain, 0x0004,
					   &size, 0 );
		printf( "transferred\n" );

		if ( datain[3] == 0x01 )        /* mouse */
		{
			t_speed = -0.5;

		}
		else if ( datain[3] == 0xff ){  /* mouse */
			t_speed = 0.5;
		}
		else{
			printf( "else\n" );
			t_speed = 0;
		}

		if ( datain[1] > 0 && datain[1] < 0x2f ){        /* mouse */
			t_speed = 0;
		}
		else if ( datain[1] > 0x30 && datain[1] < 0x5f ){  /* mouse */
			t_speed = 0.8;
		}
		else if ( datain[1] > 0x60 && datain[1] < 0x7f ){  /* mouse */
			t_speed = 1.8;
		}
		else if ( datain[1] > 0x80 && datain[1] < 0xaf ){  /* mouse */
			t_speed = -1.8;
		}
		else if ( datain[1] > 0xb0 && datain[1] < 0xcf ){  /* mouse */
			t_speed = -0.8;
		}
		else if ( datain[1] > 0xd0 && datain[1] < 0xff ){  /* mouse */
			t_speed = 0;
		}


		h_location += t_speed;
		/* //////////// WRITE DATA ////////////// */
		data.audio_choose = audio_choose;
		data.paddle_left	= (int) h_location;
		data.ball_h		= (int) ball_h;
		data.ball_v		= (int) ball_v;
		data.brick_status0	= convert2bin( brick_status[0] );
		data.brick_status1	= convert2bin( brick_status[1] );
		data.brick_status2	= convert2bin( brick_status[2] );
		data.brick_status3	= convert2bin( brick_status[3] );
		data.brick_status4	= convert2bin( brick_status[4] );
		data.brick_status5	= convert2bin( brick_status[5] );
		data.brick_status6	= convert2bin( brick_status[6] );
		data.score1 = getscore1(score);
		data.score2 = getscore2(score);
		data.score3 = getscore3(score);
		data.gamestatus = finalstatus;

		set_alldata( &data );
	}
}


