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

#include "euterpe/preferences_wnd.h"
#include "euterpe/main_wnd.h"
#include "euterpe/app_info.h"
#include "euterpe/plugin.h"

#include "WDL/wdlstring.h"

#define RSE_PREFERENCE_SETTINGS 600
#define RSE_PREFERENCE_SETTINGS_MS 50

static WDL_DLGRET LimitedViewProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
  switch (msg)
  {
  case WM_INITDIALOG:
    {} break;
  case WM_COMMAND:
    {
      switch (LOWORD(wparam))
      {
      case IDC_BUTTON1:
        {
          EnableWindow(GetDlgItem(hwnd, IDC_BUTTON1), FALSE);

          if (g_main_wnd->IsEngineOnline())
          {
            g_main_wnd->SetEngineOffline();
            wdl_log("preferences (stop): offline\n");
          }
        }
      }
    } break;
  }

  return 0;
}

RSE_PreferencesWnd::RSE_PreferencesWnd()
  : m_hwnd(NULL)
  , m_current_window(NULL)
  , m_hw_prop(NULL)
{}

RSE_PreferencesWnd::~RSE_PreferencesWnd()
{}

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

HTREEITEM RSE_PreferencesWnd::AddItem(HWND hwnd, HTREEITEM h, const char *str, int children, int data)
{
  HTREEITEM h2;
  TV_INSERTSTRUCT is = { h, TVI_LAST, {TVIF_PARAM | TVIF_TEXT | TVIF_CHILDREN,
    0, 0, 0, (char *)str, (int)strlen(str), 0, 0, children ? 1 : 0, data }};
  h2 = TreeView_InsertItem(hwnd, &is);

  if (m_last_page == data)
  {
    m_last_page_item = h2;
  }

  return h2;
}

/*
void DialogSelection(int page)
{


    for (int i = 0; i < dialogs.GetSize(); i++)
    {
        DialogInter *d = dialogs.Get(i);
        if (d->IsEnabled())
        {
            d->Destroy();
        }
    }

    WDL_ASSERT(page < dialogs.GetSize());
    WDL_ASSERT(page < dialogs_info.GetSize());
    WDL_ASSERT(dialogs.GetSize() == dialogs_info.GetSize());

    DialogInter *dlg = dialogs.Get(page);
    WDL_FastString *dlg_info = dialogs_info.Get(page);


    RECT r;
    GetWindowRect(GetDlgItem(m_hwnd, IDC_RECT), &r);
    ScreenToClient(m_hwnd, (LPPOINT)&r);
    dlg->SetParent(m_hwnd);
    dlg->Create();
    dlg->SetPos(NULL, r.left, r.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
    dlg->Show();

    SetDlgItemText(m_hwnd, IDC_STATIC_DESC, dlg_info->Get());

    int page_current = page + 1;
    int page_maximum = dialogs.GetSize();
    WDL_FastString page_num;
    page_num.SetFormatted(64, "%d/%d", page_current, page_maximum);

    SetDlgItemText(m_hwnd, IDC_STATIC_PAGE, page_num.Get());

    g_ini_file->write_int("m_last_page", page, "preferences");

}
*/

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

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

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

WDL_DLGRET RSE_PreferencesWnd::PreferencesWndProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
  switch (msg)
  {
  case WM_INITDIALOG:
    {
      WDL_FastString title(EUTERPE_NAME_MARKETING);
      title.Append(" preferences");
      SetWindowText(m_hwnd, title.Get());

      g_preference_settings = new RSE_Settings;
      g_preference_settings->SetHandle(m_hwnd, "preferences");

      int x = g_ini_file->read_int("preferences_wnd_x", 0, "preferences");
      int y = g_ini_file->read_int("preferences_wnd_y", 50, "preferences");
      SetWindowPos(m_hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);

      m_last_page = g_ini_file->read_int("last_page", 0, "preferences");

      HWND tree = GetDlgItem(m_hwnd, IDC_TREE1);

      WDL_String name;
      HTREEITEM item;
      AddItem(tree, TVI_ROOT, "General", 0, 0);

      bool has_media_library = false;

      for (int i = 0; i < g_plugin_import.GetSize(); i++)
      {
        if (!strncmp(g_plugin_import.Enumerate(i), "media_library", 13))
        {
          has_media_library = true;
          break;
        }
      }

      if (has_media_library)
      {
        item = AddItem(tree, TVI_ROOT, "Media library", 1, 1);

        //for (int i = 0; i < g_plugin_import.GetSize(); i++)
        //{
        //  if (!strncmp(g_plugin_import.Enumerate(i), "media_library", 12))
        //  {
        //    name.Set(g_plugin_import.Enumerate(i));

        //    name.DeleteSub(0, 14);

        //    AddItem(tree, item, name.Get(), 0, 1100 + i);
        //  }
        //}

        //TreeView_Expand(tree, item, TVE_EXPAND);
      }

      bool has_hw_output = false;

      for (int i = 0; i < g_plugin_import.GetSize(); i++)
      {
        if (!strncmp(g_plugin_import.Enumerate(i), "audio_device", 12))
        {
          has_hw_output = true;
          break;
        }
      }

      if (has_hw_output)
      {
        item = AddItem(tree, TVI_ROOT, "Audio system", 1, 2);

        for (int i = 0; i < g_plugin_import.GetSize(); i++)
        {
          if (!strncmp(g_plugin_import.Enumerate(i), "audio_device", 12))
          {
            name.Set(g_plugin_import.Enumerate(i));

            name.DeleteSub(0, 13);

            AddItem(tree, item, name.Get(), 0, 1200 + i);
          }
        }

        TreeView_Expand(tree, item, TVE_EXPAND);
      }

      AddItem(tree, TVI_ROOT, "Disk I/O", 0, 3);

      g_main_loop_mutex.Enter();
      bool is_playing = g_main_loop->IsPlaying();
      g_main_loop_mutex.Leave();

      if (!is_playing)
      {
        g_main_wnd->SetEngineOffline();
        wdl_log("preferences: offline\n");
      }

      TreeView_SelectItem(tree, m_last_page_item);
      SetFocus(tree);

      SetTimer(m_hwnd, RSE_PREFERENCE_SETTINGS, RSE_PREFERENCE_SETTINGS_MS, NULL);
      EnableWindow(GetDlgItem(m_hwnd, IDC_BUTTON3), FALSE);
    }
    break;
  case WM_TIMER:
    {
      if (wparam == RSE_PREFERENCE_SETTINGS)
      {
        if (g_preference_settings->HasSettings())
        {
          EnableWindow(GetDlgItem(m_hwnd, IDC_BUTTON3), TRUE);
        }
        else
        {
          EnableWindow(GetDlgItem(m_hwnd, IDC_BUTTON3), FALSE);
        }
      }
    }
    break;

  case WM_MOVE:
    {

    }
    break;

  case WM_DESTROY:
    {
      if (!g_main_wnd->IsEngineOnline())
      {
        g_main_wnd->SetEngineOnline();
        wdl_log("preferences: online\n");
      }

      KillTimer(m_hwnd, RSE_PREFERENCE_SETTINGS);

      RECT r;
      GetWindowRect(m_hwnd, &r);

      g_ini_file->write_int("preferences_wnd_x", r.left, "preferences");
      g_ini_file->write_int("preferences_wnd_y", r.top, "preferences");

      delete g_preference_settings;
      g_preference_settings = NULL;

      if (m_hw_prop)
      {
        delete m_hw_prop;
        m_hw_prop = NULL;
      }

      DestroyWindow(m_current_window);
      m_current_window = NULL;

      m_hwnd = NULL;
    }
    break;

  case WM_SYSCOMMAND:
    {
      if (LOWORD(wparam) == SC_CLOSE)
      {
        SendMessage(m_hwnd, WM_COMMAND, MAKEWPARAM(IDC_BUTTON2, 0), 0);
      }
    }
    break;

  case WM_NOTIFY:
    {
      NMTREEVIEW *p = (NMTREEVIEW *)lparam;

      if (p->hdr.code == TVN_SELCHANGED)
      {
        HTREEITEM tree_item = TreeView_GetSelection(GetDlgItem(m_hwnd, IDC_TREE1));
        TV_ITEM i = { TVIF_HANDLE, tree_item, 0, 0, 0, 0, 0 };
        TreeView_GetItem(GetDlgItem(m_hwnd, IDC_TREE1), &i);

        RECT r;

        if (m_current_window) DestroyWindow(m_current_window);

        if (m_hw_prop)
        {
          delete m_hw_prop;
          m_hw_prop = NULL;
        }

        // root || child
        // -------------
        //    0 -> 1000
        //    1 -> 1100
        //    2 -> 1200

        if (i.lParam == 0)
        {
          // General
          GetWindowRect(GetDlgItem(m_hwnd, IDC_RECT), &r);
          ScreenToClient(m_hwnd, (LPPOINT)&r);
          m_current_window = CreateDialogParam(g_inst,
            MAKEINTRESOURCE(IDD_PR_GENERAL),
            m_hwnd, RSE_GeneralWnd::ST_GeneralWndProc,
            (LPARAM)&m_gen_wnd);
          SetWindowPos(m_current_window, NULL, r.left, r.top, 0, 0,
            SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
          ShowWindow(m_current_window, SW_SHOWNA);
          g_ini_file->write_int("last_page", (int)i.lParam, "preferences");
        }
        else if (i.lParam == 1)
        {
          // Media library
          GetWindowRect(GetDlgItem(m_hwnd, IDC_RECT), &r);
          ScreenToClient(m_hwnd, (LPPOINT)&r);
          m_current_window = CreateDialogParam(g_inst,
            MAKEINTRESOURCE(IDD_PR_MEDIA_LIBRARY),
            m_hwnd, RSE_MediaLibraryWnd::ST_MediaLibraryWndProc,
            (LPARAM)&m_ml_wnd);
          SetWindowPos(m_current_window, NULL, r.left, r.top, 0, 0,
            SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
          ShowWindow(m_current_window, SW_SHOWNA);
          g_ini_file->write_int("last_page", (int)i.lParam, "preferences");
        }
        else if (i.lParam == 2)
        {
          // Audio system

          if (g_main_loop->IsPlaying())
          {
            GetWindowRect(GetDlgItem(m_hwnd, IDC_RECT), &r);
            ScreenToClient(m_hwnd, (LPPOINT)&r);
            m_current_window = CreateDialog(g_inst,
              MAKEINTRESOURCE(IDD_PR_LIMITED_VIEW),
              m_hwnd, LimitedViewProc);
            SetWindowPos(m_current_window, NULL, r.left, r.top, 0, 0,
              SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
            ShowWindow(m_current_window, SW_SHOWNA);
          }
          else
          {
            GetWindowRect(GetDlgItem(m_hwnd, IDC_RECT), &r);
            ScreenToClient(m_hwnd, (LPPOINT)&r);
            m_current_window = CreateDialogParam(g_inst,
              MAKEINTRESOURCE(IDD_PR_AUDIO_SYSTEM),
              m_hwnd, RSE_AudioSystemWnd::ST_AudioSystemWndProc,
              (LPARAM)&m_audio_system_wnd);
            SetWindowPos(m_current_window, NULL, r.left, r.top, 0, 0,
              SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
            ShowWindow(m_current_window, SW_SHOWNA);
          }

          g_ini_file->write_int("last_page", (int)i.lParam, "preferences");
        }
        else if (i.lParam >= 1000 && i.lParam < 1100)
        {
          // General properties
        }
        else if (i.lParam >= 1100 && i.lParam < 1200)
        {
          // Media library properties
        }
        else if (i.lParam >= 1200 && i.lParam < 1300)
        {
          // Audio streamer properties

          if (g_main_loop->IsPlaying())
          {
            GetWindowRect(GetDlgItem(m_hwnd, IDC_RECT), &r);
            ScreenToClient(m_hwnd, (LPPOINT)&r);
            m_current_window = CreateDialog(g_inst,
              MAKEINTRESOURCE(IDD_PR_LIMITED_VIEW),
              m_hwnd, LimitedViewProc);
            SetWindowPos(m_current_window, NULL, r.left, r.top, 0, 0,
              SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
            ShowWindow(m_current_window, SW_SHOWNA);
          }
          else
          {
            char text[2048];
            TVITEM tvi = { 0, };
            tvi.mask = TVIF_HANDLE | TVIF_TEXT;
            tvi.hItem = tree_item;
            tvi.pszText = text;
            tvi.cchTextMax = sizeof(text);

            TreeView_GetItem(GetDlgItem(m_hwnd, IDC_TREE1), &tvi);

            m_hw_prop = CreateAudioStreamerProperties(text);

            if (m_hw_prop)
            {
              GetWindowRect(GetDlgItem(m_hwnd, IDC_RECT), &r);
              ScreenToClient(m_hwnd, (LPPOINT)&r);
              m_hw_prop->PropertiesWindow(m_hwnd, r.left, r.top);
            }
          }

          g_ini_file->write_int("last_page", (int)i.lParam, "preferences");
        }
        else if (i.lParam == 3)
        {
          // Disk I/O
          GetWindowRect(GetDlgItem(m_hwnd, IDC_RECT), &r);
          ScreenToClient(m_hwnd, (LPPOINT)&r);
          m_current_window = CreateDialogParam(g_inst,
            MAKEINTRESOURCE(IDD_PR_DISK_IO),
            m_hwnd, RSE_DiskIOWnd::ST_DiskIOWndProc,
            (LPARAM)&m_diskio_wnd);
          SetWindowPos(m_current_window, NULL, r.left, r.top, 0, 0,
            SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
          ShowWindow(m_current_window, SW_SHOWNA);
          g_ini_file->write_int("last_page", (int)i.lParam, "preferences");
        }
      }
    }
    break;

  case WM_COMMAND:
    {
      switch (LOWORD(wparam))
      {
      case IDOK:
      case IDC_BUTTON1:
        {
          g_preference_settings->Apply();

          HWND list = GetDlgItem(g_playlist_wnd->Handle(), IDC_LIST1);
          int bgc = (0 << 16) | (0 << 8) | (0 << 0);
          bgc = g_ini_file->read_int("pl_bg_color", bgc, "preferences");
          int txtc = (192 << 16) | (192 << 8) | (192 << 0);
          txtc = g_ini_file->read_int("pl_txt_color", txtc, "preferences");
          ListView_SetBkColor(list, RGB((bgc >> 16) & 0xFF,
            (bgc >> 8) & 0xFF, (bgc >> 0) & 0xFF));
          ListView_SetTextBkColor(list, RGB((bgc >> 16) & 0xFF,
            (bgc >> 8) & 0xFF, (bgc >> 0) & 0xFF));
          ListView_SetTextColor(list, RGB((txtc >> 16) & 0xFF,
            (txtc >> 8) & 0xFF, (txtc >> 0) & 0xFF));
          InvalidateRect(list, NULL, FALSE);
          InvalidateRect(g_playlist_wnd->Handle(), NULL, FALSE);

          g_playlist_wnd->ApplyListViewColors(bgc, txtc); // should apply to all member dialogs

          DestroyWindow(m_hwnd);
        }
        break;

      case IDCANCEL:
      case IDC_BUTTON2:
        {
          g_preference_settings->DeleteAll();
          DestroyWindow(m_hwnd);
        }
        break;

      case IDC_BUTTON3:
        {
          g_preference_settings->Apply();

          HWND list = GetDlgItem(g_playlist_wnd->Handle(), IDC_LIST1);
          int bgc = (0 << 16) | (0 << 8) | (0 << 0);
          bgc = g_ini_file->read_int("pl_bg_color", bgc, "preferences");
          int txtc = (192 << 16) | (192 << 8) | (192 << 0);
          txtc = g_ini_file->read_int("pl_txt_color", txtc, "preferences");
          ListView_SetBkColor(list, RGB((bgc >> 16) & 0xFF,
            (bgc >> 8) & 0xFF, (bgc >> 0) & 0xFF));
          ListView_SetTextBkColor(list, RGB((bgc >> 16) & 0xFF,
            (bgc >> 8) & 0xFF, (bgc >> 0) & 0xFF));
          ListView_SetTextColor(list, RGB((txtc >> 16) & 0xFF,
            (txtc >> 8) & 0xFF, (txtc >> 0) & 0xFF));
          InvalidateRect(list, NULL, FALSE);
          InvalidateRect(g_playlist_wnd->Handle(), NULL, FALSE);

          g_playlist_wnd->ApplyListViewColors(bgc, txtc); // should apply to all member dialogs
        }
        break;
      }
    }
    break;
  }

  return 0;
}
