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

//########################################  GEORGIOS CHARITOS (gc2662) AND ADITYA BAGRI (aab2234) ####################################################

#include <stdio.h>
#include <stdlib.h>   
#include "vga_led.h"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "usbkeyboard.h"
#include <time.h>
 
int vga_led_fd; 
int timer=0;
int level=1;
////LIBUSB DECLARATIONS
struct usb_keyboard_packet packet;
int transferred;
char keystate[12];

///TIME DECLARATIONS
unsigned int x_hours=0;
unsigned int x_minutes=0;
unsigned int x_seconds=0;
unsigned int x_milliseconds=0;
unsigned int totaltime=0,count_down_time_in_secs=60,time_left=0;
 

struct libusb_device_handle *keyboard; 
uint8_t endpoint_address;              
//unsigned char endpoint_address;

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

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

/* Write the contents of the array to the display */
void write_segments(unsigned int segs[2])
{
  vga_led_arg_t vla;
  int i;
  for (i = 0 ; i < VGA_LED_DIGITS ; i++) {
    vla.digit = i;
    vla.segments = segs[i];
    //ioctl(vga_led_fd, VGA_LED_WRITE_DIGIT, &vla);
    if (ioctl(vga_led_fd, VGA_LED_WRITE_DIGIT, &vla)) {
      //perror("ioctl(VGA_LED_WRITE_DIGIT) failed");
      return;
    }
  }
}




///Time Thread
pthread_t time_thread;
void *time_thread_f(void *ignored)
{ clock_t x_startTime,x_countTime;
    
   
   x_startTime=clock();  // start clock
   time_left=count_down_time_in_secs-x_seconds;   // update timer
   
   while (time_left>=0) 
	{
		x_countTime=clock(); // update timer difference
		x_milliseconds=x_countTime-x_startTime;
		//x_seconds=(x_milliseconds/(CLOCKS_PER_SEC))-(x_minutes*60);
		//x_minutes=(x_milliseconds/(CLOCKS_PER_SEC))/60;
		x_seconds=((x_milliseconds)/2026000)-(x_minutes*60);
		x_minutes=(((x_milliseconds)/2026000)/60);
		x_hours=x_minutes/60;
 

	 
 
		time_left=count_down_time_in_secs-x_seconds; // subtract to get difference 
                if (time_left==0) {
			time_left=60; 
			level++;
		}		 
 
		//printf( "\nYou have %d seconds left ( %d ) count down timer by TopCoder",time_left,count_down_time_in_secs);
	}
 

	//printf( "\n\n\nTime's out\n\n\n"); 
    
  }

///Keyboard Thread

pthread_t keyboard_thread;
void *keyboard_thread_f(void *ignored)
{  
   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]);                                                                        
      printf("%s\n", keystate);}*/  
	}
    
  }

/////////
int main()
{
  int c0 = 1, c2 = 1; //Counters used for incrementing and decrementing the x,y coordinates of the ball
  vga_led_arg_t vla;
  int score=0; //score for the game
  int i,flag1=0,flag2=0,flag3=0,flag_level=1;
  int mole1,mole2,mole3; //moles
  static const char filename[] = "/dev/vga_led";

  static unsigned int message[8] = { 0x00, 0x00
, 0x00, 0x00,           // Initialize position of the ball to upper left corner just like in the driver
				      0x00, 0x00, 0x00, 0x00 };

  
  //char keystate[12];                                                     //lab2
  
  /* Open the keyboard */                                                //lab2
  if ( (keyboard = openkeyboard(&endpoint_address)) == NULL ) {          //lab2
    fprintf(stderr, "Did not find a keyboard\n");                        //lab2
    exit(1);                                                             //lab2
  }                                                                      //lab2

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

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

  //printf("initial state: ");
  //print_segment_info();


 
  /* Start the time thread */
 pthread_create(&time_thread, NULL, time_thread_f, NULL);



 /* Start the keyboard thread */
 pthread_create(&keyboard_thread, NULL, keyboard_thread_f, NULL);
 


for(;;) {

    message[4]=time_left;
    
    if (flag_level!=level){   
         flag_level=level;
	 usleep(1500000);
    }

    if(level==2) message[2]=1;
    message[5]=level;

    if ((x_seconds%3==0)&(flag1!=x_seconds)){
    flag1=x_seconds;
    mole1 = rand() % 10;
    if ((mole1==mole2) | (mole1==mole3)) mole1=0;
    mole2=0;
    }
    if (((x_seconds-1)%3==0)&(flag2!=x_seconds-1)){
    flag2=x_seconds-1;
    mole2 = rand() % 10;
    if ((mole2==mole1) | (mole2==mole3)) mole2=0;
    mole3=0;
    }
    if (((x_seconds-2)%3==0)&(flag3!=x_seconds-2)){
    flag3=x_seconds-2;
    mole3 = rand() % 10;
    if ((mole3==mole1) | (mole3==mole2)) mole3=0;
    mole1=0;
    }
    
    //printf("Mole positions are:MOLE1:%d MOLE2:%d MOLE3:%d\n",mole1,mole2,mole3);
    message[0] = ((mole2<<4) | mole1);
    message[1] = (message[1] & 0xf0);
    message[1] = (message[1] | mole3);
    
      switch (packet.keycode[0]){
	default:{   //printf("The packet.keycode[0] is:%d\n",packet.keycode[0]);
		    message[1] = (message[1] & 0x0f);	
		    message[1] = (message[1] | mole3);
		    write_segments(message);
		break;}
	case 0x1e:{ 
		    message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x10);	
		    write_segments(message);
		   usleep(150000);
                    if ((mole1==1) | (mole2==1) | (mole3==1)){
			score++;
                        message[3]=score;
		    	if (mole1==1) mole1=0;
		        if (mole2==1) mole2=0;
			if (mole3==1) mole3=0;
		    }		
		    break;}
	case 0x1f:{ 
                    message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x20);	
		    write_segments(message);
		   usleep(150000);
		   if ((mole1==2) | (mole2==2) | (mole3==2)){
			score++;
	                message[3]=score;
		    	if (mole1==2) mole1=0;
		        if (mole2==2) mole2=0;
			if (mole3==2) mole3=0;
		    }		
		    break;}
	case 0x20:{message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x30);	
		    write_segments(message);
		   usleep(150000);
		   if ((mole1==3) | (mole2==3) | (mole3==3)){
			score++;
                        message[3]=score;
		    	if (mole1==3) mole1=0;
		        if (mole2==3) mole2=0;
			if (mole3==3) mole3=0;
		    }		
		    break;}
	case 0x21:{ message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x40);	
		    write_segments(message);
		   usleep(150000);
		   if ((mole1==4) | (mole2==4) | (mole3==4)){
			score++;
                        message[3]=score;
		    	if (mole1==4) mole1=0;
		        if (mole2==4) mole2=0;
			if (mole3==4) mole3=0;
		    }		
		    break;}
	case 0x22:{ message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x50);	
		    write_segments(message);
		   usleep(150000);
		   if ((mole1==5) | (mole2==5) | (mole3==5)){
			score++;
                        message[3]=score;
		    	if (mole1==5) mole1=0;
		        if (mole2==5) mole2=0;
			if (mole3==5) mole3=0;
		    }		
		    break;}
	case 0x23:{ message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x60);	
		    write_segments(message);
		   usleep(150000);
		   if ((mole1==6) | (mole2==6) | (mole3==6)){
			score++;
                        message[3]=score;
		    	if (mole1==6) mole1=0;
		        if (mole2==6) mole2=0;
			if (mole3==6) mole3=0;
		    }		
		    break;}
	case 0x24:{ message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x70);	
		    write_segments(message);
		   usleep(150000);
		   if ((mole1==7) | (mole2==7) | (mole3==7)){
			score++;
                        message[3]=score;
		    	if (mole1==7) mole1=0;
		        if (mole2==7) mole2=0;
			if (mole3==7) mole3=0;
		    }		
		    break;}
	case 0x25:{ message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x80);	
		    write_segments(message);
		   usleep(150000);
		   if ((mole1==8) | (mole2==8) | (mole3==8)){
			score++;
                        message[3]=score;
		    	if (mole1==8) mole1=0;
		        if (mole2==8) mole2=0;
			if (mole3==8) mole3=0;
		    }		
		    break;}
	case 0x26:{ message[1] = (message[1] & 0x0f);
		    message[1] = (message[1] | 0x90);	
		    write_segments(message);
		   usleep(150000);
		   if ((mole1==9) | (mole2==9) | (mole3==9)){
			score++;
                        message[3]=score;
		    	if (mole1==9) mole1=0;
		        if (mole2==9) mole2=0;
			if (mole3==9) mole3=0;
		    }		
		    break;}
	}

                         
 }

///LAB3 CODE FOR THE BALL...WE KEEP IT BECAUSE WE WORKED FOR IT
    /*while (1) {                                                          //Add c0 counter(initialized as 1) to message[0](x coordinate) and c2 counter to  
	message[0] = message[0]+c0;                                      //message[2] (y coordinate).message[1] and message[3] represent the MSD hex digit  
	message[1] = message[0]>>8;                                      // of the x and y coordinates respectively so they are shifted by 8 bits
	message[2] = message[2]+c2;                                      
	message[3] = message[2]>>8;                                      //Boundary conditions on the screen:
	if ((message[0] == 0x63) && (message[1] == 0x00))                //If left boundary is hit then increment x
    	c0 = 1;
	else if ((message[0] == 0x21D) &&(message[1] == 0X02))           //If right boundary is hit then decrement x
	c0 = (-1);
	if ((message[2] == 0x63) && (message[3] == 0x00))              	 //If top boundary is hit then increment y
	c2 = (1);
	else if ((message[2] == 0x17D) && (message[3] == 0x01))          //If bottom boundary is hit then decrement y
	c2 = (-1);
	write_segments(message);
	printf("current state x=%02x %02x, y=%02x %02x \n \n \n", message[1], message[0], message[3], message[2]);    //print coordinates on the screen
    	usleep(10000);                   //For controlling the speed of Ball Movement
  	}*/
  
  /* Terminate the keyboard thread */
  pthread_cancel(keyboard_thread);

  /* Terminate the time thread */
  pthread_cancel(time_thread);

  /* Wait for the keyboard thread to finish */
  pthread_join(keyboard_thread, NULL);

  /* Wait for the time thread to finish */
  pthread_join(time_thread, NULL);

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

  return 0;
}
