// Copyright (c) 2022 Giorgos Vougioukas
//
// The license can be found in the LICENSE file.

#include "RSI/waveform_wnd.h"
#include "RSI/track.h"

static LOGFONT lf =
{
#if defined(_WIN32)
  20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
  OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
  "Arial"
#else
  17, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
  OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
  "Arial"
#endif
};

void RSI_WaveformAWnd::OnCreate()
{
  WDL_ASSERT(g_trackwnds.GetSize());
  m_trkidx = g_trackwnds.GetSize();
  m_sltidx = g_trackwnds.GetSize() - 1;
}

void RSI_WaveformAWnd::OnDestroy()
{}

void RSI_WaveformAWnd::OnPaint()
{
  int xo, yo;
  m_painter.PaintBegin(m_hwnd, RGB(51, 51, 51));
  m_bm = m_painter.GetBuffer(&xo, &yo);
  //LICE_Clear(m_bm, LICE_RGBA((m_bgc >> 16) & 0xFF,
  //  (m_bgc >> 8) & 0xFF, m_bgc & 0xFF, 255));

  RSI_DataBankSlot *dbs = g_databank->GetSlot(m_sltidx);

  if (dbs)
  {
    RECT r;
    GetClientRect(m_hwnd, &r);
    int w = r.right - r.left;
    int h = r.bottom - r.top;
    dbs->SetWaveformA(w, h);

    LICE_IBitmap *bm;
    int peakpoints;
    dbs->GetWaveformA(&bm, &peakpoints);
    if (bm)
    {
      double pos;

      RSI_Track *trk = g_tracks.Get(m_trkidx, NULL);
      if (trk)
      {
        pos = trk->GetTime();
        int posoffset = (int)(pos * peakpoints);

        LICE_Blit(m_bm, bm, 0, 0, posoffset - (w / 2), 0, w / 2, h, 1.0f, LICE_BLIT_MODE_COPY);
        LICE_Blit(m_bm, bm, w / 2, 0, posoffset, 0, w / 2, h, 1.0f, LICE_BLIT_MODE_COPY);
        LICE_Line(m_bm, w / 2, 0, w / 2, h, LICE_RGBA(255, 0, 0, 255));
      }
    }
  }

  m_painter.PaintEnd();
}

void RSI_WaveformAWnd::OnLButtonDown()
{
  g_rendersystem->SetActiveTrack(m_trkidx);
}

void RSI_WaveformAWnd::OnLButtonUp()
{

}

void RSI_WaveformAWnd::OnMouseMove()
{

}

void RSI_WaveformAWnd::OnSize()
{
  //InvalidateRect(m_hwnd, NULL, FALSE);
}

void RSI_WaveformAWnd::OnTimer()
{}

WDL_DLGRET RSI_WaveformAWnd::WaveformAWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
  RSI_WaveformAWnd *wfa = (RSI_WaveformAWnd *)GetWindowLongPtr(hwnd, GWLP_USERDATA);

#if _WIN32
  if (!wfa && msg == WM_NCCREATE)
#else
  if (!wfa && msg == WM_CREATE)
#endif
  {
    wfa = new RSI_WaveformAWnd(hwnd);
    SetWindowLongPtr(hwnd, GWLP_USERDATA, (INT_PTR)wfa);
#ifndef _WIN32
    //SWELL_SetClassName(hwnd, "waveforma_superhost");
#endif
    if (wfa) wfa->OnCreate();
    return (wfa != NULL);
  }

#if _WIN32
  if (wfa && msg == WM_NCDESTROY)
#else
  if (wfa && msg == WM_DESTROY)
#endif
  {
    wfa->OnDestroy();
    delete wfa; wfa = NULL;
  }

  if (wfa)
  {
    return wfa->WaveformAWndLoop(msg, wparam, lparam);
  }

  return 0;
}

WDL_DLGRET RSI_WaveformAWnd::WaveformAWndLoop(UINT msg, WPARAM wparam, LPARAM lparam)
{
  m_msg = msg;
  m_wparam = wparam;
  m_lparam = lparam;

  switch (msg)
  {
#if _WIN32
    case WM_NCCREATE: OnCreate(); break;
    case WM_NCDESTROY: OnDestroy(); break;
#else
    case WM_CREATE: OnCreate(); break;
    case WM_DESTROY: OnDestroy(); break;
#endif
    case WM_PAINT: OnPaint(); break;
    case WM_LBUTTONDOWN: OnLButtonDown(); break;
    case WM_LBUTTONUP: OnLButtonUp(); break;
    case WM_MOUSEMOVE: OnMouseMove(); break;
    case WM_SIZE: OnSize(); break;
    case WM_TIMER: OnTimer(); break;
  }

  return DefWindowProc(m_hwnd, msg, wparam, lparam);
}



void RSI_WaveformBWnd::OnCreate()
{
  WDL_ASSERT(g_trackwnds.GetSize());
  m_trkidx = g_trackwnds.GetSize();
  m_sltidx = g_trackwnds.GetSize() - 1;
}

void RSI_WaveformBWnd::OnDestroy()
{}

void RSI_WaveformBWnd::OnPaint()
{
  int xo, yo;
  m_painter.PaintBegin(m_hwnd, RGB(51, 51, 51));
  m_bm = m_painter.GetBuffer(&xo, &yo);
  //LICE_Clear(m_bm, LICE_RGBA((m_bgc >> 16) & 0xFF,
  //  (m_bgc >> 8) & 0xFF, m_bgc & 0xFF, 255));

  RSI_DataBankSlot *dbs = g_databank->GetSlot(m_sltidx);

  if (dbs)
  {
    RECT r;
    GetClientRect(m_hwnd, &r);
    int w = r.right - r.left;
    int h = r.bottom - r.top;
    dbs->SetWaveformB(w, h);

    LICE_IBitmap *bm;
    int peakpoints;
    dbs->GetWaveformB(&bm, &peakpoints);
    if (bm)
    {
      double pos, len;

      RSI_Track *trk = g_tracks.Get(m_trkidx, NULL);
      if (trk)
      {
        pos = trk->GetTime(); len = trk->GetTotalTime();
        int linepos = (int)(pos * (w / len));

        LICE_Blit(m_bm, bm, 0, 0, 0, 0, bm->getWidth(), bm->getHeight(), 1.0f, LICE_BLIT_MODE_COPY);
        LICE_Line(m_bm, linepos, 0, linepos, h, LICE_RGBA(255, 0, 0, 255));

        if (m_seekpos > 0 && m_seekpos < w)
        {
          int curmin, cursec, tw, th;
          curmin = (int)m_seektime / 60;
          cursec = (int)m_seektime % 60;
          m_strbuf.SetFormatted(64, "%01d:%02d", curmin, cursec);
          LICE_MeasureText(m_strbuf.Get(), &tw, &th);
          if (m_seekpos < w / 2)
          {
            LICE_Line(m_bm, m_seekpos, 0, m_seekpos, h, LICE_RGBA(0, 255, 0, 255));
            LICE_DrawText(m_bm, m_seekpos + 2, 0, m_strbuf.Get(),
              LICE_RGBA(0, 255, 0, 255), 1.0f, LICE_BLIT_MODE_COPY);
          }
          else
          {
            LICE_Line(m_bm, m_seekpos, 0, m_seekpos, h, LICE_RGBA(0, 255, 0, 255));
            LICE_DrawText(m_bm, m_seekpos - 2 - tw, 0, m_strbuf.Get(),
              LICE_RGBA(0, 255, 0, 255), 1.0f, LICE_BLIT_MODE_COPY);
          }
        }
        else if (m_seekpos == 0)
        {
          m_strbuf.SetFormatted(64, "%01d:%02d", 0, 0);
          LICE_Line(m_bm, m_seekpos, 0, m_seekpos, h, LICE_RGBA(0, 255, 0, 255));
          LICE_DrawText(m_bm, m_seekpos + 2, 0, m_strbuf.Get(),
            LICE_RGBA(0, 255, 0, 255), 1.0f, LICE_BLIT_MODE_COPY);
        }
        else if (m_seekpos == w)
        {
          m_seekpos -= 1;
          int curmin, cursec, tw, th;
          curmin = (int)m_seektime / 60;
          cursec = (int)m_seektime % 60;
          m_strbuf.SetFormatted(64, "%01d:%02d", curmin, cursec);
          LICE_MeasureText(m_strbuf.Get(), &tw, &th);
          LICE_Line(m_bm, m_seekpos, 0, m_seekpos, h, LICE_RGBA(0, 255, 0, 255));
          LICE_DrawText(m_bm, m_seekpos - 2 - tw, 0, m_strbuf.Get(),
            LICE_RGBA(0, 255, 0, 255), 1.0f, LICE_BLIT_MODE_COPY);
        }
      }
    }
  }

  m_painter.PaintEnd();
}

void RSI_WaveformBWnd::OnLButtonDown()
{
  g_rendersystem->SetActiveTrack(m_trkidx);

  POINT pt; RECT r;
  GetCursorPos(&pt);
  ScreenToClient(m_hwnd, &pt);
  GetClientRect(m_hwnd, &r);

  RSI_Track *trk = g_tracks.Get(m_trkidx, NULL);
  if (trk)
  {
    double len = trk->GetTotalTime();
    m_seektime = (double)pt.x * len / (double)r.right;
    m_seektime = wdl_clamp(m_seektime, 0.0, len);
    m_seekpos = (int)(m_seektime * (r.right / len));
  }

  SetCapture(m_hwnd);
}

void RSI_WaveformBWnd::OnLButtonUp()
{
  if (GetCapture() == m_hwnd)
  {
    if (!g_rendersystem->IsTrackActive())
    {
      g_rendersystem->Play();
      g_rendersystem->Pause();
    }
    g_rendersystem->Seek(m_seektime);
    m_seektime = 0.0;
    m_seekpos = -1;
    ReleaseCapture();
  }
}

void RSI_WaveformBWnd::OnMouseMove()
{
  if (GetCapture() == m_hwnd)
  {
    POINT pt; RECT r;
    GetCursorPos(&pt);
    ScreenToClient(m_hwnd, &pt);
    GetClientRect(m_hwnd, &r);

    RSI_Track *trk = g_tracks.Get(m_trkidx, NULL);
    if (trk)
    {
      double len = trk->GetTotalTime();
      m_seektime = (double)pt.x * len / (double)r.right;
      m_seektime = wdl_clamp(m_seektime, 0.0, len);
      m_seekpos = (int)(m_seektime * (r.right / len));
    }
  }
}

void RSI_WaveformBWnd::OnSize()
{
  //InvalidateRect(m_hwnd, NULL, FALSE);
}

void RSI_WaveformBWnd::OnTimer()
{}

WDL_DLGRET RSI_WaveformBWnd::WaveformBWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
  RSI_WaveformBWnd *wfb = (RSI_WaveformBWnd *)GetWindowLongPtr(hwnd, GWLP_USERDATA);

#if _WIN32
  if (!wfb && msg == WM_NCCREATE)
#else
  if (!wfb && msg == WM_CREATE)
#endif
  {
    wfb = new RSI_WaveformBWnd(hwnd);
    SetWindowLongPtr(hwnd, GWLP_USERDATA, (INT_PTR)wfb);
#ifndef _WIN32
    //SWELL_SetClassName(hwnd, "waveformb_superhost");
#endif
    if (wfb) wfb->OnCreate();
    return (wfb != NULL);
  }

#if _WIN32
  if (wfb && msg == WM_NCDESTROY)
#else
  if (wfb && msg == WM_DESTROY)
#endif
  {
    wfb->OnDestroy();
    delete wfb; wfb = NULL;
  }

  if (wfb)
  {
    return wfb->WaveformBWndLoop(msg, wparam, lparam);
  }

  return 0;
}

WDL_DLGRET RSI_WaveformBWnd::WaveformBWndLoop(UINT msg, WPARAM wparam, LPARAM lparam)
{
  m_msg = msg;
  m_wparam = wparam;
  m_lparam = lparam;

  switch (msg)
  {
#if _WIN32
    case WM_NCCREATE: OnCreate(); break;
    case WM_NCDESTROY: OnDestroy(); break;
#else
    case WM_CREATE: OnCreate(); break;
    case WM_DESTROY: OnDestroy(); break;
#endif
    case WM_PAINT: OnPaint(); break;
    case WM_LBUTTONDOWN: OnLButtonDown(); break;
    case WM_LBUTTONUP: OnLButtonUp(); break;
    case WM_MOUSEMOVE: OnMouseMove(); break;
    case WM_SIZE: OnSize(); break;
    case WM_TIMER: OnTimer(); break;
  }

  return DefWindowProc(m_hwnd, msg, wparam, lparam);
}
