package izapple2

import (
	"fmt"
)

/*
  See:
	https://github.com/davidgiven/cpm65
*/

type traceCpm65 struct {
	a           *Apple2
	skipConsole bool
}

const (
	cpm65BdosEntrypoint uint16 = 0x0804 // start-3, not really sure about this
)

func newTraceCpm65(skipConsole bool) *traceCpm65 {
	var t traceCpm65
	t.skipConsole = skipConsole
	return &t
}

func (t *traceCpm65) connect(a *Apple2) {
	t.a = a
}

func (t *traceCpm65) inspect() {
	pc, _ := t.a.cpu.GetPCAndSP()
	if pc == cpm65BdosEntrypoint {
		regA, regX, regY, _ := t.a.cpu.GetAXYP()
		param := uint16(regX)<<8 | uint16(regA)
		switch regY {
		case 2: // CONSOLE_OUTPUT
			if !t.skipConsole {
				fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x with \"%c\"\n", regY, bdosCodeToName(regY), pc, regA)
			}
		case 9: // WRITE_STRING
			if !t.skipConsole {
				text := t.getCpmString(param)
				fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x with \"%s\"\n", regY, bdosCodeToName(regY), pc, text)
			}
		default:
			fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x\n", regY, bdosCodeToName(regY), pc)
		}
	}
}

var cpm65BdosNames = []string{
	"EXIT_PROGRAM",           // 0
	"CONSOLE_INPUT",          // 1
	"CONSOLE_OUTPUT",         // 2
	"AUX_INPUT",              // 3
	"AUX_OUTPUT",             // 4
	"PRINTER_OUTPUT",         // 5
	"DIRECT_IO",              // 6
	"GET_IO_BYTE",            // 7
	"SET_IO_BYTE",            // 8
	"WRITE_STRING",           // 9
	"READ_LINE",              // 10
	"CONSOLE_STATUS",         // 11
	"GET_VERSION",            // 12
	"RESET_DISKS",            // 13
	"SELECT_DISK",            // 14
	"OPEN_FILE",              // 15
	"CLOSE_FILE",             // 16
	"FIND_FIRST",             // 17
	"FIND_NEXT",              // 18
	"DELETE_FILE",            // 19
	"READ_SEQUENTIAL",        // 20
	"WRITE_SEQUENTIAL",       // 21
	"CREATE_FILE",            // 22
	"RENAME_FILE",            // 23
	"GET_LOGIN_BITMAP",       // 24
	"GET_CURRENT_DRIVE",      // 25
	"SET_DMA_ADDRESS",        // 26
	"GET_ALLOCATION_BITMAP",  // 27
	"SET_DRIVE_READONLY",     // 28
	"GET_READONLY_BITMAP",    // 29
	"SET_FILE_ATTRIBUTES",    // 30
	"GET_DPB",                // 31
	"GET_SET_USER_NUMBER",    // 32
	"READ_RANDOM",            // 33
	"WRITE_RANDOM",           // 34
	"COMPUTE_FILE_SIZE",      // 35
	"COMPUTE_RANDOM_POINTER", // 36
	"RESET_DISK",             // 37
	"GET_BIOS",               // 38
	"",                       // 39
	"WRITE_RANDOM_FILLED",    // 40
	"GETZP",                  // 41
	"GETTPA",                 // 42
}

func bdosCodeToName(code uint8) string {
	if code < uint8(len(cpm65BdosNames)) {
		return cpm65BdosNames[code]
	}
	return fmt.Sprintf("BDOS_%d", code)
}

func (t *traceCpm65) getCpmString(address uint16) string {
	s := ""
	for {
		ch := t.a.mmu.Peek(address)
		if ch == '$' {
			break
		}
		s += string(ch)
		address++
	}
	return s
}
