package izapple2

import (
	"fmt"

	"github.com/koron-go/z80"
)

/*

Microsoft Z80 SoftCard
See:
	http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/Z80%20Cards/Microsoft%20SoftCard/


This card activates DMA to take control of the system. DMA is actiavted or
deactivated by writing to the Csxx area.

The emulation works on the Apple II+, but doesn't work when 80 columns are
available. It is not working then on the Apple IIe or the Apple II+ with a
Videx card.


*/

// CardVidHD represents a VidHD card
type CardZ80SoftCard struct {
	cardBase

	cpu       *z80.CPU
	z80Active bool
}

func newCardZ80SoftCardBuilder() *cardBuilder {
	return &cardBuilder{
		name:        "Microsoft Z80 SoftCard",
		description: "Microsoft Z80 SoftCard to run CP/M",
		buildFunc: func(params map[string]string) (Card, error) {
			var c CardZ80SoftCard
			c.romCxxx = &cardROMWriteTrap{
				callback: func() {
					c.flipDMA()
				},
			}

			return &c, nil
		},
	}
}

func (c *CardZ80SoftCard) assign(a *Apple2, slot int) {
	mem := &cardZ80SoftCardMMU{
		mmu: a.mmu,
	}

	c.cpu = &z80.CPU{
		Memory: mem,
	}

	c.cardBase.assign(a, slot)
}

func (c *CardZ80SoftCard) reset() {
	c.cpu.States = z80.States{}
}

func (c *CardZ80SoftCard) flipDMA() {
	c.tracef("Z80 DMA flip\n")
	c.z80Active = !c.z80Active
	if c.z80Active {
		c.activateDMA()
	} else {
		c.deactivateDMA()
	}
}

func (c *CardZ80SoftCard) runDMACycle() {
	if c.a.cpuTrace {
		fmt.Printf("Z80 PC: $%04X, A: $%02X, B: $%02X, C: $%02X, D: $%02X, E: $%02X, HL: $%04X\n",
			c.cpu.States.PC, c.cpu.States.AF.Hi, c.cpu.States.BC.Hi,
			c.cpu.States.BC.Lo, c.cpu.States.DE.Hi, c.cpu.States.DE.Lo,
			c.cpu.States.HL.U16())
	}
	c.cpu.Step()
}

type cardROMWriteTrap struct {
	callback func()
}

func (r *cardROMWriteTrap) peek(address uint16) uint8 {
	return 0
}

func (r *cardROMWriteTrap) poke(address uint16, value uint8) {
	if address >= 0xC000 && address < 0xC800 {
		r.callback()
	}
}

type cardZ80SoftCardMMU struct {
	mmu *memoryManager
}

func (m *cardZ80SoftCardMMU) Get(addr uint16) uint8 {
	return m.mmu.Peek(z80AddressTranslation(addr))
}

func (m *cardZ80SoftCardMMU) Set(addr uint16, value uint8) {
	m.mmu.Poke(z80AddressTranslation(addr), value)
}

func z80AddressTranslation(addr uint16) uint16 {
	if addr < 0xb000 {
		return addr + 0x1000
	} else if addr < 0xe000 {
		return addr + 0x2000
	} else if addr < 0xf000 {
		return addr - 0x2000
	} else {
		return addr - 0xf000
	}
}
