#pragma once
#include "stdafx.h"
#include "BaseMapper.h"
#include "InternalRamHandler.h"

//SSS-NROM-256 (Famicom box menu board)
//Info from here: http://kevtris.org/mappers/famicombox/index6.html
class FamicomBox : public BaseMapper
{
private:
	uint8_t _regs[8];
	uint8_t _extInternalRam[0x2000];
	InternalRamHandler<0x1FFF> _extendedRamHandler;

protected:
	uint32_t GetDipSwitchCount() override { return 8; }
	uint16_t RegisterStartAddress() override { return 0x5000; }
	uint16_t RegisterEndAddress() override { return 0x5FFF; }	
	uint16_t GetPRGPageSize() override { return 0x4000; }
	uint16_t GetCHRPageSize() override { return 0x2000; }
	bool AllowRegisterRead() override { return true; }

	void InitMapper() override
	{
		_regs[7] = 0xFF;

		SelectPRGPage(0, 0);
		SelectPRGPage(1, 1);

		SelectCHRPage(0, 0);

		_extendedRamHandler.SetInternalRam(_extInternalRam);
	}

	void StreamState(bool saving) override
	{
		BaseMapper::StreamState(saving);
		ArrayInfo<uint8_t> regs { _regs, 8 };
		ArrayInfo<uint8_t> extRam { _extInternalRam, 0x2000 };
		Stream(regs, extRam);
	}

	void Reset(bool softReset) override
	{
		for(int i = 0; i < 6; i++) {
			_regs[i] = 0;
		}
		_console->GetMemoryManager()->RegisterIODevice(&_extendedRamHandler);
	}

	uint8_t ReadRegister(uint16_t addr) override
	{
		switch(addr & 7) {
			case 0: 
				/*
					5000R: Device which caused an exception (0 = this device caused the exception)
					-----
					0 - 6.82Hz interrupt source hit
					1 - 8 bit timer expired @ 5003W
					2 - controller(s) were read
					3 - keyswitch was rotated
					4 - money was inserted
					5 - reset button was pressed
					6 - watchdog timer expired (reading either controller resets this timer)
					7 - Pin 4 of "CATV connector" went high/open
				*/
				_regs[0] = 0xFF; // clear all exceptions
				return _regs[0];
			
			case 1:
				//5001R (not implemented)
				break;

			case 2:
				/*
				5002R Dip switch register
					DIP Switches Info:
						0x01 - Self Test.  When on, unit will continuously self-test
						0x02 - Coin timeout period. off = 10 minutes, on = 20 minutes
						0x04 - not used
						0x08 - Famicombox menu time. off = 7 sec, on = 12 sec

						0x10 - attract time
						0x20 - attract time
						00: 12 seconds
						01: 17 seconds
						10: 23 seconds
						11: 7 seconds

						0x40 - Mode
						0x80 - Mode
						00: Key Mode
						01: CATV Mode
						10: Coin Mode
						11: Free Play
				*/
				return GetDipSwitches();
			
			case 3:
				/*5003R
					0 - key position 0 (1 = in this position)
					1 - key position 1
					2 - key position 2
					3 - key position 3
					4 - key position 4
					5 - key position 6
					6 - money system enabled (pin 9 of 3199)
					7 - pin 10 of 3199
				*/
				return 0x00;	// 0, 1 - attract
										// 2
										// 4    - menu
										// 8    - self check and game casette check
										// 10   - lock?
										// 20   - game title & count display
			case 4:
				//5004R - DB-25 pins
				return 0;

			case 5:
				//5005R: The enable for this runs to pin 28 of the expansion connector.
				return 0;

			case 6:
				//5006R: The enable for this runs to pin 27 of the expansion connector.
				return 0;
			
			case 7:
				/*
					0 - TV type selection (1 = game, 0 = TV)
					1 - keyswitch turned (1 = in middle of positions)
					2 - 0 = zapper grounded
					3 - pin 21 of exp. conn. (inverted)
					4 - state of pin 8 of "CATV" connector,  0 = low, 1 = high
					5 - relay position. 0 = position A, 1 = position B
					6 - pin 22 of exp. conn. (inverted)
					7 - 5005.5W (inverted)
				*/
				return 0x22;	// TV type, key not turned, relay B
		}
		return 0;
	}

	void WriteRegister(uint16_t addr, uint8_t value) override
	{
		//None of this is implemented
		switch(addr & 0x07) {
			case 0:
				/*
					5000W: Exception Trap enable register (reset to 00h on powerup only)
					-----
					0 - 6.82Hz interrupt source (0 = enable)
					1 - 8 bit timer expiration @ 5003W (1 = enable)
					2 - controller reads (1 = enable)
					3 - keyswitch rotation (1 = enable)
					4 - money insertion (1 = enable)
					5 - reset button (1 = enable)
					6 - not used
					7 - "CATV connector" pin 4 detection (1 = enable)
				*/
				break;

			case 1:
				/*
					5001W Money handling register (reset to 00h on power up only)
					-----
					0 - pin 1 of 2D(3199)
					1 - pin 2 of 2D(3199)
					2 - pin 3 of 2D(3199)
					3 - pin 4 of 2D(3199)
					4 - pin 12 of 2D(3199)
					5 - pin 14 of 2D(3199)
					6 - enable pin 7 of "CATV" connector, 1 = enable.when in TV mode, output goes low. else output stays high
					7 - inverter->pin 8 of "CATV" connector
				*/
				break;

			case 2:
				/*
					5002W LED & memory protect register (reset to 00h when CPU is reset)
					-----

					0 - LED sel 0
					1 - LED sel 1
					2 - LED sel 2
					3 - LED sel 3
					4 - Mem Protect 0
					5 - Mem protect 1
					6 - Mem protect 2
					7 - LED flash- high = flash, low = steady

					LED sel: 01-0fh selects one of the LEDs on the front, 0 = no LEDs

					Mem protect:

					0   - no RAM is writable
					1   - 0000-07ffh is writable
					2   - 0000-0fffh is writable
					3   - 0000-17ffh is writable
					4-7 - 0000-1fffh is writable
				*/
				break;

			case 3:
				/*
					5003W 8 bit down counter, for attract mode timing
					-----

					Writing to this location loads the counter with the 8 bit value written                                      .
					It is clocked at a 6.8274Hz rate.  When the timer wraps from 00h to ffh
					it triggers an exception, if it is enabled. (See 5000W and 5000R)
					This timer is used for the "attract" mode.  It lets the game run for
					several seconds before it brings the menu back.
				*/
				break;

			case 4:
				/*
					5004W Cart control register (reset to 00h when CPU is reset)
					-----

					0 - cart 0
					1 - cart 1
					2 - cart 2
					3 - cart 3
					4 - row select 0
					5 - row select 1
					6 - Lock.  writing a 1 here unmaps all hardware
					7 - NC

					cart:  These 4 bits select which cartridge is active.  Cartridge 0 is the
					menu cart inside the unit, carts 01-0fh are the carts on the front.

					row select: These bits select which row of carts is active.

					0 - only the internal menu cart is selected.
					1 - carts 1-5 are selected
					2 - carts 6-10 are selected
					3 - carts 11-15 are selected

					Proper cart selection requires setting up BOTH the desired cart # (00-0fh), AND
					the proper row.  The menu software uses a small table to do this.
				*/
				break;

			case 5:
				/*
					5005W CATV and joypad control (reset to 00h on power up only)
					-----
					0 - 1 = flip latching relay to position A (coil on pins 1 & 10)
					1 - connects to 3199
					2 - turn zapper on. 1 = turn on
					3 - enable 40% input of modulator.  1 = enable, 0 = disable
					4 - NC
					5 - maps to 5007R.7
					6 - joypad enable- 1 = disable, 0 = enable
					7 - joypad swap. 1 = normal, 0 = swap        swapping only swaps D0 and CLK
				*/
				break;

			case 6:
				/*
					5006W (not reset, unknown contents at powerup)
					-----
					0 - DB-25 pin 6
					1 - DB-25 pin 15
					2 - DB-25 pin 7
					3 - DB-25 pin 16
					4 - DB-25 pin 8
					5 - DB-25 pin 17
					6 - DB-25 pin 9
					7 - DB-25 pin 18
				*/
				break;

			case 7:
				/*
					5007W (not implemented)
					-----
					The enable for this runs to pin 26 of the expansion connector.
				*/
				break;
		}
	}
};
