use crate::device;
use crate::ui;

pub const MEMPAK_SIZE: usize = 0x8000;
const MPK_PAGE_SIZE: usize = 256;

pub fn format_mempak(device: &mut device::Device) {
    if device.ui.storage.saves.mempak.data.len() < MEMPAK_SIZE * 4 {
        device
            .ui
            .storage
            .saves
            .mempak
            .data
            .resize(MEMPAK_SIZE * 4, 0);

        let page_0: [u8; MPK_PAGE_SIZE] = [
            /* Label area */
            0x81, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
            0x1c, 0x1d, 0x1e, 0x1f, /* Main ID area */
            0xff, 0xff, 0xff, 0xff, 0x05, 0x1a, 0x5f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff,
            0x66, 0x25, 0x99, 0xcd, /* Unused */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, /* ID area backup #1 */
            0xff, 0xff, 0xff, 0xff, 0x05, 0x1a, 0x5f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff,
            0x66, 0x25, 0x99, 0xcd, /* ID area backup #2 */
            0xff, 0xff, 0xff, 0xff, 0x05, 0x1a, 0x5f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff,
            0x66, 0x25, 0x99, 0xcd, /* Unused */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, /* ID area backup #3 */
            0xff, 0xff, 0xff, 0xff, 0x05, 0x1a, 0x5f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff,
            0x66, 0x25, 0x99, 0xcd, /* Unused */
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
        ];
        for i in 0..4 {
            let offset = i * MEMPAK_SIZE;
            if device.ui.storage.saves.mempak.data[offset..offset + MEMPAK_SIZE] != [0; MEMPAK_SIZE]
            {
                // don't overwrite existing data
                continue;
            }

            /* Fill Page 0 with pre-initialized content */
            device.ui.storage.saves.mempak.data[offset..offset + MPK_PAGE_SIZE]
                .copy_from_slice(&page_0);

            /* Fill INODE page 1 and update it's checkum */
            let start_page = 5;
            for i in MPK_PAGE_SIZE..2 * start_page {
                device.ui.storage.saves.mempak.data[offset + i] = 0;
            }
            for i in (MPK_PAGE_SIZE + 2 * start_page..2 * MPK_PAGE_SIZE).step_by(2) {
                device.ui.storage.saves.mempak.data[offset + i] = 0x00;
                device.ui.storage.saves.mempak.data[offset + i + 1] = 0x03;
            }
            device.ui.storage.saves.mempak.data[offset + (MPK_PAGE_SIZE + 1)] = 0x71;

            /* Page 2 is identical to page 1 */
            let page1 = offset + MPK_PAGE_SIZE;
            let page2 = offset + 2 * MPK_PAGE_SIZE;
            let page1data =
                device.ui.storage.saves.mempak.data[page1..page1 + MPK_PAGE_SIZE].to_vec();
            device.ui.storage.saves.mempak.data[page2..page2 + MPK_PAGE_SIZE]
                .copy_from_slice(&page1data);

            /* Remaining pages DIR+DATA (3...) are initialized with 0x00 */
            for i in 3 * MPK_PAGE_SIZE..MEMPAK_SIZE - 3 * MPK_PAGE_SIZE {
                device.ui.storage.saves.mempak.data[offset + i] = 0;
            }
        }
    }
}

pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usize, size: usize) {
    if (address as usize) < MEMPAK_SIZE {
        let offset = (channel * MEMPAK_SIZE) + address as usize;
        device.pif.ram[data..data + size]
            .copy_from_slice(&device.ui.storage.saves.mempak.data[offset..offset + size])
    } else {
        for i in 0..size {
            device.pif.ram[data + i] = 0;
        }
    }
}

pub fn write(device: &mut device::Device, channel: usize, address: u16, data: usize, size: usize) {
    if (address as usize) < MEMPAK_SIZE {
        let offset = (channel * MEMPAK_SIZE) + address as usize;
        device.ui.storage.saves.mempak.data[offset..offset + size]
            .copy_from_slice(&device.pif.ram[data..data + size]);

        ui::storage::schedule_save(device, ui::storage::SaveTypes::Mempak);
    }
}
