use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::bus_device::BusDevice;

impl Mos6520 {
    pub fn tick(&mut self, address_bus: u16, data_bus: u8) -> u8 {
        self.address_bus = address_bus;
        self.data_bus = data_bus;

        println!("Preparing to tick MOS6520");

        // are we changing our state?
        let effective = self.internal_address(self.address_bus);

        match effective {
            0x00 => {
                // ddra
                // println!("DDRA -> {:02x} -> {:02x}", self.ddra, self.data_bus);
                self.ddra = self.data_bus;
            }
            0x01 => {
                // port a
                // println!("PORT A -> {:02x} -> {:02x}", self.port_a, self.data_bus);
                self.port_a = self.data_bus;
            }
            0x02 => {
                // ddrb
                // println!("DDRB -> {:02x}", self.ddrb);
                self.ddrb = self.data_bus;
            }
            0x03 => {
                // port b
                // println!("PORT B -> {:02x}", self.port_b);
                self.port_b = self.data_bus;
            }
            _ => {
                panic!("Unable to access via 6520 at offset ${effective}")
            }
        }

        self.tick_port_a();
        self.tick_port_b();

        self.data_bus
    }

    fn tick_port_a(&mut self) {
        self.out_a = 0x00;
        self.in_a = 0x00;

        for current_bit in 0..8 {
            let bit_mask = 1 << current_bit;
            let is_output = (self.ddra & bit_mask) != 0;
            let is_set = (self.port_a & bit_mask) != 0;

            match (is_output, is_set) {
                (true, true) => self.out_a |= bit_mask,
                (false, true) => self.in_a |= bit_mask,
                _ => {}
            }
        }

        println!("Time to tick the device on port a");
    }

    fn tick_port_b(&mut self) {
        self.out_b = 0x00;
        self.in_b = 0x00;

        for current_bit in 0..8 {
            let bit_mask = 1 << current_bit;
            let is_output = (self.ddrb & bit_mask) != 0;
            let is_set = (self.port_b & bit_mask) != 0;

            match (is_output, is_set) {
                (true, true) => self.out_b |= bit_mask,
                (false, true) => self.in_b |= bit_mask,
                _ => {}
            }
        }
        println!("Time to tick the device on port b");
    }
}
