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

#include "euterpe/find_wnd.h"
#include "euterpe/app_info.h"
#include "euterpe/playlist_wnd.h"

#include <string.h>
#include <stdlib.h>

#include "WDL/wdlstring.h"

#define RSE_PLAYLIST_QUERY 350
#define RSE_PLAYLIST_QUERY_MS 50

RSE_FindWnd::RSE_FindWnd()
  : m_hwnd(NULL)
  , m_edit(NULL)
  , m_focused_item(0)
  , m_last_query(0)
{}

RSE_FindWnd::~RSE_FindWnd()
{}

HWND RSE_FindWnd::Handle() const
{
  return m_hwnd;
}

WDL_DLGRET RSE_FindWnd::ST_FindWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
  RSE_FindWnd *self = (RSE_FindWnd *)GetWindowLongPtr(hwnd, GWLP_USERDATA);

  if (!self && msg == WM_INITDIALOG)
  {
    SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam);
    self = (RSE_FindWnd *)lparam;
    self->m_hwnd = hwnd;
  }

  if (self)
  {
    return self->FindWndProc(msg, wparam, lparam);
  }
  else
  {
    return 0;
  }
}

WDL_DLGRET RSE_FindWnd::FindWndProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
#if defined(__linux__)
  if (msg == WM_KEYDOWN && LOWORD(wparam) == VK_RETURN)
  {
    SendMessage(m_hwnd, WM_COMMAND, MAKEWPARAM(IDOK, 0), 0);
    return 0;
  }
#endif

  switch (msg)
  {
  case WM_INITDIALOG:
    {
      m_edit = GetDlgItem(m_hwnd, IDC_EDIT1);

      int x = g_ini_file->read_int("find_wnd_x", 0, EUTERPE_NAME);
      int y = g_ini_file->read_int("find_wnd_y", 50, EUTERPE_NAME);
      SetWindowPos(m_hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

      //PrevEditProc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(m_hwnd, IDC_EDIT1),
      //  GWLP_WNDPROC, (LONG_PTR)NewEditProc);

      g_playlist_wnd->GetSelected(&m_selected_items, &m_focused_item);
      g_playlist_wnd->SelectNone();

      SetTimer(m_hwnd, RSE_PLAYLIST_QUERY, RSE_PLAYLIST_QUERY_MS, NULL);
    }
    break;
  case WM_TIMER:
    {
      if (wparam == RSE_PLAYLIST_QUERY)
      {
        char text[2048];
        GetDlgItemText(m_hwnd, IDC_EDIT1, text, sizeof(text));

        int len = (int)strlen(text);

        if (m_last_query != len && m_edit == GetFocus())
        {
          m_last_query = (int)strlen(text);
          int found = g_playlist_wnd->Find(text);

          if (len > 0)
          {
            int cur, total, pl_index;
            g_playlist_wnd->InfoFind(&cur, &total, &pl_index);

            if (total > 0)
            {
              WDL_FastString strbuf;
              strbuf.SetFormatted(32, "Find | #%d %d:%d", pl_index, cur, total);
              SetWindowText(m_hwnd, strbuf.Get());
            }
            else
            {
              SetWindowText(m_hwnd, "Find | Zero");
            }
          }
          else
          {
            SetWindowText(m_hwnd, "Find");
          }
        }

        if (m_edit != GetFocus())
        {
          //SetDlgItemText(m_hwnd, IDC_EDIT1, "");
          //SetWindowText(m_hwnd, "Find");
          DestroyWindow(m_hwnd);
        }
      }
    }
    break;
  case WM_ERASEBKGND:
    {
      return 1;
    }
    break;
  case WM_MOVE:
    {

    }
    break;
  case WM_DESTROY:
    {
      KillTimer(m_hwnd, RSE_PLAYLIST_QUERY);

      RECT r;
      GetWindowRect(m_hwnd, &r);

      g_ini_file->write_int("find_wnd_x", r.left, EUTERPE_NAME);
      g_ini_file->write_int("find_wnd_y", r.top, EUTERPE_NAME);

      m_hwnd = NULL;
    }
    break;
  case WM_COMMAND:
    {
      switch(LOWORD(wparam))
      {
      case IDOK:
        {
          char text[2048];
          int cur, total, pl_index;
          GetDlgItemText(m_hwnd, IDC_EDIT1, text, sizeof(text));
          int len = (int)strlen(text);

          if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
          {
            g_playlist_wnd->InfoFind(&cur, &total, &pl_index);

            g_playlist_wnd->MarkFind();

            // If Find has no search string or no matches then
            // select the last known selection.
            if (!len || !total)
            {
              g_playlist_wnd->SetSelection(&m_selected_items, m_focused_item);
            }

            DestroyWindow(m_hwnd);
          }

          if (len > 0)
          {
            if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
            {
              g_playlist_wnd->PreviousFind();
            }
            else
            {
              g_playlist_wnd->NextFind();
            }
            g_playlist_wnd->InfoFind(&cur, &total, &pl_index);

            if (total > 0)
            {
              WDL_FastString strbuf;
              strbuf.SetFormatted(32, "Find | #%d %d:%d", pl_index, cur, total);
              SetWindowText(m_hwnd, strbuf.Get());
            }
            else
            {
              SetWindowText(m_hwnd, "Find | Zero");
            }
          }
          else
          {
            SetWindowText(m_hwnd, "Find");
          }
        }
        break;
      case IDCANCEL:
        {
          g_playlist_wnd->SetSelection(&m_selected_items, m_focused_item);
          DestroyWindow(m_hwnd);
        }
        break;
      }
    }
    break;
  }

  return 0;
}
