/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2024, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include "img-precomp.h"  // Precompiled headers
//
#include <mrpt/config.h>
#include <mrpt/img/CEnhancedMetaFile.h>
#include <mrpt/img/CImage.h>
#include <mrpt/system/os.h>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

using namespace mrpt;
using namespace mrpt::img;
using namespace mrpt::system;

static int LINUX_IMG_WIDTH_value = 800;
static int LINUX_IMG_HEIGHT_value = 600;

void CEnhancedMetaFile::LINUX_IMG_WIDTH(int value) { LINUX_IMG_WIDTH_value = value; }
int CEnhancedMetaFile::LINUX_IMG_WIDTH() { return LINUX_IMG_WIDTH_value; }
void CEnhancedMetaFile::LINUX_IMG_HEIGHT(int value) { LINUX_IMG_HEIGHT_value = value; }
int CEnhancedMetaFile::LINUX_IMG_HEIGHT() { return LINUX_IMG_HEIGHT_value; }
/*---------------------------------------------------------------
            Constructor
---------------------------------------------------------------*/
CEnhancedMetaFile::CEnhancedMetaFile(const std::string& targetFileName, int scaleFactor) :
    m_scale(scaleFactor), m_targetFile(targetFileName)
{
#ifdef _WIN32
  m_hdc = CreateEnhMetaFileA(nullptr, targetFileName.c_str(), nullptr, nullptr);
  if (!m_hdc.get()) THROW_EXCEPTION("Can't create EMF file!!!");
#else
  m_hdc = (void*)new CImage(LINUX_IMG_WIDTH_value, LINUX_IMG_HEIGHT_value);
  ((CImage*)m_hdc.get())
      ->filledRectangle(
          0, 0, LINUX_IMG_WIDTH_value - 1, LINUX_IMG_HEIGHT_value - 1, TColor(0, 0, 0));
#endif
}

/*---------------------------------------------------------------
            Destructor
---------------------------------------------------------------*/
CEnhancedMetaFile::~CEnhancedMetaFile()
{
#ifdef _WIN32
  // Free objects:
  if (m_hFont.get())
  {
    DeleteObject(m_hFont.get());
    m_hFont = nullptr;
  }

  // Finish EMF:
  DeleteEnhMetaFile(CloseEnhMetaFile((HDC)m_hdc.get()));
#else
  bool ok = ((CImage*)m_hdc.get())->saveToFile(m_targetFile + ".png");
  if (!ok) std::cerr << "Error saving image to file: " << m_targetFile << std::endl;

  // Free objects:
  delete ((CImage*)m_hdc.get());
#endif
}

/*---------------------------------------------------------------
            drawImage
---------------------------------------------------------------*/
void CEnhancedMetaFile::drawImage(int x, int y, const mrpt::img::CImage& img)
{
#ifdef _WIN32
  try
  {
    LPBITMAPINFO pBmpInfo =
        (LPBITMAPINFO) new unsigned char[sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD))];
    //		LPBITMAPINFO		pBmpInfo = (LPBITMAPINFO) new unsigned
    // char[sizeof(BITMAPINFOHEADER) ];

    unsigned int imgWidth = (unsigned int)img.getWidth();
    unsigned int imgHeight = (unsigned int)img.getHeight();

    pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pBmpInfo->bmiHeader.biWidth = imgWidth;
    pBmpInfo->bmiHeader.biHeight = imgHeight;
    pBmpInfo->bmiHeader.biPlanes = 1;
    //		pBmpInfo->bmiHeader.biBitCount		= 24;
    pBmpInfo->bmiHeader.biBitCount = 8;
    pBmpInfo->bmiHeader.biCompression = BI_RGB;
    pBmpInfo->bmiHeader.biSizeImage = 0;
    pBmpInfo->bmiHeader.biXPelsPerMeter = pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
    pBmpInfo->bmiHeader.biClrUsed = 0;
    pBmpInfo->bmiHeader.biClrImportant = 0;

    // Palette
    for (unsigned char i = 0; i < 255; i++)
    {
      pBmpInfo->bmiColors[i].rgbRed = i;
      pBmpInfo->bmiColors[i].rgbGreen = i;
      pBmpInfo->bmiColors[i].rgbBlue = i;
      pBmpInfo->bmiColors[i].rgbReserved = 0;
    }

    //		unsigned int	lineBytes = 3*bmp.Width;
    unsigned int lineBytes = imgWidth;
    if (lineBytes % 2) lineBytes++;
    if (lineBytes % 4) lineBytes += 2;

    BYTE* ptrBits = new BYTE[lineBytes * imgHeight];

    for (unsigned int py = 0; py < imgHeight; py++)
      for (unsigned int px = 0; px < imgWidth; px++)
        ptrBits[(py * lineBytes + px) + 0] = *img(px, py);

    HBITMAP hBitmap = CreateDIBitmap(
        (HDC)m_hdc.get(), &pBmpInfo->bmiHeader, CBM_INIT, ptrBits, pBmpInfo, DIB_RGB_COLORS);

    ASSERT_(hBitmap != nullptr);

    BITMAP bm;
    GetObject(hBitmap, sizeof(bm), &bm);

    HDC hdcMem = CreateCompatibleDC((HDC)m_hdc.get());
    HBITMAP hbmT = (HBITMAP)SelectObject(hdcMem, hBitmap);

    BitBlt(
        (HDC)m_hdc.get(), x, y, (int)(m_scale * imgWidth), (int)(m_scale * imgHeight), hdcMem, 0, 0,
        SRCCOPY);

    SelectObject(hdcMem, hbmT);
    DeleteDC(hdcMem);

    // Free mem:
    // ---------------------------------------
    DeleteObject(hBitmap);
    delete[] pBmpInfo;
    delete[] ptrBits;
  }
  catch (...)
  {
    THROW_EXCEPTION("Unexpected runtime error!!");
  }
#else
  ((CImage*)m_hdc.get())->drawImage(x, y, img);
#endif
}

/*---------------------------------------------------------------
            drawBitmap
---------------------------------------------------------------*/
void CEnhancedMetaFile::line(
    int x0,
    int y0,
    int x1,
    int y1,
    const mrpt::img::TColor color,
    unsigned int width,
    TPenStyle penStyle)
{
#ifdef _WIN32
  x0 *= m_scale;
  y0 *= m_scale;
  x1 *= m_scale;
  y1 *= m_scale;

  HPEN hPen = CreatePen(penStyle, width, (unsigned int)color);

  HPEN hOldPen = (HPEN)SelectObject((HDC)m_hdc.get(), hPen);

  MoveToEx((HDC)m_hdc.get(), x0, y0, nullptr);
  LineTo((HDC)m_hdc.get(), x1, y1);

  SelectObject((HDC)m_hdc.get(), hOldPen);
  DeleteObject(hPen);
#else
  ((CImage*)m_hdc.get())->line(x0, y0, x1, y1, color, width, penStyle);
#endif
}

/*---------------------------------------------------------------
            drawBitmap
---------------------------------------------------------------*/
void CEnhancedMetaFile::textOut(
    int x0, int y0, const std::string& str, const mrpt::img::TColor color)
{
#ifdef _WIN32
  x0 *= m_scale;
  y0 *= m_scale;

  ::SetBkMode((HDC)m_hdc.get(), TRANSPARENT);
  ::SetTextColor((HDC)m_hdc.get(), (unsigned int)color);

  ::TextOutA((HDC)m_hdc.get(), x0, y0, str.c_str(), (int)str.size());
#else
  ((CImage*)m_hdc.get())->textOut(x0, y0, str, color);
#endif
}

/*---------------------------------------------------------------
          selectVectorTextFont
---------------------------------------------------------------*/
void CEnhancedMetaFile::selectVectorTextFont(
    [[maybe_unused]] const std::string& fontName,
    [[maybe_unused]] int fontSize,
    [[maybe_unused]] bool bold,
    [[maybe_unused]] bool italic)
{
#ifdef _WIN32
  HFONT hFont, oldFont;
  LOGFONTA lpf;

  lpf.lfHeight = fontSize;
  lpf.lfWidth = 0;
  lpf.lfEscapement = 0;
  lpf.lfOrientation = 0;
  lpf.lfWeight = bold ? 700 : 400;
  lpf.lfItalic = italic ? 1 : 0;
  lpf.lfUnderline = 0;
  lpf.lfStrikeOut = 0;
  lpf.lfCharSet = DEFAULT_CHARSET;
  lpf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  lpf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  lpf.lfQuality = DEFAULT_QUALITY;
  lpf.lfPitchAndFamily = DEFAULT_PITCH;
  os::strcpy(lpf.lfFaceName, LF_FACESIZE, fontName.c_str());

  hFont = ::CreateFontIndirectA(&lpf);

  oldFont = (HFONT)::SelectObject((HDC)m_hdc.get(), hFont);

  if (oldFont) ::DeleteObject(oldFont);
#else
  MRPT_TRY_START;

  ((CImage*)m_hdc.get())->selectTextFont(fontName);

  MRPT_TRY_END;
#endif
}

/*---------------------------------------------------------------
          setPixel
---------------------------------------------------------------*/
void CEnhancedMetaFile::setPixel(int x, int y, size_t color)
{
#ifdef _WIN32
  ::SetPixel((HDC)m_hdc.get(), x * m_scale, y * m_scale, color);
#else
  ((CImage*)m_hdc.get())->setPixel(x, y, color);
#endif
}

/*---------------------------------------------------------------
            rectangle
---------------------------------------------------------------*/
void CEnhancedMetaFile::rectangle(int x0, int y0, int x1, int y1, TColor color, unsigned int width)
{
  line(x0, y0, x1, y0, color, width);
  line(x1, y0, x1, y1, color, width);
  line(x1, y1, x0, y1, color, width);
  line(x0, y1, x0, y0, color, width);
}
