#include <io.h>
#include <system.h>
#include <stdio.h>
#include "DM9000A.h"

#define IOWR_VGA_DATA(base, offset, data) \
    IOWR_16DIRECT(base, (offset) * 2, data) 
#define IORD_VGA_DATA(base, offset) \
    IORD_16DIRECT(base, (offset) * 2)  
#define ROUND_NUMBER 3 
#define MAX_MSG_LENGTH 128

// Ethernet MAC address.  Choose the last three bytes yourself
unsigned char mac_address[6] = { 0x01, 0x60, 0x6E, 0x11, 0x02, 0x0A  };
unsigned int  receive_buffer_length;
unsigned char receive_buffer[1600];
  
int counter=0;
float x_ball=312;// default x location of ball
float y_ball=232;// default y location of ball
int x_ball1=60;// x location of ball_1 
int y_ball1=60;// y location of ball_1
int x_ball2=55;// x location of ball_2
int y_ball2=55;// y location of ball_2

float delta_x=1;// delta x of ball
float delta_y=1;// delta y of ball

int l3=2,l2=2,l1=2;//left pad score :from left to right is l1(address is 6), l2(address is 7), and l3(address is 8)
int r3=2,r2=2,r1=2;// right pad score :from right to left is r1(address is 9), r2(address is 10), and r3(address is 11) 
  
int k; //delay counter
int l; //delay counter
int x_lpad=0;//default x location of left paddle
int y_lpad=150;//default y location of left paddle
int t=1;// delta x of left paddle 
int o=1;// delta y of left paddle
int x_rpad=619;//x location of right paddle
int y_rpad=150;//y location of right paddle
int deltax_rpad=1;// delta x of right paddle 
int deltay_rpad=1;// delta y of right paddle
int score_lpad=3;// score of left paddle
int score_rpad=3;// score of right paddle

int loop_length[]={1200,1000,800};// speed of the ball
int score_rctrl=0; // the score of the rotary controller
int score_ai=0; // the score of AI
int level_stage=2;//default is 1, the total levels will be 3
int winning_flag=0; //default is 0, when 1, rotary controller wins.otherwise, AI wins.
int step_level=3;//default is 1(level 1), total number of levels are 3 
int *pt_loop;
int divcounter=0;// change the frequency of the refreshment of left padder
int counter_map[]={64,16,2};
int *pt_cntmap;
int temp_x_lpad;
int temp_y_lpad;
int temp_x_rpad;
int temp_y_rpad;
int update_flag=1;
char ai_control = 1;

//Ethernet Interrupt
static void ethernet_interrupt_handler() 
{
  unsigned int receive_status;

  receive_status = ReceivePacket(receive_buffer, &receive_buffer_length);

  if (receive_status == DMFE_SUCCESS) 
  {
    printf("0x%.2X,", receive_buffer[42]);
    
    //Up
    if(receive_buffer[42] == 0x77)
    {   
        if(y_lpad>0)
        {
            y_lpad=y_lpad-10;
        }
     }
     
    //Down
    if(receive_buffer[42] == 0x73)
    {
        if(y_lpad < 360)
        {
            y_lpad=y_lpad+10;
        }
    } 
    
    //AI ON
    if(receive_buffer[42] == 0x6B)
    {
        ai_control = 1;
    } 
    
    //AI OFF
    if(receive_buffer[42] == 0x6C)
    {
        ai_control = 0;
    } 
  }
  /* Clear the DM9000A ISR: PRS, PTS, ROS, ROOS 4 bits, by RW/C1 */
  dm9000a_iow(ISR, 0x3F);             
  /* Re-enable DM9000A interrupts */
  dm9000a_iow(IMR, INTR_set);
}

//VGA Interrupt   
static void interrupt_vga (void * context, alt_u32 id)
{
//IOWR_16DIRECT(VGA_BASE, 0, 0); // reset request
   IOWR_VGA_DATA(VGA_BASE, 0,  x_ball);  // ball h
   IOWR_VGA_DATA(VGA_BASE, 1,  y_ball);  // ball v
   IOWR_VGA_DATA(VGA_BASE, 12, x_ball1);  // ball1 h
   IOWR_VGA_DATA(VGA_BASE, 13, y_ball1);  // ball1 v 
   IOWR_VGA_DATA(VGA_BASE, 14, x_ball2);  // ball2 h
   IOWR_VGA_DATA(VGA_BASE, 15, y_ball2);  // ball2 v
   IOWR_VGA_DATA(VGA_BASE, 2, x_lpad);  // plot x_lpad
   IOWR_VGA_DATA(VGA_BASE, 3, y_lpad);  // plot y_lpad
   IOWR_VGA_DATA(VGA_BASE, 4, x_rpad);  // plot x_rpad
   IOWR_VGA_DATA(VGA_BASE, 5, y_rpad);  // plot y_rpad 
   //Heart Display Control
   IOWR_VGA_DATA(VGA_BASE, 6, l1);  // ----left lose one score
   IOWR_VGA_DATA(VGA_BASE, 7, l2);  // ----left lose one score
   IOWR_VGA_DATA(VGA_BASE, 8, l3);  // ----left lose one score
   IOWR_VGA_DATA(VGA_BASE, 9, r1);  // ----right lose one score 
   IOWR_VGA_DATA(VGA_BASE, 10,r2);  // ----right lose one score  
   IOWR_VGA_DATA(VGA_BASE, 11,r3);  // ----right lose one score 
   
   //Heart Display Control
            if(score_lpad == 0)
            {
                l1 = 3;l2 = 3;l3 = 3;
            }
            else if(score_lpad == 1)
            {
                l1 = 3;l2 = 3;l3 = 2;
            }
            else if(score_lpad == 2)
            {
                l1 = 3;l2 = 2;l3 = 2;
            }
            else
            {
                l1 = 2;l2 = 2;l3 = 2;
            }
            
            //Heart Display Control
            if(score_rpad == 0)
            {
                r1 = 3;r2 = 3;r3 = 3;
            }
            else if(score_rpad == 1)
            {
                r1 = 3;r2 = 3;r3 = 2;
            }
            else if(score_rpad == 2)
            {
                r1 = 3;r2 = 2;r3 = 2;
            }
            else
            {
                r1 = 2;r2 = 2;r3 = 2;
            }  
    
} 

//Rotary Controller Interrupt
static void interrupt_rotary (void * context, alt_u32 id)
{
    int flag_right_left;    
    counter ++;
    printf ("%d\n",counter); 
    flag_right_left=IORD_16DIRECT(ROTARY_BASE, 0);
    //Rotary Left
    if(flag_right_left==1)
    {   
        if(y_rpad>0)
        {
           y_rpad=y_rpad-10;
        }
        printf ("Left\n");
     }  
    //Rotary Right
    if(flag_right_left==2)
    {
        if(y_rpad<360)
        {
        
        y_rpad=y_rpad+10;
        }
        printf ("Right\n");
    }
    // reset the interrupt request
    IOWR_16DIRECT(ROTARY_BASE, 0, 0);  
}

//Make one sound
void sound()
{
    IOWR_16DIRECT(AUDIO_BASE, 0, 0);
    for(k=0;k<60;k++){} 
    IORD_16DIRECT(AUDIO_BASE, 0); 
}

int main()
{
    
    alt_irq_register(VGA_IRQ, NULL, (void*)interrupt_vga); //register the irq
    // Initalize the DM9000 and the Ethernet interrupt handler
    DM9000_init(mac_address);
    alt_irq_register(DM9000A_IRQ, NULL, (void*)ethernet_interrupt_handler); 
    
    pt_loop=loop_length;// default is assigning the address of loop_length[0] to p_loop
    pt_cntmap=counter_map; //default *pt_cnt=counter_map[0]
    alt_irq_register( ROTARY_IRQ, NULL,(void*)interrupt_rotary ); // register IRQSOURCE
    
    for(;;)
    {
        for(k=0;k<*pt_loop;k++)
        {;}//delay
        
        temp_y_lpad=y_lpad;
        temp_y_rpad=y_rpad;                 
        x_ball=x_ball+delta_x;
        y_ball=y_ball+delta_y;
          
        switch(level_stage)
        {
            case 1:pt_cntmap=counter_map;
                break;
             
            case 2:pt_cntmap=counter_map+1;
                break;
      
            case 3:pt_cntmap=counter_map+2;
                break;
                
            default:
                break;                     
        }
 /*******************************************************************************/       
 // Score Control
 /*******************************************************************************/           
        if(score_lpad == 0 | score_rpad == 0)
        {
            score_lpad = 3;
            score_rpad = 3;
            if(level_stage==3)
             {
                level_stage=1;
                pt_loop=loop_length;
            } 
            else
            {
                level_stage++;
                pt_loop++;
            }
        }
              
 /*******************************************************************************/       
 // AI:left padder control part 
 /*******************************************************************************/ 
        if((divcounter = *pt_cntmap) && (ai_control == 1))        
        {  
            if(delta_x<0)
            {
                if(y_lpad>=y_ball+8)
                {
                    if(y_lpad<=0)
                    {
                        y_lpad=0;
                    }
                    else if(y_lpad>=360)
                    {
                        y_lpad=360; 
                    }
                    else
                    {
                        y_lpad=y_lpad-step_level;
                    }
                }
                else if(y_lpad<=y_ball-120)
                {
                    if(y_lpad<=0)
                    {
                        y_lpad=0;
                    }
                    else if(y_lpad>=360)
                    {
                        y_lpad=360;
                    }
                    else
                    {
                        y_lpad=y_lpad+step_level;
                    }     
                }
                else
                    y_lpad=y_lpad; 
                divcounter=0;
            }
        } 
        else
        {
            divcounter++;
        }     
 /*************************************************************************************/       
    if( x_ball<=21)
    {
        if(y_ball>=y_lpad & y_ball<=(y_lpad+120))
        {
            if(y_ball >= (y_lpad + 48) & y_ball<= (y_lpad + 72))
            {
                delta_x=1.3;
            }
            else if (y_ball >= (y_lpad + 24) & y_ball<= (y_lpad + 96))
            {
                delta_x=1;
            }
            else 
            {
                delta_x=0.7;
            }
             
            sound();
        }
        else
        {
            x_ball=312;
            y_ball=232;
            x_ball1=312;
            y_ball1=232;
            x_ball2=312;
            y_ball2=232;
            delta_x=1;

            IOWR_VGA_DATA(VGA_BASE, 0, x_ball);  // ball h
            IOWR_VGA_DATA(VGA_BASE, 1, y_ball);  // ball v
            score_lpad--;  

            for(k=0;k<5000;k++)
            {
                for(l=0;l<200;l++)
                {;}//delay
            }
        }     
    }
    
    if( x_ball>=603)
    {
        if(y_ball>=y_rpad & y_ball<=(y_rpad+120))
        {
            if(y_ball >= (y_rpad + 48) & y_ball<= (y_rpad + 72))
            {
                delta_x=-1.3;
            }
            else if (y_ball >= (y_rpad + 24) & y_ball<= (y_rpad + 96))
            {
                delta_x=-1;
            }
            else 
            {
                delta_x=-0.7;
            }
            sound();
        }
        else
        {
            x_ball=312;
            y_ball=232;
            x_ball1=312;
            y_ball1=232;
            x_ball2=312;
            y_ball2=232;
            delta_x=1;
            IOWR_VGA_DATA(VGA_BASE, 0, x_ball);  // ball h
            IOWR_VGA_DATA(VGA_BASE, 1, y_ball);  // ball v 
            score_rpad--; 
          
            for(k=0;k<5000;k++)
            {
                for(l=0;l<200;l++)
                {;}//delay//delay
            }
        }
    }
 
    //Up and down edge of Screen
    if(y_ball==0)
    {
        delta_y=1;
        sound();
    }
    if(y_ball==464)
    {
        delta_y=-1;
        sound();
    }
    
    //shadow of ball control
    if( delta_x > 0 & delta_y > 0 )
    {
        x_ball1=x_ball- 5;// x location of ball_1 
        y_ball1=y_ball- 5;// y location of ball_1
        x_ball2=x_ball-10;// x location of ball_2
        y_ball2=y_ball-10;// y location of ball_2   
    }
    else if( delta_x > 0 & delta_y < 0 )
    {
        x_ball1=x_ball- 5;// x location of ball_1 
        y_ball1=y_ball+ 5;// y location of ball_1
        x_ball2=x_ball-10;// x location of ball_2
        y_ball2=y_ball+10;// y location of ball_2   
    }
    else if( delta_x < 0 & delta_y > 0 )
    {
        x_ball1=x_ball+ 5;// x location of ball_1 
        y_ball1=y_ball- 5;// y location of ball_1
        x_ball2=x_ball+10;// x location of ball_2
        y_ball2=y_ball-10;// y location of ball_2   
    }
    else
    {
        x_ball1=x_ball+ 5;// x location of ball_1 
        y_ball1=y_ball+ 5;// y location of ball_1
        x_ball2=x_ball+10;// x location of ball_2
        y_ball2=y_ball+10;// y location of ball_2   
    }

 //   printf ("ball h : %d \n", IORD_VGA_DATA(VGA_BASE, 2));
 //   printf ("ball v : %d \n", IORD_VGA_DATA(VGA_BASE, 3));
 //   printf ("score of AI : %d\n ",score_ai);
 //   printf ("score of ROTARY : %d\n", score_rctrl);
 //   printf ("who wins(1 or 0): %d %d\n", winning_flag,level_stage);
 //   printf ("game round number: %d\n", ROUND_NUMBER);
  }
  return 0;
}



