//////////////////////////////////////////////////////////////////////////
// Mapper236  800-in-1                                                  //
//////////////////////////////////////////////////////////////////////////
using static VirtualNes.MMU;
using BYTE = System.Byte;


namespace VirtualNes.Core
{
    public class Mapper236 : Mapper
    {
        BYTE bank, mode;
        public Mapper236(NES parent) : base(parent)
        {
        }

        public override void Reset()

        {
            SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);

            bank = mode = 0;
        }

        //void Mapper236::Write(WORD addr, BYTE data)
        public override void Write(ushort addr, byte data)
        {
            if (addr >= 0x8000 && addr <= 0xBFFF)
            {
                bank = (byte)(((addr & 0x03) << 4) | (bank & 0x07));
            }
            else
            {
                bank = (byte)((addr & 0x07) | (bank & 0x30));
                mode = (byte)(addr & 0x30);
            }

            if ((addr & 0x20) != 0)
            {
                SetVRAM_Mirror(VRAM_HMIRROR);
            }
            else
            {
                SetVRAM_Mirror(VRAM_VMIRROR);
            }

            switch (mode)
            {
                case 0x00:
                    bank |= 0x08;
                    SetPROM_8K_Bank(4, bank * 2 + 0);
                    SetPROM_8K_Bank(5, bank * 2 + 1);
                    SetPROM_8K_Bank(6, (bank | 0x07) * 2 + 0);
                    SetPROM_8K_Bank(7, (bank | 0x07) * 2 + 1);
                    break;
                case 0x10:
                    bank |= 0x37;
                    SetPROM_8K_Bank(4, bank * 2 + 0);
                    SetPROM_8K_Bank(5, bank * 2 + 1);
                    SetPROM_8K_Bank(6, (bank | 0x07) * 2 + 0);
                    SetPROM_8K_Bank(7, (bank | 0x07) * 2 + 1);
                    break;
                case 0x20:
                    bank |= 0x08;
                    SetPROM_8K_Bank(4, (bank & 0xFE) * 2 + 0);
                    SetPROM_8K_Bank(5, (bank & 0xFE) * 2 + 1);
                    SetPROM_8K_Bank(6, (bank & 0xFE) * 2 + 2);
                    SetPROM_8K_Bank(7, (bank & 0xFE) * 2 + 3);
                    break;
                case 0x30:
                    bank |= 0x08;
                    SetPROM_8K_Bank(4, bank * 2 + 0);
                    SetPROM_8K_Bank(5, bank * 2 + 1);
                    SetPROM_8K_Bank(6, bank * 2 + 0);
                    SetPROM_8K_Bank(7, bank * 2 + 1);
                    break;
            }
        }


        //void Mapper236::SaveState(LPBYTE p)
        public override void SaveState(byte[] p)
        {
            p[0] = bank;
            p[1] = mode;
        }

        //void Mapper236::LoadState(LPBYTE p)
        public override void LoadState(byte[] p)
        {
            bank = p[0];
            mode = p[1];
        }
    }
}