/******************************************************************************/
/* Mednafen - Multi-system Emulator                                           */
/******************************************************************************/
/* gfxdebugger.cpp:
**  Copyright (C) 2006-2020 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "main.h"
#include "gfxdebugger.h"
#include "debugger.h"
#include <trio/trio.h>

static MDFN_Surface *gd_surface = NULL;
static bool IsActive = 0;
static const char *LayerNames[16];
static int LayerScanline[16] = { 0 };
static int LayerScroll[16] = { 0 };
static int LayerPBN[16] = { 0 };
static int LayerCount = 0;
static int CurLayer = 0;

static void RedoSGD(bool instant = 0)
{
 CurGame->Debugger->SetGraphicsDecode(gd_surface, instant ? -1 : LayerScanline[CurLayer], CurLayer, 0, LayerScroll[CurLayer], LayerPBN[CurLayer]);
}

// Call this function from the game thread.
void GfxDebugger_SetActive(bool newia)
{
 if(CurGame->Debugger && CurGame->Debugger->SetGraphicsDecode && CurGame->LayerNames)
 {
  IsActive = newia;

  if(IsActive && !LayerCount)
  {
   LayerCount = 0;

   int clen;
   const char *lnp = CurGame->LayerNames;
   while((clen = strlen(lnp)))
   {
    LayerNames[LayerCount] = lnp;
    LayerCount++;
    lnp += clen + 1;
   }
  }

  if(!IsActive)
  {
   if(gd_surface)
   {
    delete gd_surface;
    gd_surface = NULL;
   }
  }
  else if(IsActive)
  {
   if(!gd_surface)
    gd_surface = new MDFN_Surface(NULL, 128, 128, 128 * 3, MDFN_PixelFormat::ABGR32_8888);
  }
  RedoSGD();
 }
}

#define MK_COLOR_A(r,g,b,a) (pf_cache.MakeColor(r, g, b, a))

// Call this function from the game thread
void GfxDebugger_Draw(MDFN_Surface *surface, const MDFN_Rect *rect, const MDFN_Rect *screen_rect)
{
 if(!IsActive)
  return;

 const MDFN_PixelFormat pf_cache = surface->format;
 uint32 *src_pixels;
 uint32 * pixels = surface->pixels;
 uint32 pitch32 = surface->pitchinpix;
 const bool ism = Debugger_GT_IsInSteppingMode();

 if(ism)
 {
  RedoSGD(TRUE);
 }

 if(gd_surface->format.Rshift != surface->format.Rshift || gd_surface->format.Gshift != surface->format.Gshift ||
  gd_surface->format.Bshift != surface->format.Bshift || gd_surface->format.Ashift != surface->format.Ashift ||
  gd_surface->format.colorspace != surface->format.colorspace)
 {
  //puts("Convert Meow");
  gd_surface->SetFormat(surface->format, TRUE);
 }

 src_pixels = gd_surface->pixels;

 if(!src_pixels)
 {
  
  return;
 }

 for(unsigned int y = 0; y < 128; y++)
 {
  uint32 *row = pixels + ((rect->w - 256) / 2) + y * pitch32 * 2;
  for(unsigned int x = 0; x < 128; x++)
  {
   //printf("%d %d %d\n", y, x, pixels);
   row[x*2] = row[x*2 + 1] = row[pitch32 + x*2] = row[pitch32 + x*2 + 1] = src_pixels[x + y * 128 * 3];
   //row[x] = MK_COLOR_A(0, 0, 0, 0xc0);
   //row[x] = MK_COLOR_A(0x00, 0x00, 0x00, 0x7F);
  }
 }


 // Draw layer name
 {
  for(int y = 256; y < 256 + 18; y++)
  {
   for(int x = 0; x < rect->w; x++)
   {
    pixels[y * pitch32 + x] = MK_COLOR_A(0x00, 0x00, 0x00, 0xC0);
   }
  }
  char buf[256];

  if(ism)
   trio_snprintf(buf, 256, "%s, PBN: %d, Scroll: %d, Instant", LayerNames[CurLayer], LayerPBN[CurLayer], LayerScroll[CurLayer]);
  else
   trio_snprintf(buf, 256, "%s, PBN: %d, Scroll: %d, Line: %d", LayerNames[CurLayer], LayerPBN[CurLayer], LayerScroll[CurLayer], LayerScanline[CurLayer]);
  DrawTextShadow(surface, 0, 256, buf, MK_COLOR_A(0xF0, 0xF0, 0xF0, 0xFF), MK_COLOR_A(0, 0, 0, 0xFF), MDFN_FONT_9x18_18x18, rect->w);
 }

 int mousex, mousey;
 SDL_GetMouseState(&mousex, &mousey);
 int vx, vy;

 vx = (mousex - screen_rect->x) * rect->w / screen_rect->w - ((rect->w - 256) / 2);
 vy = (mousey - screen_rect->y) * rect->h / screen_rect->h;

 vx /= 2;
 vy /= 2;

 if(vx < 128 && vy < 128 && vx >= 0 && vy >= 0)
 {
  if(src_pixels[vx + vy * 128 * 3] & (0xFF << surface->format.Ashift))
  {
   for(int y = 278; y < 278 + 18; y++)
    for(int x = 0; x < rect->w; x++)
    {
     pixels[y * pitch32 + x] = MK_COLOR_A(0x00, 0x00, 0x00, 0xC0);
    }
   char buf[256];

   trio_snprintf(buf, 256, "Tile: %08x, Address: %08x", src_pixels[128 + vx + vy * 128 * 3], src_pixels[256 + vx + vy * 128 * 3]);

   DrawTextShadow(surface, 0, 278, buf, MK_COLOR_A(0xF0, 0xF0, 0xF0, 0xFF), MK_COLOR_A(0, 0, 0, 0xFF), MDFN_FONT_9x18_18x18, rect->w);
  }
 }

 
}

// Call this from the game thread
int GfxDebugger_Event(const SDL_Event *event)
{
 if(!IsActive)
  return true;

 if(event->type == SDL_KEYDOWN)
 {
  switch(event->key.keysym.sym)
  {
   default:
	break;

   case SDLK_MINUS:
	if(LayerScanline[CurLayer])
	{
	 LayerScanline[CurLayer]--;
	 RedoSGD();
	}
	break;

   case SDLK_EQUALS:
	LayerScanline[CurLayer]++;
	RedoSGD();
	break;

   case SDLK_UP:
	if(LayerScroll[CurLayer])
	{
	 LayerScroll[CurLayer]--;
	 RedoSGD();
	}
	break;

   case SDLK_PAGEUP:
	LayerScroll[CurLayer] -= 8;
	if(LayerScroll[CurLayer] < 0)
	 LayerScroll[CurLayer] = 0;
	RedoSGD();
	break;

   case SDLK_PAGEDOWN:
	LayerScroll[CurLayer] += 8;
	RedoSGD();
	break;

   case SDLK_DOWN:
	LayerScroll[CurLayer]++;
	RedoSGD();
	break;

   case SDLK_LEFT:
	CurLayer = (CurLayer - 1);

	if(CurLayer < 0)
	 CurLayer = LayerCount - 1;

	RedoSGD();
	break;

   case SDLK_RIGHT:
	CurLayer = (CurLayer + 1) % LayerCount;
	RedoSGD();
	break;

   case SDLK_COMMA:
	if(LayerPBN[CurLayer] >= 0)
	 LayerPBN[CurLayer]--;
	RedoSGD();
	break;

   case SDLK_PERIOD:
	LayerPBN[CurLayer]++;
	RedoSGD();
	break;
  }
 }
 return true;
}

