using BizHawk.Common;

namespace BizHawk.Emulation.Cores.Nintendo.NES
{
	// RacerMate II
	// 64KB PRGROM, 64KB CHRRAM(!), CHRRAM is battry backed (!!)
	// the "ram protect" function is not emulated.  the notes i found said that it
	// defaults to off, the control regs are write only, and cannot be reenabled.  so...

	// todo: special controller, and IRQ is possibly wrong
	public sealed class Mapper168 : NES.NESBoardBase
	{
		int prg = 0;
		int chr = 0;
		int irqclock = 2048;

		public override bool Configure(NES.EDetectionOrigin origin)
		{
			switch (Cart.board_type)
			{
				case "MAPPER168":
				case "UNL-RACERMATE":
					break;
				default:
					return false;
			}
			AssertPrg(64);
			Cart.chr_size = 0; //AssertChr(0); //shitty dumps
			Cart.vram_size = 64; //AssertVram(64); //shitty dumps
			Cart.wram_size = 0; //AssertWram(0); // shitty dumps
			//AssertBattery(true); // battery is handled directly
			SetMirrorType(Cart.pad_h, Cart.pad_v);
			return true;
		}

		public override byte ReadPRG(int addr)
		{
			if (addr >= 0x4000)
				return ROM[addr + 0x8000];
			else
				return ROM[addr + (prg << 14)];
		}

		// the chr reg on hardware is supposedly bitscrambled and then inverted from
		// what would be expected.  since it doesn't make a difference and i don't know
		// of any clear source on what it's actually supposed to be, ignore.
		int Scramble(int chr)
		{
			return chr;
		}

		public override void WritePRG(int addr, byte value)
		{
			if (addr < 0x4000)
			{
				chr = value & 15;
				prg = value >> 6 & 3;
			}
			else if (addr == 0x7080) // ack
				IRQSignal = false;
			else if (addr == 0x7000) // start count
				irqclock = 0;
		}

		public override byte ReadPPU(int addr)
		{
			if (addr < 0x1000)
				return VRAM[addr | Scramble(0) << 12];
			else if (addr < 0x2000)
				return VRAM[(addr & 0xfff) | Scramble(chr) << 12];
			else
				return base.ReadPPU(addr);
		}

		public override void WritePPU(int addr, byte value)
		{
			if (addr < 0x1000)
				VRAM[addr | Scramble(0) << 12] = value;
			else if (addr < 0x2000)
				VRAM[(addr & 0xfff) | Scramble(chr) << 12] = value;
			else
				base.WritePPU(addr, value);
		}

		public override byte[] SaveRam { get { return VRAM; } }

		public override void SyncState(Serializer ser)
		{
			base.SyncState(ser);
			ser.Sync("prg", ref prg);
			ser.Sync("chr", ref chr);
			ser.Sync("irqclock", ref irqclock);
		}

		public override void ClockCPU()
		{
			if (irqclock == 2048 - 1)
			{
				irqclock++;
				IRQSignal = true;
			}
			else if (irqclock < 2048 - 1)
			{
				irqclock++;
			}
		}
	}
}
