mod definitions;
mod implementations;

use crate::cpu::Cpu;

#[allow(unused_imports)]
use crate::cpu::instructions::definitions::*;

#[derive(Clone, Copy)]
pub struct Instruction {
    pub name: &'static str,
    pub opcode: u8,
    pub cycles: u8,
    pub addrmode: fn(cpu: &mut Cpu) -> u8,
    pub execute: fn(cpu: &mut Cpu) -> u8,
}

impl Instruction {
    pub fn lookup(opcode: u8) -> Instruction {
        match opcode {
            // could be something like
            // `opcode if opcode == BRK_00.opcode`
            // this would prevent bugs with differing
            // opcodes, but since the match arms were
            // generated with a script and since that
            // would be uglier, I decided to do the
            // pattern match like this
            0x00 => BRK_00,
            0x01 => ORA_01,
            0x05 => ORA_05,
            0x06 => ASL_06,
            0x08 => PHP_08,
            0x09 => ORA_09,
            0x0A => ASL_0A,
            0x0D => ORA_0D,
            0x0E => ASL_0E,
            0x10 => BPL_10,
            0x11 => ORA_11,
            0x15 => ORA_15,
            0x16 => ASL_16,
            0x18 => CLC_18,
            0x19 => ORA_19,
            0x1D => ORA_1D,
            0x1E => ASL_1E,
            0x20 => JSR_20,
            0x21 => AND_21,
            0x24 => BIT_24,
            0x25 => AND_25,
            0x26 => ROL_26,
            0x28 => PLP_28,
            0x29 => AND_29,
            0x2A => ROL_2A,
            0x2C => BIT_2C,
            0x2D => AND_2D,
            0x2E => ROL_2E,
            0x30 => BMI_30,
            0x31 => AND_31,
            0x35 => AND_35,
            0x36 => ROL_36,
            0x38 => SEC_38,
            0x39 => AND_39,
            0x3D => AND_3D,
            0x3E => ROL_3E,
            0x40 => RTI_40,
            0x41 => EOR_41,
            0x45 => EOR_45,
            0x46 => LSR_46,
            0x48 => PHA_48,
            0x49 => EOR_49,
            0x4A => LSR_4A,
            0x4C => JMP_4C,
            0x4D => EOR_4D,
            0x4E => LSR_4E,
            0x50 => BVC_50,
            0x51 => EOR_51,
            0x55 => EOR_55,
            0x56 => LSR_56,
            0x58 => CLI_58,
            0x59 => EOR_59,
            0x5D => EOR_5D,
            0x5E => LSR_5E,
            0x60 => RTS_60,
            0x61 => ADC_61,
            0x65 => ADC_65,
            0x66 => ROR_66,
            0x68 => PLA_68,
            0x69 => ADC_69,
            0x6A => ROR_6A,
            0x6C => JMP_6C,
            0x6D => ADC_6D,
            0x6E => ROR_6E,
            0x70 => BVS_70,
            0x71 => ADC_71,
            0x75 => ADC_75,
            0x76 => ROR_76,
            0x78 => SEI_78,
            0x79 => ADC_79,
            0x7D => ADC_7D,
            0x7E => ROR_7E,
            0x81 => STA_81,
            0x84 => STY_84,
            0x85 => STA_85,
            0x86 => STX_86,
            0x88 => DEY_88,
            0x8A => TXA_8A,
            0x8C => STY_8C,
            0x8D => STA_8D,
            0x8E => STX_8E,
            0x90 => BCC_90,
            0x91 => STA_91,
            0x94 => STY_94,
            0x95 => STA_95,
            0x96 => STX_96,
            0x98 => TYA_98,
            0x99 => STA_99,
            0x9A => TXS_9A,
            0x9D => STA_9D,
            0xA0 => LDY_A0,
            0xA1 => LDA_A1,
            0xA2 => LDX_A2,
            0xA4 => LDY_A4,
            0xA5 => LDA_A5,
            0xA6 => LDX_A6,
            0xA8 => TAY_A8,
            0xA9 => LDA_A9,
            0xAA => TAX_AA,
            0xAC => LDY_AC,
            0xAD => LDA_AD,
            0xAE => LDX_AE,
            0xB0 => BCS_B0,
            0xB1 => LDA_B1,
            0xB4 => LDY_B4,
            0xB5 => LDA_B5,
            0xB6 => LDX_B6,
            0xB8 => CLV_B8,
            0xB9 => LDA_B9,
            0xBA => TSX_BA,
            0xBC => LDY_BC,
            0xBD => LDA_BD,
            0xBE => LDX_BE,
            0xC0 => CPY_C0,
            0xC1 => CMP_C1,
            0xC4 => CPY_C4,
            0xC5 => CMP_C5,
            0xC6 => DEC_C6,
            0xC8 => INY_C8,
            0xC9 => CMP_C9,
            0xCA => DEX_CA,
            0xCC => CPY_CC,
            0xCD => CMP_CD,
            0xCE => DEC_CE,
            0xD0 => BNE_D0,
            0xD1 => CMP_D1,
            0xD5 => CMP_D5,
            0xD6 => DEC_D6,
            0xD8 => CLD_D8,
            0xD9 => CMP_D9,
            0xDA => NOP_DA,
            0xDD => CMP_DD,
            0xDE => DEC_DE,
            0xE0 => CPX_E0,
            0xE1 => SBC_E1,
            0xE4 => CPX_E4,
            0xE5 => SBC_E5,
            0xE6 => INC_E6,
            0xE8 => INX_E8,
            0xE9 => SBC_E9,
            0xEA => NOP_EA,
            0xEC => CPX_EC,
            0xED => SBC_ED,
            0xEE => INC_EE,
            0xF0 => BEQ_F0,
            0xF1 => SBC_F1,
            0xF5 => SBC_F5,
            0xF6 => INC_F6,
            0xF8 => SED_F8,
            0xF9 => SBC_F9,
            0xFA => NOP_FA,
            0xFD => SBC_FD,
            0xFE => INC_FE,

            _ => Instruction {
                name: "INVALID",
                opcode: 0xFF,
                cycles: 0,
                addrmode: |_| 0,
                execute: |_| 0,
            },
        }
    }
}
