#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "vga_led.h"
#include "usbkeyboard.h"
#include "hello.h"
#include <stdbool.h>


struct libusb_device_handle *keyboard;
uint8_t endpoint_address;
int vga_led_fd;
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("%02x ", vla.segments);
    }
    printf("\n");
}

/* Write the contents of the array to the display */
void write_segments(const int segs[SEGMENTS])
{
    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_keyboard_packet packet;
    int transferred;
    char keystate[12];
    if ( (keyboard = openkeyboard(&endpoint_address)) == NULL )
    {
        fprintf(stderr, "Did not find a keyboard\n");
        exit(1);
  	}
    
    vga_led_arg_t vla;
    static const char filename[] = "/dev/vga_led";
    static int data[SEGMENTS] = {
        300, 200, 1,	//chara x0-0 y0-1 f0-2
        500,200,0,	//bullet1 x1-3 y1-4 f1-5
        500,300,0,		//bullet2 x2-6 y2-7 f2-8
        500,400,0,	//bullet3 x3-9 y3-10 f3-11
        500,300,0,1,	//enemy1 x4-12 y4-13 f4-14 id4-15
        100,300,0,2,	//enemy2 x5-16 y5-17 f5-18 id5-19
        400,300,0,2,	//enemy3 x6-20 y6-21 f6-22 id6-23
        0,		//floor	x7-24
        0,		//brick x8-25
        100,400,0,		//explosion1 x9-26 y9-27 f9-28
        300,400,0,		//explosion2 x10-29 y10-30 f10-31
        500,400,0,		//exlposion3 x11-32 y11-33 f11-34
        300,100,0,
        0,0,0,
        1,
        1,
		0   //flag_shoot_mu
    };
    printf("VGA axis 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();
    //write the initial value to the register
    write_segments(data);
    printf("current state: ");
    print_segment_info();
    
    int i,j;
    int t_up, t_down;
    int x_move, y_move;
    struct item Chara;
    struct item Air;
    struct item Bullet[3];
    struct item Enemy[3];
    struct item Explosion[3];
    
    int Brick_x = data[25];
    //state
    bool start = false;
    bool dead = false;
    
    int num_shoot;
    int num_bullet;
    int num_enemy;
    int count;
    int count_gen_enemy;
    int count_dead_enemy;
    int count_dead;
    int count_collision[3]={0,0,0};
    int count_fell;
    int count_shoot;
    
    int enemyId[3];
    int enemyID;
    int generate;
    
    //flags
    bool flag_press; //press any key to start
    bool flag_shoot;
    bool flag_shoot_mu;
    bool flag_air_left;
    bool flag_air_straight;
    bool flag_air_right;
    bool flag_gameover=false;
    
    init(Chara);
    init(Air);
    init(Bullet[0]);
    init(Bullet[1]);
    init(Bullet[2]);
    init(Enemy[0]);
    init(Enemy[1]);
    init(Enemy[2]);
    init(Explosion[0]);
    init(Explosion[1]);
    init(Explosion[2]);
    while (1)
    {
        libusb_interrupt_transfer(keyboard, endpoint_address,(unsigned char *)&packet,sizeof(packet),&transferred, 1);
        if (transferred == 6)
        {
            x_move = packet.leftright;
            y_move = packet.button;
            sprintf(keystate, "%02x %02x %02x", packet.leftright,packet.updown, packet.button);
            printf("%s\n", keystate);
        }
        
        if (!start)
		{
			dead = false;
			Chara.x = 300;
			Chara.y = 200;
            
            if (flag_press == true)
                flag_press = false;
            else
                flag_press = true;
            
			if(Brick_x > 0)
                Brick_x--;
			else
	   			Brick_x = 40;
            
			if (Chara.flag < 6)
				Chara.flag++;
			else
				Chara.flag = 1;
            
			if (packet.button)
			{
				start = true;
				Chara.flag = 1;
                                flag_press = false;
			}
            
			write_segments(data);
			usleep(100000);
		}
        
        if (start)
        {
            if (!dead)
            {
                if (flag_shoot==false && count==6)
                {
                    if (Chara.flag < 4)
                        Chara.flag++;
                    else
                        Chara.flag = 1;
                }
                
                if(x_move > LEFT_MIN && x_move < LEFT_MAX && Chara.x > 0)//left ef--7f
                {
            		Chara.x = Chara.x - 2;//x1
                }
                if(x_move > RIGHT_MIN && x_move < RIGHT_MAX && Chara.x < 570)//right 80--10
                {
            		Chara.x = Chara.x + 2;//x1
                }
                
                if((y_move == BUTTON_UP || y_move == BUTTON_BOTH) && Chara.y > 0)
                {
            		t_down = 0;
            		if ((Chara.y - ACC*t_up*t_up - 0.5*t_up)>0)
            		{
                		Chara.y = Chara.y - ACC*t_up*t_up-0.5*t_up;
            		}
            		else
                		Chara.y = 0;
            		t_up++;
                }
                if(y_move != BUTTON_UP && y_move != BUTTON_BOTH && Chara.y < 410)
                {
            		t_up = 0;
            		if(Chara.y + ACC*t_down*t_down+0.5*t_down < 410)
                		Chara.y = Chara.y + ACC*t_down*t_down+0.5*t_down;
            		else
                        Chara.y = 410;
            		t_down++;
                }
                //air movement
                if (x_move > LEFT_MIN && x_move < LEFT_MAX &&(y_move == BUTTON_UP || y_move == BUTTON_BOTH))	//left
                {
                    flag_air_right = true;
                    //flag_air_straight = true;
                    if(flag_air_left == true)
                        Air.flag = 1;
                    Air.x = Chara.x + 5;
                    
                	if (count == 6)
                    {
                        flag_air_left = false;
                        if(Air.flag == 1)
                            Air.flag = 2;
                        else
                            Air.flag = 1;
                    }
                }
                
                if(x_move > RIGHT_MIN && x_move < RIGHT_MAX &&(y_move == BUTTON_UP || y_move == BUTTON_BOTH))//right 80--10
                {
                    flag_air_left = true;
                    //flag_air_straight = true;
                    if(flag_air_right == true)
                        Air.flag = 3;
                    Air.x = Chara.x - 16;
                    
                	if (count == 6)
                    {
                        flag_air_right = false;
                        if(Air.flag == 3)
                            Air.flag = 4;
                        else
                            Air.flag = 3;
                    }
                }
                
                if((y_move == BUTTON_UP || y_move == BUTTON_BOTH)&& !(x_move > LEFT_MIN && x_move < LEFT_MAX)&&!(x_move > RIGHT_MIN && x_move < RIGHT_MAX) )//up
                {
                    flag_air_straight = true;
                    if(flag_air_straight == true)
                        Air.flag = 5;
                    Air.x = Chara.x - 5;
                    
                	if (count == 6)
                    {
                        flag_air_straight = false;
                        if(Air.flag == 5)
                            Air.flag = 6;
                        else
                            Air.flag = 5;
                    }
                }
                
                if(!(y_move == BUTTON_UP || y_move == BUTTON_BOTH) )//down
                {
                    Air.flag = 0;
                }
                
                //bullet initial
                if ((y_move == BUTTON_SHOOT || y_move == BUTTON_BOTH) && num_bullet < 3 && flag_shoot == false)//at most 3 bullet
                {
                    flag_shoot = 1;
                    flag_shoot_mu = 1;
                    num_shoot = 0;
                    num_bullet++;
                    Chara.flag = 4;
                    
                    for(i = 0; i < 3; i++)//search for 3 which bullet is blank then add the new bullet to it
                    {
                        if(Bullet[i].flag == 0)
                            j = i;
                    }
                    Bullet[j].x = Chara.x + 70;  //init value
                    Bullet[j].y = Chara.y + 15;
                    Bullet[j].flag = 1;    //when bullet disappaer flag[j]=0
                }
                
                //shoot stop
                if(y_move != BUTTON_SHOOT && y_move != BUTTON_BOTH)
                {
                    flag_shoot = false;
                }
                
                //bullet move
                for(i=0; i<3;i++)
                {
                    if(Bullet[i].flag != 0)//if bullet exists
                    {
                        Bullet[i].x = Bullet[i].x + 2;
                    	if(count == 6)//if its time to change flag
                    	{
                        	
                            if (Bullet[i].flag == 1) //flag0: not exist flag1: bulletA flag2: bulletB
                                Bullet[i].flag = 2;
                        	else
                                Bullet[i].flag = 1;
                        }
                    	if(Bullet[i].x > 640)//bullet has move out of the screen
                        {
                        	Bullet[i].x = 0;
                            Bullet[i].flag = 0;
                        	num_bullet--;
                        }
                    }
                }
                
                //generation of enemy
                if(num_enemy < 3)//at most 3 enemy
                {
                    
                    count_gen_enemy++;
                    
                    if(count_gen_enemy>50)
                    {
                        generate = (rand()%15);
                        if (generate == 5||count_gen_enemy>1000)//do generation randomly
                        {
                            count_gen_enemy = 0;
                            num_enemy++;
                            enemyID = (rand()%2)+1;//random generate enemyID (0-2) standfor different shape of enemy
                            
                            for(i=0;i<3;i++)//search for which enemy position is blank then add the new bullet to the
                            {
                                if(Enemy[i].flag == 0)
                                    j = i;
                                
                            }
                            enemyId[j] = enemyID;   //chose enemy 0 1 2
                            Enemy[j].x = 740;       //from the rightside of the screen
                            Enemy[j].y = ((rand()%(4))+1)*96;//random y
                            Enemy[j].flag = 1;      //flag set to 1 meaning display
                        }
                    }
                }
                
                //enemy movement
                for(i=0; i<3;i++)
                {
                    if(Enemy[i].flag != 0)//if enemy exists
                    {
                        if(count < 5)//if its time to change loc and flag
                        {
                            Enemy[i].x -= 2;
                            Enemy[i].y += 2;
                        }
                     	else
                        {
                            Enemy[i].x -= 2;
                            Enemy[i].y -= 2;
                        }
                        if(count == 4)
                        {
                        	if(Enemy[i].flag == 1)
                                Enemy[i].flag = 2;
                            else
                                Enemy[i].flag = 1;
                        }
                        if(Enemy[i].x < 10)//if the enemy has move out of the screen
                        {
                            Enemy[i].x=0;
                            Enemy[i].flag=0;
                            num_enemy--;
                        }
                    }
                }
                
                //collision bullet & enemy
                for(i=0; i<3; i++)
                {
                    for(j=0; j<3; j++)
                    {
                        //if position overlap,(supposed that every enemy is 50*50) and flag is 1||2
                        if (Bullet[i].x + 10  > Enemy[j].x - 100 && Bullet[i].x < Enemy[j].x - 40 && (Bullet[i].y + 10 > Enemy[j].y &&
                            Bullet[i].y < Enemy[j].y + 60) && Bullet[i].flag != 0 && (Enemy[j].flag == 1 || Enemy[j].flag == 2))
                        {
                            Bullet[i].flag = 0;
                            num_bullet--;
                            Enemy[j].flag = 0;
                            num_enemy--;
                            Explosion[j].flag = 1;
                            count_dead_enemy++;
                            Explosion[j].x = Enemy[j].x - 30;
                            Explosion[j].y = Enemy[j].y;
                        }
                        if (Explosion[j].flag && count_collision[j] == 6)//if collision happened?
                        {
                            
                            Explosion[j].flag = 0;
                            Explosion[j].x = 0;
                            Explosion[j].y = 0;
                            count_collision[j]=0;
                        }
                    }
                }
                
                for(i=0; i<3; i++)
                {
                    //if position overlap,(supposed that every enemy is 50*50) and flag is 1||2
                    if (Chara.x + 40 > Enemy[i].x - 100 && Chara.x < Enemy[i].x && (Chara.y + 40 > Enemy[i].y && Chara.y < Enemy[i].y + 40)
                        && (Enemy[i].flag == 1 || Enemy[i].flag == 2) && (Chara.flag < 6))
                    {
                    	Chara.flag = 6 ;//
                        dead = true;
                    }
                }
                
                
                if(count_fell == 6)
                {
                    if(flag_shoot)
                    {		
                        if(Chara.flag == 4)
                            Chara.flag = 5;
                        else if(Chara.flag == 5)
                            Chara.flag = 4;
                    }
                }
                
            }//not dead
            else//dead
            {//falling
                Air.flag = 0;
                Bullet[0].flag = 0;
                Bullet[1].flag = 0;
                Bullet[2].flag = 0;
                Enemy[0].flag = 0;
                Enemy[1].flag = 0;
                Enemy[2].flag = 0;
                Explosion[0].flag = 0;
                Explosion[1].flag = 0;
                Explosion[2].flag = 0;
                num_bullet = 0;
                num_enemy = 0;
                if ((count == 6||count == 2) && Chara.flag >=6 && Chara.y < 380)//if collision happened?
                {
                    Chara.y += 6;
                    if(Chara.flag == 6)
                        Chara.flag = 7;
                    if(Chara.flag == 7)
                        Chara.flag = 6;
                }
                
                if(count == 6 && Chara.y >= 380)
                {
                    flag_gameover = true;
                    if(Chara.flag<11)
                    {
                        Chara.flag++;
                        Chara.x += 8;
                    }
					
                }
                if (Chara.flag == 11 && count_dead == 0)
                {
                    count_dead = 1;
                }
                if(count_dead == 60)
                {
                    count_dead = 0;
                    start = false;
                    flag_press = true;
                    flag_gameover = false;
                    count_dead_enemy = 0;
                }
                
            }//dead

        
        }//start
        
        if(count_fell == 6)
        {//brick movement
            if(Brick_x > 0)
           		Brick_x--;
            else
                Brick_x = 40;
        }
        
        if(flag_shoot_mu)
            count_shoot++;
    
        if(count_shoot==10)
        {
            count_shoot = 0;
            flag_shoot_mu = 0;
        }
        
        data[0] = Chara.x;
        data[1] = Chara.y;
        data[2] = Chara.flag;
        data[3] = Bullet[0].x;
        data[4] = Bullet[0].y;
        data[5] = Bullet[0].flag;
        data[6] = Bullet[1].x;
        data[7] = Bullet[1].y;
        data[8] = Bullet[1].flag;
        data[9] = Bullet[2].x;
        data[10] = Bullet[2].y;
        data[11] = Bullet[2].flag;
        data[12] = Enemy[0].x;
        data[13] = Enemy[0].y;
        data[14] = Enemy[0].flag;
        data[15] = enemyId[0];
        data[16] = Enemy[1].x;
        data[17] = Enemy[1].y;
        data[18] = Enemy[1].flag;
        data[19] = enemyId[1];
        data[20] = Enemy[2].x;
        data[21] = Enemy[2].y;
        data[22] = Enemy[2].flag;
        data[23] = enemyId[2];
        //xyf[24] =
        data[25] = Brick_x;
        data[26] = Explosion[0].x;
        data[27] = Explosion[0].y;
        data[28] = Explosion[0].flag;
        data[29] = Explosion[1].x;
        data[30] = Explosion[1].y;
        data[31] = Explosion[1].flag;
        data[32] = Explosion[2].x;
        data[33] = Explosion[2].y;
        data[34] = Explosion[2].flag;
        data[35] = Air.x;
        data[36] = Chara.y + 58;
        data[37] = Air.flag;
        data[38] = count_dead_enemy / 100;  //number1 398
        data[39] = (count_dead_enemy / 10) % 10; //number2
        data[40] = count_dead_enemy % 10;//number3
        data[41] = flag_press;//press
        data[42] = flag_gameover;//game over
        data[43] = flag_shoot_mu;
        write_segments(data);
        
        if (count < 8)
            count++;
        else
            count = 1;
        
        for(i=0;i<3;i++)
        {
            if (Explosion[i].flag == 1)
            {
                count_collision[i]++;
            }
        }
        
        if (count_fell<20)
            count_fell++;
        else
            count_fell = 1;
        
        usleep(17000);/////////
        
        if(count_dead >= 1)
        {
            count_dead++;
        }
        
    }
    
    
    printf("VGA LED Userspace program terminating\n");
    return 0;

}
