/*
 * Userspace program that communicates with the led_vga device driver
 * primarily through ioctls
 *
 * Stephen A. Edwards
 * Columbia University
 */

#include <stdio.h>
#include "vga_led.h"
#include "wiicontroller.h"
#include "wiimote.h"
#include "wiimote_api.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 <sndfile.h>
#include <stdbool.h>
#include <pthread.h>

pthread_t paddle_thread;
void *paddle_thread_f(void*);
pthread_mutex_t lock;
int vga_ball_fd;
unsigned int ppx;

/* Read and print the segment values */
void print_segment_info() {
  vga_ball_arg_t vla;
  int i;

  for (i = 0 ; i < VGA_LED_DIGITS ; i++) {
    vla.digit = i;
    if (ioctl(vga_ball_fd, VGA_LED_READ_DIGIT, &vla)) {
      perror("ioctl(VGA_LED_READ_DIGIT) failed");
      return;
    }
    printf("%02x ", vla.segments);
  }
  printf("\n");
}

/* Write the contents of the array to the display */
void write_segments(const unsigned char segs[8])
{
  vga_ball_arg_t vla;
  int i;
  for (i = 0 ; i < VGA_LED_DIGITS ; i++) {
    vla.digit = i;
    vla.segments = segs[i];
    if (ioctl(vga_ball_fd, VGA_LED_WRITE_DIGIT, &vla)) {
      perror("ioctl(VGA_LED_WRITE_DIGIT) failed");
      return;
    }
  }
}
void write_coords(unsigned int x, unsigned int y) {
circle_center cc;
cc.x = x;
cc.y = y;
if(ioctl(vga_ball_fd, VGA_LED_WRITE_CENTER, &cc)) {
perror("ioctl(VGA_LED_WRITE_CENTER) failed");
return;
}
}

void write_pad(unsigned int x) {

if (x < 0 || x > 700) return;
if(x>=512)
	x = 512;
ppx=512-x;
//printf("write_pad...\n");
if(ioctl(vga_ball_fd, VGA_LED_WRITE_PAD, &ppx)) {
perror("ioctl(VGA_LED_WRITE_PAD) failed");

return;
}
}

void write_score(unsigned int x) {
int score = x;
//printf("write_pad...\n");
if(ioctl(vga_ball_fd, VGA_LED_WRITE_SCORE, &score)) {
perror("ioctl(VGA_LED_WRITE_SCORE) failed");
return;
}
}

void write_life(unsigned int x) {
int life = x;
//printf("write_pad...\n");
if(ioctl(vga_ball_fd, VGA_LED_WRITE_LIFE, &life)) {
perror("ioctl(VGA_LED_WRITE_LIFE) failed");
return;
}
}

void write_on(unsigned int x) {
unsigned int on = x;
if(ioctl(vga_ball_fd, VGA_LED_WRITE_ON, &on)) {
perror("ioctl(VGA_LED_WRITE_ON) failed");
return;
}
}

void write_audio(short x) {
int audio = x;
if(ioctl(vga_ball_fd, VGA_LED_WRITE_AUDIO, &audio)) {
perror("ioctl(VGA_LED_WRITE_AUDIO) failed");
return;
}
}

void write_over(int x) {
int over = x;
if(ioctl(vga_ball_fd, VGA_LED_WRITE_OVER, &over)) {
perror("ioctl(VGA_LED_WRITE_OVER) failed");
return;
}
}

int bounce_columbia(int row, int col, int x, int y, int dx, int dy){
	if((y==(row+1)*32-16 || y==(row+2)*32+16)&& x>=col*128 && x<=(1+col)*128)
		return 1;
	else if((x==col*128-16 || x==(col+1)*128+16) && y>=(row+1)*32 && y<= (row+2)*32)
		return 2;
	else if((((row+1)*32-y)*((row+1)*32-y))+(col*128-x)*(col*128-x)>=16*16 && dx==1 && dy==1)
		return 3;
	else if((((row+1)*32-y)*((row+1)*32-y))+((col+1)*128-x)*((col+1)*128-x)>=16*16 && dx==-1 && dy==1)
		return 3;
	else if((((row+2)*32-y)*((row+2)*32-y))+(col*128-x)*(col*128-x)>=16*16 && dx==1 && dy==-1)
		return 3;
	else if((((row+2)*32-y)*((row+2)*32-y))+((col+1)*128-x)*((col+1)*128-x)>=16*16 && dx==-1 && dy==-1)
		return 3;
	else return 0;
	
}
int main()
{
  vga_ball_arg_t vla;

  if(pthread_mutex_init(&lock,NULL)!=0)
 {
	printf("mutex init failed\n");
	return 1;
  }
  int i;
  static const char filename[] = "/dev/vga_ball";

  static unsigned char message[8] = { 0x39, 0x6D, 0x79, 0x79,
				      0x66, 0x7F, 0x66, 0x3F };

  printf("VGA LED Userspace program started\n");

  if ( (vga_ball_fd = open(filename, O_RDWR)) == -1) {
    fprintf(stderr, "could not open %s\n", filename);
    return -1;
  }

  printf("initial state: ");
  int x = 320;
  int y = 240;
  int dx = -1;
  int dy = -1;
  unsigned int on = 0xffffffff;
  write_on(on);
  printf("on is %d\n", on);
  int over = 0;
  write_over(over);


  int score = 0;
  printf("score is %d\n", score);
  write_score(score);
  int life = 9;
  write_life(life);

  	

//read wave file --------------------------
SNDFILE *sf;
SF_INFO info;
int num_channels;
int num, num_items;
short *buf;
int f,sr, c;
int k, j;
FILE *out;
info.format = 0;
sf = sf_open("QQ.wav", SFM_READ, &info);
if(sf == NULL) {
	printf("Failed to open file\n");
	exit(-1);
	}
f= info.frames;
sr = info.samplerate;
c= info.channels;
printf("frames is %d\n",f);
printf("samplerate is %d\n",sr);
printf("channels is %d\n",c);
num_items=f*c;
printf("num_items is is %d\n",num_items);

//allocate space for data
buf = (short* ) malloc(num_items*sizeof(short));
num = sf_read_short(sf,buf,num_items);
sf_close(sf);
printf("read %d items\n",num);

//write data to filedata.out
out = fopen("filedata.out","w");



pthread_create(&paddle_thread, NULL, paddle_thread_f, NULL);

sleep(10);
//fclose(out);
k=0;
 while(1) {
	

	write_audio(buf[k]);
	printf("buf is %d\n",buf[k]);
	fprintf(out, "%d ", buf[k]);
	fprintf(out, "\n");
	if(k<num)
		k=k+c;

 
x += dx;
y += dy;



write_coords(x, y);
write_on(on);


if(x == 15|| x==640-16)
dx = -dx;

bool bounced=(y == 15) || (y == 480-32-32-16 && x>=(ppx) && x<=((ppx)+128));

//printf("px is %d x y %d %d\n", ppx,x,y);
if(bounced) {
//printf("px is %d x y %d %d\n", ppx,x,y);
dy = -dy;
}

//on = ~on;
int row, col,num;
num = 0;
for(row=0;row<=4;row++) {
	for(col=0;col<=4;col++) {
		
	 if((on>>num)&1 == 1 && (y>=(row+1)*32-16 && y<=(row+2)*32+16)&& x>=col*128 && x<=(1+col)*128) {
			if(bounce_columbia(row,col,x,y,dx,dy)==1 && (num==9 || num==18 ||num==12)) {
				dy = -dy;
				printf("columibia bounced y dx %d dy%d\n",dx,dy);
			}
			else if(bounce_columbia(row,col,x,y,dx,dy)==3 &&(num==9 || num ==12 || num == 18)) {
				dy=-dy;
				printf("columibia bounced x y dx %d dy%d\n",dx,dy);
			}
			else if(num!=9&&num!=12&&num!=18) {
			unsigned int mask = ~(1<<num);
			
			on = on&mask;
			
//			write_on(on);
			printf("on&(1<<num)==1<<num? %d\n",(on>>num)&1);
			printf("row is %d col is %d on&num is %d\n",row,col,on&(1<<num));
			score++;
			printf("score is %d\n",score);
			write_score(score);
			dy = -dy;
//			write_coords(x, y);
			}
			}
	 if((on>>num)&1==1 && (x>=col*128-16 && x<=(col+1)*128+16) && y>=(row+1)*32 && y<= (row+2)*32) {
			if(bounce_columbia(row,col,x,y,dx,dy)==2 &&(num==9 || num ==12 || num == 18)) {
				dx= -dx;
				printf("columibia bounced x dx %d dy%d\n",dx,dy);
			}
			else if(bounce_columbia(row,col,x,y,dx,dy)==3 &&(num==9 || num ==12 || num == 18)) {
				dx= -dx;
				printf("columibia bounced x y dx %d dy%d\n",dx,dy);
			}
			else if(num!=9&&num!=12&&num!=18) {
			unsigned int mask = ~(1<<num);
		
			on = on&mask;
			
//			write_on(on);
			printf("row is %d col is %d on&num is%d\n", row, col, on&(1<<num));
			score++;
			printf("score is %d\n", score);
			write_score(score);
			dx = -dx;
//			write_coords(x, y);
			}
			}
			num++;
	}
}

if(y>480-32-32-10 && (x<(ppx)||x>(ppx)+128)) {
	life--;
	write_life(life);
	score = 0;
	write_score(score);
	on = 0xffffffff;
	write_on(on);
	x= 320;
	y= 240;
	write_coords(x,y);
	if(life==0) {
		over = 1;
		write_over(over);
		printf("game over\n");
		return;
	}
	sleep(10);
	
	
}

 if(life == 2 && on==0xfe028200)
 usleep(5000);
else if(life == 1&& on==0xfe028200)
 usleep(3000);
else
 usleep(7000); 
}
//wii_disconnect(wii);
//fclose(out);
//  pthread_cancel(paddle_thread);

  /* Wait for the network thread to finish */
//  pthread_join(paddle_thread, NULL);

  printf("current state: ");

  printf("VGA LED Userspace program terminating\n");
  return 0;
}

void *paddle_thread_f(void *ignored)
{
 
  unsigned int py;
  unsigned int px;


  wiimote_t wii;

  wii = wii_connect();
  while(1) {
pthread_mutex_lock(&lock);
  wii_getpos(&wii, &px, &py);
  printf("wii px is %d\n",px);
 
//  if(px>=0 && px<=640-128)
//	write_pad(512 - px);
  write_pad(px);

  usleep(7000);
  pthread_mutex_unlock(&lock);
  }

  return NULL;
}
