mod args;

use std::{fs, process::exit};

use crate::args::Args;

use seapu::{
    asm::assemble,
    cpu::SeaPU,
    debug::SeaPUDebug,
    io::{DEFAULT_INPUT, DEFAULT_OUTPUT, IOAddrs, SeaPUIO},
};

use clap::Parser;

fn main() {
    let args = Args::parse();

    let mut program = fs::read(&args.file).unwrap_or_else(|err| {
        eprintln!("error opening file '{}': {}", args.file, err);
        exit(1);
    });

    let io_addrs = IOAddrs {
        input: args.input_addr.unwrap_or(DEFAULT_INPUT),
        output: args.output_addr.unwrap_or(DEFAULT_OUTPUT),
    };

    if args.assemble {
        let asm = String::from_utf8(program).unwrap_or_else(|err| {
            eprintln!("error converting file '{}' to string: {}", args.file, err);
            exit(1);
        });

        program = assemble(&asm, Some(io_addrs)).unwrap_or_else(|err| {
            eprintln!("error assembling file '{}': {}", args.file, err);
            exit(1);
        });

        if let Some(output_file) = args.assembler_output {
            fs::write(&output_file, program).unwrap_or_else(|err| {
                eprintln!("error while writing to file '{}': {}", output_file, err);
                exit(1);
            });

            exit(0);
        }
    }

    let mut cpu = SeaPU::new(SeaPUIO {
        addrs: io_addrs,
        ..Default::default()
    });

    cpu.load_program(&program);

    if args.debug {
        cpu.run_debug();
    } else {
        if let Err(e) = cpu.run() {
            eprintln!("{e}");
        };
    }

    if args.dump {
        print!("{}", cpu.dump());
    }
}
