/*
 * Userspace program that communicates with the led_vga device driver
 * primarily through ioctls
 *
 * ChengXue Qian 
 * XiaoWen Han
 * Hao Jin
 * MuQing Liu
 * Columbia University
 */

#include <stdlib.h>
#include <stdio.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 <math.h>

#include "usbmouse.h"



struct libusb_device_handle *mouse;
uint8_t endpoint_address;
int vga_led_fd;

int mouse_y=0;    //to calculate mouse displacement



int CtrlP[17]={17};
int score=0;
int dis=0;
int simple=20;
int start=16;
int hcnt=0;
int vcnt=0;
float startTemp=16;
int startTemp0=0;
int change=0;
int mode=0;
int example=1;

float base0[10]={0.6944,	0.4879,	0.3270,	0.2061,	0.1193,	0.0612,	0.0258,	0.0077,	0.0010,	0.0000};  //base function ///coefficient*scale
float base1[10]={2.7778,	2.7293,	2.5953,	2.3927,	2.1388,	1.8505,	1.5451,	1.2395,	0.9510,	0.6965};  //base function coefficient*scale
float base2[10]={0.6944,	0.9485,	1.2368,	1.5423,	1.8478,	2.1363,	2.3906,	2.5937,	2.7284,	2.7778};
float base3[10]={0.0000,	0.0009,	0.0086,	0.0257,	0.0608,	0.1188,	0.2052,	0.3258,	0.4863,	0.6923};

int min(int a, int b)
{
  if (a<=b)return a;
  else return b;
}

int poww(int a)
{
  if(a==0) return 1;
  else return -1;
}

struct coordinate
{
  int a[140];
}y;

struct coordinate getY()
{

  int i=0;
  int j=0;
  float y0[140]={17};
  int index;
    for(i=0; i<14; i++){
      for(j=0;j<10;j++){

	index=10*i+j;   
	y0[index]=base0[j]*CtrlP[i]+base1[j]*CtrlP[i+1]+base2[j]*CtrlP[i+2]+base3[j]*CtrlP[i+3];
	  if (y0[index]-(int)y0[index]>=0.5){
	    y.a[index]=y0[index]+1;
	      }
	  else{
	    y.a[index]=y0[index];
	      }
          
         }
    }
    return y;
 }
////////updata CtrlP and the modifeid ellipse according to the change of CtrlP
struct coordinate changeY()  //change=0:nochange change=1:increase radius by2 change=2:decrease radius by2  start=position_changed start=0,1,2,...,16
{
  if(change!=1&&change!=2)
    {
    }else if (change==1&&CtrlP[start]>18){
  }else if (change==2&&CtrlP[start]< 3){
  }else{
    float y0[140]={17};
    int i=0;
    int j=0;
      if(change==1&&CtrlP[start]<19){CtrlP[start]+=2;}
      if(change==2&&CtrlP[start]> 2){CtrlP[start]-=2;}
      int index;
      int end=start-4;
      startTemp0=min(13,start);
      for(i=startTemp0; i>=0&&i>end; i--){
	for(j=0;j<10;j++){
	  index=10*i+j;
	  y0[index]=base0[j]*CtrlP[i]+base1[j]*CtrlP[i+1]+base2[j]*CtrlP[i+2]+base3[j]*CtrlP[i+3];
             if (y0[index]-(int)y0[index]>=0.5){
	       y.a[index]=y0[index]+1;
		 }else{
	       y.a[index]=y0[index];
		 }
          
     }
    }
    }
    return y;
      }
/* 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;
    }
  
  }

}

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



int main()
{
  struct usb_mouse_packet packet;
  int transferred;
  char keystate[6];
  unsigned char message0[20][8]={0};
  unsigned char message[11]={0};


  mouse=openmouse(&endpoint_address);

  int clear_key = 1;



  vga_led_arg_t vla;

  static const char filename[] = "/dev/vga_led";// the driver.c


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

 ;
  print_segment_info();

  write_segments(message);


  print_segment_info();


  

  int seed=4;
  int rad=20;
  int i;
  int j;
  int k;
  int mes_1;
  int mes_2;
  int index;


     srand(seed);
     for (i=3;i<17;i++){
         CtrlP[i]=rand()%rad+1;
     }
     y=getY();

    CtrlP[0]=17;
    CtrlP[1]=8;
    CtrlP[2]=5;

while(1){
    libusb_interrupt_transfer(mouse, endpoint_address,(unsigned char *) &packet, 
			sizeof(packet),&transferred, 0);

     
     change=0;

     if(packet.various_func==1){change=1;}
     if(packet.various_func==2){change=2;}
     
     if(mode==0){
          if(example==1 && packet.add0==0x01){example=4;}
     else if(example==1 && packet.add0==0xff){example=2;}
     else if(example==2 && packet.add0==0x01){example=1;}	
     else if(example==2 && packet.add0==0xff){example=3;}
     else if(example==3 && packet.add0==0x01){example=2;}
     else if(example==3 && packet.add0==0xff){example=4;}
     else if(example==4 && packet.add0==0x01){example=3;}
     else if(example==4 && packet.add0==0xff){example=1;}
	}
   

     
    mouse_y=(128-abs(128-packet.Y_displacement));
;
     if(mouse_y>=3)start=start+poww((packet.Y_displacement & 0x80)>>7);
     if(start<3){start=3;}
     if(start>16){start=16;}
   

     y=changeY();

     startTemp0=min(start,13);
     vcnt=10+2*startTemp0;   //scale down 10 times
     hcnt=y.a[10*startTemp0+1];  ///no center offset 320

   
     if(mode==0 && packet.various_func==4){mode=1;}
     

     score=0;
     dis=0;
    
     if(mode==1 && packet.various_func==4){

     if(example==1){    //simple
     dis=abs(CtrlP[3]-simple)+abs(CtrlP[4]-simple)+abs(CtrlP[5]-simple)+abs(CtrlP[6]-simple)+abs(CtrlP[7]-simple)+abs(CtrlP[8]-simple)+abs(CtrlP[9]-simple)+abs(CtrlP[10]-simple)+abs(CtrlP[11]-simple)+abs(CtrlP[12]-simple)+abs(CtrlP[13]-simple)+abs(CtrlP[14]-simple)+abs(CtrlP[15]-simple)+abs(CtrlP[16]-simple);
     printf("(should less than 10) dis is %d  \n",dis);
     if (dis<10)score=1;
     else score=2;}

     if(example==2){      //middle
     dis=abs(CtrlP[16]-CtrlP[15])+abs(CtrlP[15]-CtrlP[14])+abs(CtrlP[14]-CtrlP[13])+abs(CtrlP[13]-CtrlP[12])+abs(CtrlP[12]-CtrlP[11])+abs(CtrlP[11]-CtrlP[10])+abs(CtrlP[10]/CtrlP[9]-0.8)+abs(CtrlP[9]/CtrlP[8]-0.8)+abs(CtrlP[8]/CtrlP[7]-0.8)+abs(CtrlP[7]/CtrlP[6]-1)+abs(CtrlP[6]/CtrlP[5]-1)+abs(CtrlP[5]/CtrlP[4]-1.2)+abs(CtrlP[4]/CtrlP[3]-1.3);
     printf("(should less than 15)dis is %d  \n",dis);
     if (dis<15)score=1;
     else score=2;}

     if(example==3){       //hard
     dis=abs(y.a[140]/y.a[130]-1.15)+abs(y.a[130]/y.a[120]-1.08)+abs(y.a[120]/y.a[110]-0.96)+abs(y.a[110]/y.a[100]-0.79)+abs(y.a[100]/y.a[90]-0.66)+abs(y.a[90]/y.a[80]-1.04)+abs(y.a[80]/y.a[70]-1.45)+abs(y.a[70]/y.a[60]-0.92)+abs(y.a[60]/y.a[50]-0.72)+abs(y.a[50]/y.a[40]-2.17)+abs(y.a[40]/y.a[30]-0.74)+abs(y.a[30]/y.a[20]-0.94);
     printf("(should less than 6) dis is %d  \n",dis);
     if (dis<3)score=1;
     else score=2;}
     }

  index=0;


  for (mes_1=0;mes_1<20;mes_1++){
    for (mes_2=0;mes_2<8;mes_2++){
        if(mes_2==0){
            message0[mes_1][mes_2]=mes_1;
	   
        }else{
            message0[mes_1][mes_2]=y.a[index];
            index=index+1;
    
        }
    }
  }


  print_segment_info();

  for(j=0;j<20;j++){

      for(k=0;k<8;k++){
          message[k]=message0[j][k];
      }
 
  
  message[8]=hcnt;
  message[9]=vcnt;
  message[10]=mode;
  message[11]=example;
  message[12]=score;

  write_segments(message);
  
  }

 if (mode==1){
 if (score==1||packet.add0){
  if(score)usleep(5000000);
  else     usleep(500000);
  mode=0;
  for (i=3;i<17;i++){
         CtrlP[i]=rand()%rad+1;
     }
     y=getY();

    CtrlP[0]=17;
    CtrlP[1]=8;
    CtrlP[2]=5;
} 
}


  }
 
 

return 0;
}
