/*
 * For the STK500. Connect PORTB to leds and PORTD to switches.
 */
//#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 100000UL
#include <util/delay.h>

// Globals
volatile uint8_t playing;
volatile uint8_t score;
int leds[9] = {255,254,253,251,247,239,223,191,127};
int i = 0;

// Prototypes
int attract(int);
int speed(void);
int target(int);
int tug(void);
int bounce(void);
void display(int);
void countdown(void);

// Interrupt Handler
SIGNAL(SIG_OUTPUT_COMPARE1A) {
    if ( playing == 1 ) {
        playing = 0;
        for(i=0;i<=10;i++){
            display(score);
            _delay_ms(3000);
            PORTB=0xFF;
            _delay_ms(3000);
        }
    }
    return;
}

int main(void) {
    sei();
    DDRD = 0;    /* set for input. */
    DDRB = 0xff; /* enable as output */
    int j = 0;

    while(1) {
        int rc = attract(j++);
        if ( rc == 1 || rc == 5 ) {
            speed();
        }
        else if ( rc == 2 || rc == 6 ) {
            target(500);
        }
        else if ( rc == 3 || rc == 7 ) {
            tug();
        }
        else if ( rc == 4 ) {
            bounce();
        }
    }
    return 1;
}

int attract(int j) {
    int l_rc = 0;
    PORTB = leds[j%9];
    for(i=0;i<900;i++) {
        if ( ( ( PIND & ( 1 << PD0 ) ) == 0 ) || ( ( PIND & ( 1 << PD1 ) ) == 0 ) ) {
            l_rc=j%9;
        }
        _delay_ms(5);
    }
    return l_rc;
}

int bounce(void) {
    _delay_ms(1000);
    int ball = 5;
    int miss = 0;
    int forward = 0;
    int count = 500;
    score = -1;
    while ( miss != 1 ) {
        if ( forward == 1 ) {
            ball++;
        }
        else {
            ball--;
        }
        PORTB=leds[ball];
        if ( ball == 0 || ball == 8 ) {
            miss=1;
        }
        else {
            for(i=0;i<count;i++) {
                if ( ( ball == 1 ) && ( ( PIND & ( 1 << PD0 ) ) == 0 ) ) {
                        forward=1;
                }
                else if ( ( ball == 7 ) && ( ( PIND & ( 1 << PD1 ) ) == 0 ) ) {
                        forward=0;
                }
                else {
                    if ( ( PIND & ( 1 << PD0 ) ) == 0 ) {
                        miss=1;
                    }
                    if ( ( PIND & ( 1 << PD1 ) ) == 0 ) {
                        miss=1;
                    }
                }
                _delay_ms(10);
            }
        }
        if ( ball == 7 || ball == 1 ) {
            if ( count > 61 ) {
                count=count-20;
            }
            else if ( count > 20 && ball == 7 ) {
                count=count-1;
            }
            score++;
        }
    }
    // Display Score
    for(i=0;i<=10;i++){
        PORTB=0xFF;
        _delay_ms(3000);
        display(score);
        _delay_ms(3000);
    }
    return 1;
}

int target(int l_time) {
    // Flash Target
    //int bullseye = rand()%6+2;
    int bullseye = 4;
    for(i=0;i<7;i++) {
        PORTB = leds[bullseye];
        _delay_ms(5000);
        PORTB = 0xff;
        _delay_ms(5000);
    }

    // Run lights
    score = 1;
    i = 0;
    while ( ( ( PIND & ( 1 << PD1 ) ) != 0 ) && ( ( PIND & ( 1 << PD0 ) ) != 0 ) && (i++<(25*9)+1) ) {
        PORTB = leds[i%9];
        _delay_ms(l_time);
        if ( (i%9) == 0 ) {
            score++;
        }
    }
    if ( (i%9) != bullseye ) {
        score=255;
    }

    // Display Score
    for(i=0;i<=10;i++){
        PORTB=0xFF;
        _delay_ms(3000);
        display(score);
        _delay_ms(3000);
    }

    PORTB = 0xff;
     return 1;
}

int speed(void) {
    countdown();
    // Timer setup
    TCNT1 = 0;
    TIMSK = _BV(OCIE1A);
    TCCR1B = _BV(CS12) | _BV(WGM12);
    OCR1A = 31250;

    score = 0;
    playing = 1;
    while (playing==1) {
        if ( ( PIND & ( 1 << PD1 ) ) == 0  ) {
            _delay_ms(75);
            while ( ( PIND & ( 1 << PD1 ) ) == 0  ) {}
            score++;
        }
        display(score);
    }
    return 1;
}

int tug(void) {
    countdown();
    
    score = 0;
    i = 4;
    int down0 = 0;
    int down1 = 0;

    // Timer setup
    TCNT1 = 0;
    TIMSK = _BV(OCIE1A);
    TCCR1B = _BV(CS12) | _BV(WGM12);
    OCR1A = 31250;
    playing = 1;
    while (playing==1) {
        PORTB=leds[i];
        if ( i>4 ) {
            score=0xF8;
        }
        else if (i<4) {
            score=0x0F;
        }
        else {
            score=0xFF;
        }
        if ( ( PIND & ( 1 << PD1 ) ) == 0  ) {
            _delay_ms(50);
            down1=1;
        }
        if ( ( PIND & ( 1 << PD0 ) ) == 0  ) {
            _delay_ms(50);
            down0=1;
        }
        if ( ( ( PIND & ( 1 << PD1 ) ) != 0 ) && ( down1 == 1 ) ) {
            down1=0;
            if ( i<7 ) {
                i++;
            }
        }
        if ( ( ( PIND & ( 1 << PD0 ) ) != 0 ) && ( down0 == 1 ) ) {
            down0=0;
            if ( i>1 ) {
                i--;
            }
        }
    }
    return 1;
}

void countdown(void) {
    for(i=5;i>0;i--){
        PORTB=leds[i];
        _delay_ms(3000);
    }
    return;
}

void display(int l_score) {
    PORTB=255-l_score;
}