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

#include "euterpe/pr_disk_io_wnd.h"
#include "euterpe/main_wnd.h"

#include "WDL/win32_utf8.h"
#include "WDL/wdlstring.h"
#include "WDL/heapbuf.h"

RSE_DiskIOWnd::RSE_DiskIOWnd()
  : m_hwnd(NULL)
{}

RSE_DiskIOWnd::~RSE_DiskIOWnd()
{}

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

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

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

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

void RSE_DiskIOWnd::OnInitDialog()
{
  int readmode = g_ini_file->read_int("read_mode", 2, "preferences");
  int readbuffer = g_ini_file->read_int("read_buffer", 262144, "preferences");
  int readbuffers = g_ini_file->read_int("read_buffers", 3, "preferences");
  int writemode = g_ini_file->read_int("write_mode", 1, "preferences");
  int writebuffer = g_ini_file->read_int("write_buffer", 65536, "preferences");
  int minwritebuffers = g_ini_file->read_int("min_write_buffers", 16, "preferences");
  int maxwritebuffers = g_ini_file->read_int("max_write_buffers", 128, "preferences");

  // 1: Asynchronous unbuffered
  // 2: Asynchronous buffered
  // -1: Synchronous unbuffered
  HWND diskreadmode = GetDlgItem(m_hwnd, IDC_COMBO1);
  SendMessage(diskreadmode, CB_ADDSTRING, 0, (LPARAM)"Asynchronous unbuffered");
  SendMessage(diskreadmode, CB_SETITEMDATA, 0, 1);
  SendMessage(diskreadmode, CB_ADDSTRING, 0, (LPARAM)"Asynchronous buffered (default)");
  SendMessage(diskreadmode, CB_SETITEMDATA, 1, 2);
  SendMessage(diskreadmode, CB_ADDSTRING, 0, (LPARAM)"Synchronous unbuffered");
  SendMessage(diskreadmode, CB_SETITEMDATA, 2, -1);

  switch (readmode)
  {
    case 1: SendMessage(diskreadmode, CB_SETCURSEL, 0, 0); break;
    case 2: SendMessage(diskreadmode, CB_SETCURSEL, 1, 0); break;
    case -1: SendMessage(diskreadmode, CB_SETCURSEL, 2, 0); break;
    default: SendMessage(diskreadmode, CB_SETCURSEL, 1, 0); break;
  }

  WDL_FastString strbuf;

  strbuf.SetFormatted(128, "%d", readbuffer);
  HWND ed = GetDlgItem(m_hwnd, IDC_EDIT1);
  SetWindowText(ed, strbuf.Get());

  strbuf.SetFormatted(128, "%d", readbuffers);
  ed = GetDlgItem(m_hwnd, IDC_EDIT2);
  SetWindowText(ed, strbuf.Get());

  // 1: Asynchronous buffered
  // 2: Asynchronous write-through
  // 3: Asynchronous unbuffered
  // 0: Synchronous
  HWND diskwritemode = GetDlgItem(m_hwnd, IDC_COMBO2);
  SendMessage(diskwritemode, CB_ADDSTRING, 0, (LPARAM)"Asynchronous buffered (default)");
  SendMessage(diskwritemode, CB_SETITEMDATA, 0, 1);
  SendMessage(diskwritemode, CB_ADDSTRING, 0, (LPARAM)"Asynchronous write-through");
  SendMessage(diskwritemode, CB_SETITEMDATA, 1, 2);
  SendMessage(diskwritemode, CB_ADDSTRING, 0, (LPARAM)"Asynchronous unbuffered");
  SendMessage(diskwritemode, CB_SETITEMDATA, 2, 3);
  SendMessage(diskwritemode, CB_ADDSTRING, 0, (LPARAM)"Synchronous");
  SendMessage(diskwritemode, CB_SETITEMDATA, 3, 0);

  switch (writemode)
  {
    case 1: SendMessage(diskwritemode, CB_SETCURSEL, 0, 0); break;
    case 2: SendMessage(diskwritemode, CB_SETCURSEL, 1, 0); break;
    case 3: SendMessage(diskwritemode, CB_SETCURSEL, 2, 0); break;
    case 0: SendMessage(diskwritemode, CB_SETCURSEL, 3, 0); break;
    default: SendMessage(diskwritemode, CB_SETCURSEL, 0, 0); break;
  }

  strbuf.SetFormatted(128, "%d", writebuffer);
  ed = GetDlgItem(m_hwnd, IDC_EDIT3);
  SetWindowText(ed, strbuf.Get());

  strbuf.SetFormatted(128, "%d", minwritebuffers);
  ed = GetDlgItem(m_hwnd, IDC_EDIT4);
  SetWindowText(ed, strbuf.Get());

  strbuf.SetFormatted(128, "%d", maxwritebuffers);
  ed = GetDlgItem(m_hwnd, IDC_EDIT5);
  SetWindowText(ed, strbuf.Get());
}

void RSE_DiskIOWnd::OnDestroy()
{
  m_hwnd = NULL;
}

void RSE_DiskIOWnd::OnCommand()
{
  switch(LOWORD(m_wparam))
  {
  case IDC_COMBO1:
    {
      if (HIWORD(m_wparam) == CBN_SELCHANGE)
      {
        HWND diskreadmode = GetDlgItem(m_hwnd, IDC_COMBO1);
        int sel = (int)SendMessage(diskreadmode, CB_GETCURSEL, 0, 0);
        int readmode = (int)SendMessage(diskreadmode, CB_GETITEMDATA, sel, 0);

        g_preference_settings->Set("read_mode", readmode);
      }
    }
    break;
  case IDC_COMBO2:
    {
      if (HIWORD(m_wparam) == CBN_SELCHANGE)
      {
        HWND diskwritemode = GetDlgItem(m_hwnd, IDC_COMBO2);
        int sel = (int)SendMessage(diskwritemode, CB_GETCURSEL, 0, 0);
        int writemode = (int)SendMessage(diskwritemode, CB_GETITEMDATA, sel, 0);

        g_preference_settings->Set("write_mode", writemode);
      }
    }
    break;
  case IDC_EDIT1:
    {
      if (HIWORD(m_wparam) == EN_CHANGE)
      {
        BOOL ok;
        int val = GetDlgItemInt(m_hwnd, IDC_EDIT1, &ok, TRUE);
        g_preference_settings->Set("read_buffer", val);
      }
    }
    break;
  case IDC_EDIT2:
    {
      if (HIWORD(m_wparam) == EN_CHANGE)
      {
        BOOL ok;
        int val = GetDlgItemInt(m_hwnd, IDC_EDIT2, &ok, TRUE);
        g_preference_settings->Set("read_buffers", val);
      }
    }
    break;
  case IDC_EDIT3:
    {
      if (HIWORD(m_wparam) == EN_CHANGE)
      {
        BOOL ok;
        int val = GetDlgItemInt(m_hwnd, IDC_EDIT3, &ok, TRUE);
        g_preference_settings->Set("write_buffer", val);
      }
    }
    break;
  case IDC_EDIT4:
    {
      if (HIWORD(m_wparam) == EN_CHANGE)
      {
        BOOL ok;
        int val = GetDlgItemInt(m_hwnd, IDC_EDIT4, &ok, TRUE);
        g_preference_settings->Set("min_write_buffers", val);
      }
    }
    break;
  case IDC_EDIT5:
    {
      if (HIWORD(m_wparam) == EN_CHANGE)
      {
        BOOL ok;
        int val = GetDlgItemInt(m_hwnd, IDC_EDIT5, &ok, TRUE);
        g_preference_settings->Set("max_write_buffers", val);
      }
    }
    break;
  }
}

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

  switch(msg)
  {
    case WM_INITDIALOG: OnInitDialog(); break;
    case WM_DESTROY: OnDestroy(); break;
    case WM_COMMAND: OnCommand(); break;
  }

  return 0;
}
