//////////////////////////////////////////////////////////////////////////
// Mapper173          Subor                                             //
//////////////////////////////////////////////////////////////////////////
using VirtualNes.Core.Debug;
using static VirtualNes.MMU;
using BYTE = System.Byte;
using INT = System.Int32;
namespace VirtualNes.Core
{
    public class Mapper173 : Mapper
    {

        BYTE[] reg = new BYTE[10];

        INT irq_counter, irq_latch;
        BYTE irq_enable, irq_repeat;
        BYTE irq_occur;
        public Mapper173(NES parent) : base(parent) { }

        public override bool IsStateSave()
        {
            return true;
        }
        public override void Reset()
        {
            //	nes.ppu.SetExtLatchMode( TRUE );
            for (INT i = 0; i < 11; i++) reg[i] = 0x00;

            irq_enable = irq_repeat = 0;
            irq_counter = irq_latch = 0;
            irq_occur = 0;

            SetPROM_32K_Bank(0);
            nes.SetVideoMode(2 != 0);
        }

        public override byte ExRead(ushort addr)
        {
            Debuger.Log($"ExRead   - addr= {addr}\n");

            return 0x00;

            switch (addr)
            {
                case 0x4026:
                    //
                    break;
                case 0x4033:
                    //D7: 
                    //D6: 
                    //D5: 
                    //D4: 
                    //D3: 
                    //D2: 
                    //D1: 
                    //D0: 
                    //
                    break;
                case 0x4204:    //FDC主状态寄存器(STATUS)
                                //
                    break;
                case 0x4205:    //FDC数据寄存器(DATA)(读???)
                                //
                    break;
            }
        }

        public override void ExWrite(ushort addr, byte data)
        {
            Debuger.Log($"ExWrite  - addr= {addr} ; dat= {data}\n");
            switch (addr)
            {
                case 0x4020:
                    reg[0] = data;
                    break;
                case 0x4022:
                    reg[1] = data;
                    break;
                case 0x4023:
                    reg[2] = data;
                    break;
                case 0x4026:
                    reg[3] = data;
                    break;
                case 0x4031:
                    reg[4] = data;
                    break;
                case 0x4032:
                    reg[5] = data;

                    irq_repeat = (byte)(data & 0x01);
                    irq_enable = (byte)(data & 0x02);
                    irq_occur = 0;
                    if (irq_enable != null)
                    {
                        irq_counter = irq_latch;
                    }
                    else
                    {
                        nes.cpu.ClrIRQ(CPU.IRQ_MAPPER);
                    }
                    break;
                case 0x4034:
                    reg[6] = data;

                    irq_latch = (irq_latch & 0xFF00) | data;
                    break;
                case 0x4035:
                    reg[7] = data;

                    irq_latch = (irq_latch & 0x00FF) | (data << 8);
                    break;
                case 0x4040:
                    SetPROM_4K_Bank(0x8000, data & 0x7F);
                    break;
                case 0x4041:
                    SetPROM_4K_Bank(0x9000, data & 0x7F);
                    break;
                case 0x4042:
                    SetPROM_4K_Bank(0xa000, data & 0x7F);
                    break;
                case 0x4043:
                    SetPROM_4K_Bank(0xb000, data & 0x7F);
                    break;
                case 0x4044:
                    SetPROM_4K_Bank(0xc000, data & 0x7F);
                    break;
                case 0x4045:
                    SetPROM_4K_Bank(0xd000, data & 0x7F);
                    break;
                case 0x4046:
                    SetPROM_4K_Bank(0xe000, data & 0x7F);
                    break;
                case 0x4047:
                    SetPROM_4K_Bank(0xf000, data & 0x7F);
                    break;

                case 0x4205:    //FDC数据寄存器(DATA)(写???)
                                //
                    break;
            }
        }

        public override byte ReadLow(ushort addr)
        {
            //	DEBUGOUT( "ReadLow  - addr= %04x\n", addr );

            return CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
        }

        public override void WriteLow(ushort addr, byte data)
        {
            //	DEBUGOUT( "WriteLow - addr= %04x ; dat= %03x\n", addr, data );

            CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
        }

        public override void Write(ushort addr, byte data)
        {
            //	DEBUGOUT( "Write    - addr= %04x ; dat= %03x\n", addr, data );
        }


        public override void HSync(int scanline)
        {
            //	if( (scanline >= 0 && scanline <= 239) ) {
            //		if( nes.ppu.IsDispON() ) {
            //			if( irq_enable ) {
            //				irq_enable = 0;
            ///				nes.cpu.SetIRQ( IRQ_MAPPER );
            //			}
            //		}
            //	}
        }

        public override void Clock(int cycles)
        {

            if (irq_enable != 0)
            {
                irq_counter -= cycles;
                if (irq_counter <= 0)
                {
                    ////			irq_counter &= 0xFFFF;
                    irq_counter += irq_latch;

                    if (irq_occur == 0)
                    {
                        irq_occur = 0xFF;
                        if (irq_repeat == 0)
                        {
                            irq_enable = 0;
                        }
                        nes.cpu.SetIRQ(CPU.IRQ_MAPPER);
                    }
                }
            }
        }

        public override void PPU_Latch(ushort addr)
        {
            //
        }

        public override void PPU_ExtLatch(ushort ntbladr, ref byte chr_l, ref byte chr_h, ref byte attr)
        {
            INT loopy_v = nes.ppu.GetPPUADDR();
            INT loopy_y = nes.ppu.GetTILEY();
            INT tileofs = (PPUREG[0] & PPU.PPU_BGTBL_BIT) << 8;
            INT attradr = 0x23C0 + (loopy_v & 0x0C00) + ((loopy_v & 0x0380) >> 4);
            INT attrsft = (ntbladr & 0x0040) >> 4;
            ArrayRef<byte> pNTBL = PPU_MEM_BANK[ntbladr >> 10];
            INT ntbl_x = ntbladr & 0x001F;
            INT tileadr, ntb;

            ntb = (ntbladr >> 10) & 3;

            if (ntb == 2)
                tileofs |= 0x1000;
            //	else if(ntb && PPU_SW)
            tileofs |= 0x1000;
            //	else
            tileofs |= 0x0000;

            attradr &= 0x3FF;
            attr = (byte)(((pNTBL[attradr + (ntbl_x >> 2)] >> ((ntbl_x & 2) + attrsft)) & 3) << 2);
            tileadr = tileofs + pNTBL[ntbladr & 0x03FF] * 0x10 + loopy_y;

            chr_l = PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
            chr_h = PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
        }

        public override void SaveState(byte[] p)
        {
            //
        }

        public override void LoadState(byte[] p)
        {
            //
        }
    }
}