// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <string>

#include "Common/MsgHandler.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/HW/DSPLLE/DSPDebugInterface.h"
#include "Core/HW/DSPLLE/DSPSymbols.h"

std::string DSPDebugInterface::Disassemble(unsigned int address)
{
  // we'll treat addresses as line numbers.
  return DSPSymbols::GetLineText(address);
}

void DSPDebugInterface::GetRawMemoryString(int memory, unsigned int address, char* dest,
                                           int max_size)
{
  if (DSPCore_GetState() == DSPCORE_STOP)
  {
    dest[0] = 0;
    return;
  }

  switch (memory)
  {
  case 0:  // IMEM
    switch (address >> 12)
    {
    case 0:
    case 0x8:
      sprintf(dest, "%04x", dsp_imem_read(address));
      break;
    default:
      sprintf(dest, "--IMEM--");
      break;
    }
    break;
  case 1:  // DMEM
    switch (address >> 12)
    {
    case 0:
    case 1:
      sprintf(dest, "%04x (DMEM)", dsp_dmem_read(address));
      break;
    case 0xf:
      sprintf(dest, "%04x (MMIO)", g_dsp.ifx_regs[address & 0xFF]);
      break;
    default:
      sprintf(dest, "--DMEM--");
      break;
    }
    break;
  }
}

unsigned int DSPDebugInterface::ReadMemory(unsigned int address)
{
  return 0;
}

unsigned int DSPDebugInterface::ReadInstruction(unsigned int address)
{
  return 0;
}

bool DSPDebugInterface::IsAlive()
{
  return true;  // Core::GetState() != Core::CORE_UNINITIALIZED;
}

bool DSPDebugInterface::IsBreakpoint(unsigned int address)
{
  int real_addr = DSPSymbols::Line2Addr(address);
  if (real_addr >= 0)
    return g_dsp_breakpoints.IsAddressBreakPoint(real_addr);

  return false;
}

void DSPDebugInterface::SetBreakpoint(unsigned int address)
{
  int real_addr = DSPSymbols::Line2Addr(address);

  if (real_addr >= 0)
  {
    if (g_dsp_breakpoints.Add(real_addr))
    {
    }
  }
}

void DSPDebugInterface::ClearBreakpoint(unsigned int address)
{
  int real_addr = DSPSymbols::Line2Addr(address);

  if (real_addr >= 0)
  {
    if (g_dsp_breakpoints.Remove(real_addr))
    {
    }
  }
}

void DSPDebugInterface::ClearAllBreakpoints()
{
  g_dsp_breakpoints.Clear();
}

void DSPDebugInterface::ToggleBreakpoint(unsigned int address)
{
  int real_addr = DSPSymbols::Line2Addr(address);
  if (real_addr >= 0)
  {
    if (g_dsp_breakpoints.IsAddressBreakPoint(real_addr))
      g_dsp_breakpoints.Remove(real_addr);
    else
      g_dsp_breakpoints.Add(real_addr);
  }
}

bool DSPDebugInterface::IsMemCheck(unsigned int address)
{
  return false;
}

void DSPDebugInterface::ClearAllMemChecks()
{
  PanicAlert("MemCheck functionality not supported in DSP module.");
}

void DSPDebugInterface::ToggleMemCheck(unsigned int address)
{
  PanicAlert("MemCheck functionality not supported in DSP module.");
}

void DSPDebugInterface::InsertBLR(unsigned int address, unsigned int value)
{
  PanicAlert("insertBLR functionality not supported in DSP module.");
}

// =======================================================
// Separate the blocks with colors.
// -------------
int DSPDebugInterface::GetColor(unsigned int address)
{
  static const int colors[6] = {
      0xd0FFFF,  // light cyan
      0xFFd0d0,  // light red
      0xd8d8FF,  // light blue
      0xFFd0FF,  // light purple
      0xd0FFd0,  // light green
      0xFFFFd0,  // light yellow
  };

  // Scan backwards so we don't miss it. Hm, actually, let's not - it looks pretty good.
  int addr = -1;
  for (int i = 0; i < 1; i++)
  {
    addr = DSPSymbols::Line2Addr(address - i);
    if (addr >= 0)
      break;
  }
  if (addr == -1)
    return 0xFFFFFF;

  Symbol* symbol = DSPSymbols::g_dsp_symbol_db.GetSymbolFromAddr(addr);
  if (!symbol)
    return 0xFFFFFF;
  if (symbol->type != Symbol::SYMBOL_FUNCTION)
    return 0xEEEEFF;
  return colors[symbol->index % 6];
}
// =============

std::string DSPDebugInterface::GetDescription(unsigned int address)
{
  return "";  // g_symbolDB.GetDescription(address);
}

unsigned int DSPDebugInterface::GetPC()
{
  return DSPSymbols::Addr2Line(g_dsp.pc);
}

void DSPDebugInterface::SetPC(unsigned int address)
{
  int new_pc = DSPSymbols::Line2Addr(address);
  if (new_pc > 0)
    g_dsp.pc = new_pc;
}

void DSPDebugInterface::RunToBreakpoint()
{
}
