#include "player.h"

#include <stdint.h>
#include <stdio.h>

#include "main.h"
#include "notes.h"
#include "ui.h"

typedef struct{
    struct {
        uint16_t tone;
        uint8_t vol;
    } channel[4];
} psg_state_t;

static uint8_t music_tick_interrupt_happened = 0;
static uint8_t input_interrupt_happened = 0;
static char input;
static uint8_t playing = 0;
static uint8_t tick = 0;
static uint8_t row = 0;
static pattern_t * pattern = NULL;
static psg_state_t psg_state = {
    .channel = {
        { .tone = 0, .vol = 15 },
        { .tone = 0, .vol = 15 },
        { .tone = 0, .vol = 15 },
        { .tone = 0, .vol = 15 },
    }
};

static void sn_set_tone(uint8_t channel, uint16_t period){
    period &= 0x03ff;
    uint8_t latch = 0x80 | ((channel & 3) << 5) | (period & 0x0f);
    uint8_t data = (period >> 4) & 0x3f;
    psg_write(latch);
    psg_write(data);
}

static void sn_set_volume(uint8_t channel, uint8_t volume){
    uint8_t command = 0x90 | ((channel & 3) << 5) | (volume & 0x0f);
    psg_write(command);
}

static void flush_psg(){
    for(uint8_t chan=0; chan<3; chan++){
        sn_set_tone(chan, psg_state.channel[chan].tone);
        sn_set_volume(chan, psg_state.channel[chan].vol);
    }
    sn_set_volume(3, psg_state.channel[3].vol);
}

static void process_row(){
    row_t * current = &pattern->rows[row];
    for(uint8_t chan=0; chan<3; chan++){
        if(current->channel[chan].note >= 12 && current->channel[chan].note < NR_NOTE_PERIODS+12){
            psg_state.channel[chan].tone = note_periods[current->channel[chan].note-12];
            psg_state.channel[chan].vol = 0;
        }else if(current->channel[chan].note == 0xff){
            psg_state.channel[chan].vol = 15;
        }
    }
}

static void next_pattern(){
    playing = 0;
}

static void perform_music_tick(){
    if(!playing || !pattern)
        return;
    
    flush_psg();

    tick++;

    if(tick>=pattern->speed){
        tick = 0;
        row ++;
        if(row>=PATTERN_ROWS){
            row = 0;
            next_pattern();
        }
        process_row();
    }
}

// 50Hz music tick interrupt
void music_tick_interrupt(){
    music_tick_interrupt_happened = 1;
}

// Input interrupt
void input_interrupt(char _input){
    input = _input;
    input_interrupt_happened = 1;
}

void player_main(){
    flush_psg();
    ui_init();

    pattern_t p = {};
    p.speed = 6;

    pattern = &p;

    for(;;){
        if(music_tick_interrupt_happened){
            music_tick_interrupt_happened = 0;
            perform_music_tick();
        }
        if(input_interrupt_happened){
            input_interrupt_happened = 0;
            ui_input(input);
        }
        uint8_t action = do_ui(playing, pattern, row);
        if(action != ACTION_NONE){
            if(action == ACTION_PLAY_ONCE){
                tick = 0;
                row = 0;
                process_row();
                flush_psg();
                playing = 1;
            }
            if(action == ACTION_STOP){
                playing = 0;
                tick = 0;
                row = 0;
                psg_state = (psg_state_t){
                    .channel = {
                        { .tone = 0, .vol = 15 },
                        { .tone = 0, .vol = 15 },
                        { .tone = 0, .vol = 15 },
                        { .tone = 0, .vol = 15 },
                    }
                };
                flush_psg();
            }
            if(action == ACTION_QUIT){
                break;
            }
        }
    }

}

void save(){
    disk_write(pattern, sizeof(pattern_t));
}

void load(){
    disk_read(pattern, sizeof(pattern_t));
}
