#[macro_use]
extern crate bitflags;

pub(crate) mod controller;

use anyhow::{anyhow, Result};
use log::{debug, error, info, warn};
use std::{
    fs::{File, OpenOptions},
    io::{Read, Write},
    str::from_utf8,
    sync::{Arc, RwLock},
    thread::spawn,
    time::Instant,
};

#[derive(Debug)]
pub(crate) struct State {
    controller: [u8; 4],
    last_got: Box<Instant>,
    ok: bool,
}

pub(crate) type MTState = Arc<RwLock<State>>;

fn main() -> Result<()> {
    pretty_env_logger::try_init()?;

    let mut vblank = File::open("vblank")?;
    let mut input = OpenOptions::new().write(true).open("input")?;

    let st = {
        let st = State {
            controller: [0; 4],
            last_got: Box::new(Instant::now()),
            ok: true,
        };

        Arc::new(RwLock::new(st))
    };

    info!("ready");

    {
        let st = st.clone();
        spawn(move || controller::test(st));
    }

    loop {
        let mut data = [0; 3];
        debug!("waiting for vblank");
        vblank.read(&mut data)?;
        let str = from_utf8(&data)?;
        debug!("got data: {}", str);

        match str {
            "OK\n" => {
                let mut data = st.write().unwrap();
                input.write(&data.controller)?;
                data.controller = [0; 4];
            }
            "BYE" => {
                warn!("asked to exit by the game");
                return Ok(());
            }
            _ => {
                error!("got unknown FIFO data {}", str);
                return Err(anyhow!("unknown FIFO data received"));
            }
        };
    }
}
