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

#include "RSI/main_wnd.h"

#define RSI_MAIN_SCREEN_UPDATE_ID 300
#define RSI_MAIN_SCREEN_UPDATE_MS 50

#include "RSI/preferences.h"
#include "RSI/render_system.h"
#include "RSI/data_bank.h"
#include "RSI/app_info.h"
#include "RSI/plugin.h"
#include "RSI/track.h"
#include "RSI/track_wnd.h"
#include "RSI/waveform_wnd.h"
#include "RSI/about_wnd.h"
#include "RSI/changelog_wnd.h"
#include "RSI/license_wnd.h"
#include "RSI/load_wnd.h"
#include "RSI/preferences_wnd.h"
#include "RSI/stats_wnd.h"
#include "RSI/library_wnd.h"
#include "RSI/database.h"

#include "WDL/wdlstring.h"
#include "WDL/time_precise.h"
#include "WDL/filebrowse.h"
#include "WDL/lice/lice.h"
#include "WDL/wingui/virtwnd.h"
#include "WDL/wingui/scrollbar/coolscroll.h"

#define RSI_OPEN_MEDIA_FILES \
  "All supported media files\0*.flac;*.mp3\0" \
  "FLAC files (*.FLAC)\0*.flac\0" \
  "MPEG audio files (*.MP3)\0*.mp3\0" \
  "All files (*.*)\0*.*\0\0"
#define RSI_OPEN_MEDIA_FILE_DEFEXT "mp3"

RSI_MainWnd::RSI_MainWnd()
  : m_hwnd(NULL)
  , m_library(false)
{}

RSI_MainWnd::~RSI_MainWnd()
{
  DestroyWindow(m_hwnd);
}

void RSI_MainWnd::ToggleLibrary()
{
  m_library = !m_library;
  SendMessage(g_librarywnd->Handle(), WM_SETREDRAW, FALSE, 0);
  OnSize();
  SendMessage(g_librarywnd->Handle(), WM_SETREDRAW, TRUE, 0);
  InvalidateRect(g_librarywnd->Handle(), NULL, FALSE);
}

bool RSI_MainWnd::IsLibraryFull() const
{
  return m_library;
}

int RSI_MainWnd::UpdateScreenRegions()
{
  for (int i = 0; i < g_trackwnds.GetSize(); i++)
  {
    RSI_TrackWnd *trkwnd = g_trackwnds.Get(i);
    if (trkwnd)
    {
      trkwnd->UpdateScreenRegions();
    }
  }

  if (!g_loadwnd && g_rendersystem->IsLoadingInProgress())
  {
    DialogBox(g_inst, MAKEINTRESOURCE(IDD_LOAD), m_hwnd, RSI_LoadWndProc);
  }

  // menubar
  if (g_rendersystem->IsTrackAvailable())
  {
    EnableMenuItem(GetMenu(m_hwnd), ID_FILE_LOADTRACK, MF_ENABLED);
  }
  else
  {
    EnableMenuItem(GetMenu(m_hwnd), ID_FILE_LOADTRACK, MF_GRAYED);
  }

  return 1;
}

void RSI_MainWnd::OnInitDialog()
{
  double wall0 = time_precise();

  //InitializeCoolSB(m_hwnd);

  if (IsStableRelease())
  {
    SetWindowText(m_hwnd, RSI_NAME_MARKETING);
  }
  else
  {
    SetWindowText(m_hwnd, RSI_FULL_VERSION " (" RSI_ARCH ")");
  }

  m_resize.init(m_hwnd);
  //m_resize.init_item(IDC_CUSTOM1, 0.0f, 0.0f, 1.0f, 1.0f);

  m_main_menu = LoadMenu(g_inst, MAKEINTRESOURCE(IDR_MAIN_MENUBAR));
  SetMenu(m_hwnd, m_main_menu);

  m_x = GetPrivateProfileInt(RSI_NAME, "main_wnd_x", 50, g_inipath.Get());
  m_y = GetPrivateProfileInt(RSI_NAME, "main_wnd_y", 50, g_inipath.Get());
  m_w = GetPrivateProfileInt(RSI_NAME, "main_wnd_w", 1024, g_inipath.Get());
  m_h = GetPrivateProfileInt(RSI_NAME, "main_wnd_h", 900, g_inipath.Get());
  SetWindowPos(m_hwnd, NULL, m_x, m_y, m_w, m_h, SWP_NOACTIVATE);

  RECT r;
  GetClientRect(m_hwnd, &r);

  int lrm = 2, tbm = 2;
  int tx = 0, ty = 0, tw = ((r.right - lrm) / 4) - lrm, th = 0;

  for (int i = 0; i < RSI_MAX_TRACKS; i++)
  {
    RSI_TrackWnd *trkwnd = new RSI_TrackWnd;
    g_trackwnds.Add(trkwnd);
    CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_TRACK),
      m_hwnd, RSI_TrackWnd::TrackWndProc, (LPARAM)trkwnd);

    if (!m_library)
    {
      th = 270;
      ShowWindow(GetDlgItem(trkwnd->Handle(), IDC_CUSTOM1), SW_SHOW);
      ShowWindow(GetDlgItem(trkwnd->Handle(), IDC_CUSTOM2), SW_SHOW);
    }
    else
    {
      th = 60 + tbm;
      ShowWindow(GetDlgItem(trkwnd->Handle(), IDC_CUSTOM1), SW_HIDE);
      ShowWindow(GetDlgItem(trkwnd->Handle(), IDC_CUSTOM2), SW_HIDE);
    }

    SetWindowPos(trkwnd->Handle(), NULL, tx + lrm, ty + tbm, tw, th, SWP_NOZORDER | SWP_NOACTIVATE);

    tx += tw + lrm;

    if (tx == (tw + lrm) * 4) { ty += th + tbm; tx = 0; }

    ShowWindow(trkwnd->Handle(), SW_SHOW);
  }

  g_librarywnd = new RSI_LibraryWnd;
  CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_LIBRARY),
    m_hwnd, RSI_LibraryWnd::LibraryWndProc, (LPARAM)g_librarywnd);
  SetWindowPos(g_librarywnd->Handle(), NULL, r.left, ty + tbm, r.right - r.left,
    r.bottom - ty, SWP_NOZORDER | SWP_NOACTIVATE);
  ShowWindow(g_librarywnd->Handle(), SW_SHOW);

  int maximized = GetPrivateProfileInt(RSI_NAME, "main_wnd_maximized", 0, g_inipath.Get());

  if (maximized)
  {
    ShowWindow(m_hwnd, SW_SHOWMAXIMIZED);
  }
  else
  {
    ShowWindow(m_hwnd, SW_SHOWNORMAL);
  }

  //RECT r;
  //HWND cstm = GetDlgItem(m_hwnd, IDC_CUSTOM1);
  //GetWindowRect(cstm, &r);
  //ScreenToClient(cstm, (LPPOINT)&r);
  //ScreenToClient(cstm, ((LPPOINT)&r)+1);

  //SCROLLINFO si = 
  //{
  //  sizeof(si),
  //  SIF_PAGE | SIF_POS | SIF_RANGE,
  //  0,
  //  r.bottom - r.top,
  //  r.bottom, //pich + margin,
  //  0,
  //};

  //CoolSB_SetScrollInfo(cstm, SB_VERT, &si, TRUE);
  g_databank = new RSI_DataBank;
  g_rendersystem = new RSI_RenderSystem;

  g_audiostreamer = CreateAudioStreamer();

  if (g_rendersystem && g_audiostreamer)
  {
    if (!g_audiostreamer->Open())
    {
      int fmt = g_preferences->GetAudioDeviceBitDepth();
      int srate = (int)g_preferences->GetAudioDeviceSamplerate();
      int nch = g_preferences->GetAudioDeviceOutputChannels();

      WDL_FastString fmtstr;

      switch (fmt)
      {
      case 0: fmtstr.Set("16-bit"); break;
      case 1: fmtstr.Set("24-bit"); break;
      case 2: fmtstr.Set("32-bit"); break;
      case 3: fmtstr.Set("32-bit FP"); break;
      default: fmtstr.Set("Unknown"); break;
      }

      WDL_FastString err;
      err.SetFormatted(1024,
        RSI_NAME_MARKETING " cannot open the audio device with the following settings:\n\n"
        "Audio bit depth: %s\n"
        "Audio sample rate: %d\n"
        "Audio output channels: %d\n\n"
        "Make sure that the related settings are correct in " RSI_NAME_MARKETING " preferences.",
        fmtstr.Get(), srate, nch);

      MessageBox(m_hwnd, err.Get(), "Audio device error", MB_OK);
    }
    else
    {
      WDL_ASSERT(!g_rendersystem->IsRunning());
      WDL_ASSERT(!g_audiostreamer->IsRunning());
      g_rendersystem->StartThread();
      g_audiostreamer->Start(RSI_AudioOnSamples);
    }
  }
  else
  {
    MessageBox(m_hwnd,
      RSI_NAME_MARKETING " cannot find a valid audio system.\n"
      "Press OK to close " RSI_NAME_MARKETING ".",
      "Audio system error", MB_OK);
    DestroyWindow(m_hwnd);
  }

  double wall1 = time_precise();

  if (WDL_unlikely(!IsStableRelease()))
  {
    const char warn_msg[] =
    {
      "Welcome to " RSI_NAME_MARKETING " (the \"Software\").\n\n"
      "THIS IS AN UNSTABLE RELEASE STILL IN DEVELOPEMENT PHASE\n"
      "AND IS PROVIDED ON AN \"AS IS\" BASIS AND IS BELIEVED\n"
      "TO CONTAIN DEFECTS AND A PRIMARY PURPOSE OF THIS\n"
      "RELEASE IS TO OBTAIN FEEDBACK ON SOFTWARE PERFORMANCE\n"
      "AND THE IDENTIFICATION OF DEFECTS.\n\n"
      "IT IS ADVISED TO USE CAUTION AND NOT TO RELY IN ANY WAY\n"
      "ON THE CORRECT FUNCTIONING OF THIS RELEASE.\n\n"
      RSI_NAME_MARKETING " version: " RSI_NAKED_VERSION " (" RSI_ARCH ")\n\n"
      "For the latest production release visit: " RSI_WEBSITE_URL "\n\n"
      "Startup time: %.3f\n\n"
      RSI_COPYRIGHT
    };

    WDL_FastString tmp;

    tmp.SetFormatted(1024, warn_msg, wall1 - wall0);

    MessageBox(m_hwnd, tmp.Get(), "Release for testing purposes", MB_OK);
  }

  SetTimer(m_hwnd, RSI_MAIN_SCREEN_UPDATE_ID, RSI_MAIN_SCREEN_UPDATE_MS, NULL);
}

void RSI_MainWnd::OnSysCommand()
{
  if (m_wparam == SC_CLOSE)
  {
    bool active = false;

    for (int i = 0; i < g_tracks.GetSize(); i++)
    {
      RSI_Track *trk = g_tracks.Enumerate(i);
      if (trk)
      {
        if (trk->IsActive()) { active = true; break; }
      }
    }

    if (active && g_preferences->AskExit())
    {
      int res = MessageBox(m_hwnd, "Playback is active. Do you really want to Exit?", "Ask Exit", MB_YESNO);
      if (res == IDYES) DestroyWindow(m_hwnd);
    }
    else
    {
      DestroyWindow(m_hwnd);
    }
  }
}

int RSI_MainWnd::OnClose()
{
  return 0;
}

void RSI_MainWnd::OnSize()
{
  if (m_wparam != SIZE_MINIMIZED)
  {
    m_resize.onResize();

    RECT r;
    GetClientRect(m_hwnd, &r);

    int lrm = 2, tbm = 2;
    int tx = 0, ty = 0, tw = ((r.right - lrm) / 4) - lrm, th = 0;

    for (int i = 0; i < g_trackwnds.GetSize(); i++)
    {
      RSI_TrackWnd *trkwnd = g_trackwnds.Get(i);

      if (!m_library)
      {
        th = 270;
        ShowWindow(GetDlgItem(trkwnd->Handle(), IDC_CUSTOM1), SW_SHOW);
        ShowWindow(GetDlgItem(trkwnd->Handle(), IDC_CUSTOM2), SW_SHOW);
      }
      else
      {
        th = 60 + tbm;
        ShowWindow(GetDlgItem(trkwnd->Handle(), IDC_CUSTOM1), SW_HIDE);
        ShowWindow(GetDlgItem(trkwnd->Handle(), IDC_CUSTOM2), SW_HIDE);
      }

      SetWindowPos(trkwnd->Handle(), NULL, tx + lrm, ty + tbm, tw, th, SWP_NOZORDER | SWP_NOACTIVATE);

      tx += tw + lrm;

      if (tx == (tw + lrm) * 4) { ty += th + tbm; tx = 0; }
    }

    if (g_librarywnd)
    {
      SetWindowPos(g_librarywnd->Handle(), NULL, r.left, ty + tbm, r.right - r.left,
        r.bottom - ty, SWP_NOZORDER | SWP_NOACTIVATE);
      HWND lst = GetDlgItem(g_librarywnd->Handle(), IDC_LIST1);
      int pos = ListView_GetNextItem(lst, -1, LVNI_SELECTED);
      if (pos != -1)
      {
        ListView_EnsureVisible(lst, pos, FALSE);
      }
    }
  }

  //InvalidateRect(m_hwnd, NULL, FALSE);

  if (m_wparam != SIZE_MINIMIZED && m_wparam != SIZE_MAXIMIZED)
  {
    RECT r;
    GetWindowRect(m_hwnd, &r);

    m_x = r.left;
    m_y = r.top;
    m_w = r.right - r.left;
    m_h = r.bottom - r.top;
  }
}

void RSI_MainWnd::OnMove()
{
  int xpos = (int)(short) LOWORD(m_lparam); // horizontal position
  int ypos = (int)(short) HIWORD(m_lparam); // vertical position

  if (xpos >= 0 && ypos >= 0 && GetCapture() == m_hwnd)
  {
    RECT r;
    GetWindowRect(m_hwnd, &r);

    m_x = r.left;
    m_y = r.top;
    m_w = r.right - r.left;
    m_h = r.bottom - r.top;
  }
}

void RSI_MainWnd::OnDestroy()
{
  KillTimer(m_hwnd, RSI_MAIN_SCREEN_UPDATE_MS);

#ifdef _WIN32
  WINDOWPLACEMENT wp = { sizeof(wp) };
  GetWindowPlacement(m_hwnd, &wp);

  WDL_FastString xstr, ystr, wstr, hstr;
  xstr.SetFormatted(32, "%d", m_x);
  ystr.SetFormatted(32, "%d", m_y);
  wstr.SetFormatted(32, "%d", m_w);
  hstr.SetFormatted(32, "%d", m_h);

  if (wp.showCmd == SW_SHOWMAXIMIZED)
  {
    WritePrivateProfileString(RSI_NAME, "main_wnd_maximized", "1", g_inipath.Get());
  }
  else
  {
    WritePrivateProfileString(RSI_NAME, "main_wnd_maximized", "0", g_inipath.Get());
    WritePrivateProfileString(RSI_NAME, "main_wnd_x", xstr.Get(), g_inipath.Get());
    WritePrivateProfileString(RSI_NAME, "main_wnd_y", ystr.Get(), g_inipath.Get());
    WritePrivateProfileString(RSI_NAME, "main_wnd_w", wstr.Get(), g_inipath.Get());
    WritePrivateProfileString(RSI_NAME, "main_wnd_h", hstr.Get(), g_inipath.Get());
  }

  PostQuitMessage(0);
#else
  RECT r;
  GetWindowRect(m_hwnd, &r);

  WDL_FastString xstr, ystr, wstr, hstr;
  xstr.SetFormatted(32, "%d", r.left);
  ystr.SetFormatted(32, "%d", r.top);
  wstr.SetFormatted(32, "%d", r.right - r.left);
  hstr.SetFormatted(32, "%d", r.bottom - r.top);

  if (r.left >= 0 && r.top >= 0)
  {
    WritePrivateProfileString(RSI_NAME, "main_wnd_x", xstr.Get(), g_inipath.Get());
    WritePrivateProfileString(RSI_NAME, "main_wnd_y", ystr.Get(), g_inipath.Get());
    WritePrivateProfileString(RSI_NAME, "main_wnd_w", wstr.Get(), g_inipath.Get());
    WritePrivateProfileString(RSI_NAME, "main_wnd_h", hstr.Get(), g_inipath.Get());
  }

  #ifdef __APPLE__
  SWELL_PostQuitMessage(g_mainwnd);
  #endif
  g_hasrequestedquit = true;
#endif

  WDL_ASSERT(g_audiostreamer);
  WDL_ASSERT(g_rendersystem);
  WDL_ASSERT(g_databank);
  WDL_ASSERT(g_librarywnd);

  WDL_ASSERT(g_audiostreamer->IsRunning());
  WDL_ASSERT(g_rendersystem->IsRunning());
  g_audiostreamer->Stop();
  g_audiostreamer->Close();
  g_rendersystem->EjectEverything();
  g_rendersystem->StopThread();

  delete g_audiostreamer;
  delete g_rendersystem;
  delete g_databank;

  delete g_librarywnd;
  g_trackwnds.Empty(true);
}

void RSI_MainWnd::OnCommand()
{
  switch (LOWORD(m_wparam))
  {
  //case IDOK:
  //  {
  //    SetDlgItemText(m_hwnd, IDC_EDIT1, "");
  //  }
  //  break;
  case ID_FILE_LOADTRACK:
    {
      char *fl = NULL;
      WDL_FastString act;

      if (g_rendersystem->IsTrackAvailable())
      {
        bool preservecwd = g_preferences->WantPreserveCurrentDirectory();
        act.SetFormatted(512, "Load file to track %d", g_rendersystem->GetActiveTrack());
        fl = WDL_ChooseFileForOpen(m_hwnd, act.Get(), NULL, NULL,
          RSI_OPEN_MEDIA_FILES, RSI_OPEN_MEDIA_FILE_DEFEXT, preservecwd, false);

        if (fl) g_rendersystem->LoadFileTrack(fl);
      }

      if (fl) free(fl);
    }
    break;
  case ID_FILE_EXIT:
    {
      bool active = false;

      for (int i = 0; i < g_tracks.GetSize(); i++)
      {
        RSI_Track *trk = g_tracks.Enumerate(i);
        if (trk)
        {
          if (trk->IsActive()) { active = true; break; }
        }
      }

      if (active && g_preferences->AskExit())
      {
        int res = MessageBox(m_hwnd, "Playback is active. Do you really want to Exit?", "Ask Exit", MB_YESNO);
        if (res == IDYES)
        {
          if (g_mainwnd) { delete g_mainwnd; g_mainwnd = NULL; }
          //if (g_mainwnd) { DestroyWindow(g_mainwnd->Handle()); }
        }
      }
      else
      {
        if (g_mainwnd) { delete g_mainwnd; g_mainwnd = NULL; }
        //if (g_mainwnd) { DestroyWindow(g_mainwnd->Handle()); }
      }
    }
    break;
  case ID_OPTIONS_STATS:
    {
      if (!g_statswnd)
      {
        g_statswnd = new RSI_StatsWnd;
        CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_STATS), m_hwnd,
          RSI_StatsWnd::StatsWndProc, (LPARAM)g_statswnd);
        ShowWindow(g_statswnd->Handle(), SW_SHOW);
      }
      else
      {
        SetFocus(g_statswnd->Handle());
      }
    }
    break;
  case ID_OPTIONS_SCANMEDIALIBRARYPATHS:
    {
      int answer = MessageBox(m_hwnd,
        "Are you sure you want to scan media library paths?",
        "Scan media library paths", MB_YESNO);
      if (answer == IDYES) g_librarywnd->ScanFiles();
    }
    break;
  case ID_OPTIONS_PREFERENCES:
    {
      if (!g_preferences->WantCurses())
      {
        g_preferences->Open();
      }
      else
      {
        if (!g_prefwnd)
        {
          g_prefwnd = new RSI_PreferencesWnd;
          CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_PREFERENCES), m_hwnd,
            RSI_PreferencesWnd::PreferencesWndProc, (LPARAM)g_prefwnd);
          ShowWindow(g_prefwnd->Handle(), SW_SHOW);
        }
        else
        {
          SetFocus(g_prefwnd->Handle());
        }
      }
    }
    break;
  case ID_HELP_DOCUMENTATION:
    {
      WDL_FastString doc;
      doc.Set(g_modpath.Get());
      doc.Append("documentation.txt");

      ShellExecute(m_hwnd, "", "notepad.exe", doc.Get(), "", SW_SHOWNORMAL);
    }
    break;
  case ID_HELP_ABOUTRSI:
    {
      if (!g_aboutwnd)
      {
        g_aboutwnd = new RSI_AboutWnd;
        CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_ABOUT), m_hwnd,
          RSI_AboutWnd::AboutWndProc, (LPARAM)g_aboutwnd);
        ShowWindow(g_aboutwnd->Handle(), SW_SHOW);
      }
      else
      {
        SetFocus(g_aboutwnd->Handle());
      }
    }
    break;
  case ID_HELP_CHANGELOG:
    {
      if (!g_changelogwnd)
      {
        g_changelogwnd = new RSI_ChangelogWnd;
        CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_CHANGELOG), m_hwnd,
          RSI_ChangelogWnd::ChangelogWndProc, (LPARAM)g_changelogwnd);
        ShowWindow(g_changelogwnd->Handle(), SW_SHOW);
      }
      else
      {
        SetFocus(g_changelogwnd->Handle());
      }
    }
    break;
  case ID_HELP_VERSION:
    {
      const char version_str[] =
      {
        RSI_NAME_MARKETING " version: " RSI_NAKED_VERSION " (" RSI_ARCH ")\n\n"
        "Build timestamp: " RSI_TIMESTAMP "\n"
        "Git commit: " RSI_GIT_SHA
      };

      MessageBox(m_hwnd, version_str, "Version details", MB_OK);
    }
    break;
  case ID_HELP_OFFICIALWEBSITE:
    {
      ShellExecute(m_hwnd, "", RSI_WEBSITE_URL, "", "", SW_SHOWNORMAL);
    }
    break;
  case ID_HELP_LICENSE:
    {
      if (!g_licwnd)
      {
        g_licwnd = new RSI_LicenseWnd;
        CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_LICENSE), m_hwnd,
          RSI_LicenseWnd::LicenseWndProc, (LPARAM)g_licwnd);
        ShowWindow(g_licwnd->Handle(), SW_SHOW);
      }
      else
      {
        SetFocus(g_licwnd->Handle());
      }
    }
    break;
  }
}

void RSI_MainWnd::OnTimer()
{
  if (m_wparam == RSI_MAIN_SCREEN_UPDATE_ID)
  {
    UpdateScreenRegions();
  }
}

void RSI_MainWnd::OnPaint()
{
  //int xo, yo;
  m_painter.PaintBegin(m_hwnd, RGB(34, 34, 34));
  m_painter.PaintEnd();
}

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

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

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

WDL_DLGRET RSI_MainWnd::MainWndLoop(UINT msg, WPARAM wparam, LPARAM lparam)
{
  m_msg = msg;
  m_wparam = wparam;
  m_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: OnInitDialog(); break;
    case WM_SYSCOMMAND: OnSysCommand(); break;
    case WM_CLOSE: return OnClose(); break;
    case WM_SIZE: OnSize(); break;
    case WM_MOVE: OnMove(); break;
    case WM_DESTROY: OnDestroy(); break;
    case WM_COMMAND: OnCommand(); break;
    case WM_TIMER: OnTimer(); break;
    case WM_PAINT: OnPaint(); break;
    case WM_ERASEBKGND: return 1; break;
  }

  return 0;
}

#include "WDL/eel2/ns-eel.h"
#include "WDL/lice/lice.h"
#include "WDL/wingui/virtwnd-controls.h"
#include "WDL/wingui/scrollbar/coolscroll.h"


int WDL_STYLE_WantGlobalButtonBorders() { return 0; }
bool WDL_STYLE_WantGlobalButtonBackground(int *col) { return false; }
bool WDL_STYLE_GetBackgroundGradient(double *gradstart, double *gradslope) { return false; }
LICE_IBitmap *WDL_STYLE_GetSliderBitmap2(bool vert) { return NULL; }
bool WDL_STYLE_AllowSliderMouseWheel() { return true; }
int WDL_STYLE_GetSliderDynamicCenterPos() { return 500; }


// TO BE IMPLEMENTED BY APP:
// implemented by calling app, can return a LICE_IBitmap **img for "scrollbar"
void *GetIconThemePointer(const char *name)
{
  if (!strcmp(name, "scrollbar"))
  {}

  return NULL;
}

// can be a passthrough to GetSysColor()
int CoolSB_GetSysColor(HWND m_hwnd, int val)
{
  return GetSysColor(val);
}

#include <WDL/eel2/ns-eel.h>

void NSEEL_HOSTSTUB_EnterMutex()
{}

void NSEEL_HOSTSTUB_LeaveMutex()
{}
