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

#include "euterpe/transport_wnd.h"
#include "euterpe/res/resource.h"
#include "euterpe/app_info.h"
#include "euterpe/main_wnd.h"
#include "euterpe/icon_theme.h"
#include "euterpe/db2slider.h"

#include "WDL/fpcmp.h"
#include "WDL/win32_utf8.h"
#include "WDL/wdlcstring.h"
#include "WDL/filebrowse.h"
#include "WDL/dirscan.h"

#define RSE_DISPLAY_SEEK_TIME (WM_USER + 200)
#define RSE_ENABLE_PROGRESS_TIMER (WM_USER + 201)
#define RSE_DISABLE_PROGRESS_TIMER (WM_USER + 202)

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

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

static LOGFONT time_font =
{
  26, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
  OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
  "Arial"
};

RSE_PauseButton::RSE_PauseButton()
{}

RSE_PauseButton::~RSE_PauseButton()
{}

void RSE_PauseButton::OnMouseUp(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {
    g_main_loop_mutex.Enter();
    g_main_loop->Pause();
    g_main_loop_mutex.Leave();
  }
  WDL_VirtualIconButton::OnMouseUp(xpos, ypos);
}

RSE_PreviousButton::RSE_PreviousButton()
{}

RSE_PreviousButton::~RSE_PreviousButton()
{}

void RSE_PreviousButton::OnMouseUp(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {
    g_main_loop_mutex.Enter();
    g_main_loop->Previous();
    g_main_loop_mutex.Leave();
  }
  WDL_VirtualIconButton::OnMouseUp(xpos, ypos);
}

RSE_NextButton::RSE_NextButton()
{}

RSE_NextButton::~RSE_NextButton()
{}

void RSE_NextButton::OnMouseUp(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {
    g_main_loop_mutex.Enter();
    g_main_loop->Next();
    g_main_loop_mutex.Leave();
  }
  WDL_VirtualIconButton::OnMouseUp(xpos, ypos);
}

RSE_PlayButton::RSE_PlayButton()
{}

RSE_PlayButton::~RSE_PlayButton()
{}

int RSE_PlayButton::OnMouseDown(int xpos, int ypos)
{
  int a = WDL_VirtualIconButton::OnMouseDown(xpos, ypos);

  return a;
}

void RSE_PlayButton::OnMouseUp(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {
    g_main_loop_mutex.Enter();
    g_main_loop->Play();
    g_main_loop_mutex.Leave();
  }
  WDL_VirtualIconButton::OnMouseUp(xpos, ypos);
}

RSE_StopButton::RSE_StopButton()
{}

RSE_StopButton::~RSE_StopButton()
{}

void RSE_StopButton::OnMouseUp(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {
    g_main_loop_mutex.Enter();
    g_main_loop->Stop();
    g_main_loop_mutex.Leave();
  }
  WDL_VirtualIconButton::OnMouseUp(xpos, ypos);
}

RSE_TimeStaticText::RSE_TimeStaticText()
{}

RSE_TimeStaticText::~RSE_TimeStaticText()
{}

RSE_PercDecibelStaticText::RSE_PercDecibelStaticText()
{}

RSE_PercDecibelStaticText::~RSE_PercDecibelStaticText()
{}

RSE_ProgressSlider::RSE_ProgressSlider()
  : m_img(NULL)
{
  SetRange(0, 100, 0);
}

RSE_ProgressSlider::~RSE_ProgressSlider()
{

}

int RSE_ProgressSlider::OnMouseDown(int xpos, int ypos)
{
  SetCapture(GetRealParent());
  SendMessage(GetRealParent(), RSE_DISABLE_PROGRESS_TIMER, 0, 0);
  return WDL_VirtualSlider::OnMouseDown(xpos, ypos);
}

void RSE_ProgressSlider::OnMouseUp(int xpos, int ypos)
{
  WDL_VirtualSlider::OnMouseUp(xpos, ypos);

  g_main_loop_mutex.Enter();
  double duration = g_main_loop->GetDuration();
  g_main_loop_mutex.Leave();

  int pos = GetSliderPosition();

  double time = duration / 100 * pos;

  g_main_loop_mutex.Enter();
  g_main_loop->Seek(time);
  g_main_loop_mutex.Leave();

  ReleaseCapture();

  SendMessage(GetRealParent(), RSE_ENABLE_PROGRESS_TIMER, 0, 0);
}

void RSE_ProgressSlider::OnMouseMove(int xpos, int ypos)
{
  if (GetCapture())
  {
    WDL_VirtualSlider::OnMouseMove(xpos, ypos);

    SendMessage(GetRealParent(), RSE_DISPLAY_SEEK_TIME, 0, 0);
  }
}

RSE_VolumeSlider::RSE_VolumeSlider()
{}

RSE_VolumeSlider::~RSE_VolumeSlider()
{

}

void RSE_VolumeSlider::OnMouseUp(int xpos, int ypos)
{
  WDL_VirtualSlider::OnMouseUp(xpos, ypos);

  if (GetCapture())
  {
    g_main_loop_mutex.Enter();
    g_main_loop->SetVolume(SLIDER2DB(GetSliderPosition()));
    g_main_loop_mutex.Leave();
  }
  else
  {
    SendMessage(g_main_wnd->Handle(), WM_COMMAND, ID_PLAY_EXACTVOLUME, 0);
  }
}

void RSE_VolumeSlider::OnMouseMove(int xpos, int ypos)
{
  WDL_VirtualSlider::OnMouseMove(xpos, ypos);

  if (GetCapture())
  {
    g_main_loop_mutex.Enter();
    g_main_loop->SetVolume(SLIDER2DB(GetSliderPosition()));
    g_main_loop_mutex.Leave();
  }
}

bool RSE_VolumeSlider::OnMouseDblClick(int xpos, int ypos)
{
  if (WDL_VirtualSlider::OnMouseDblClick(xpos, ypos))
  {
    g_main_loop_mutex.Enter();
    g_main_loop->SetVolume(0.0);
    g_main_loop_mutex.Leave();

    return true;
  }

  return false;
}

RSE_RepeatButton::RSE_RepeatButton()
{}

RSE_RepeatButton::~RSE_RepeatButton()
{}

void RSE_RepeatButton::OnMouseMove(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {

  }
  WDL_VirtualIconButton::OnMouseMove(xpos, ypos);
}

void RSE_RepeatButton::OnMouseUp(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {
    g_main_loop_mutex.Enter();
    g_main_loop->ToggleRepeat();
    g_main_loop_mutex.Leave();
  }
  WDL_VirtualIconButton::OnMouseUp(xpos, ypos);
}

RSE_ShuffleButton::RSE_ShuffleButton()
{}

RSE_ShuffleButton::~RSE_ShuffleButton()
{}

void RSE_ShuffleButton::OnMouseMove(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {

  }
  WDL_VirtualIconButton::OnMouseMove(xpos, ypos);
}

void RSE_ShuffleButton::OnMouseUp(int xpos, int ypos)
{
  RECT r;
  this->GetPosition(&r);

  POINT p;
  GetCursorPos(&p);
  ScreenToClient(GetRealParent(), &p);

  if (PtInRect(&m_position, p))
  {
    g_main_loop_mutex.Enter();
    g_main_loop->ToggleShuffle();
    g_main_loop_mutex.Leave();
  }
  WDL_VirtualIconButton::OnMouseUp(xpos, ypos);
}

RSE_TransportWnd::RSE_TransportWnd()
  : m_hwnd(NULL)
  , m_button_height(35)
  , m_button_width(31)
  , m_bm(NULL)
  , m_font(NULL)
  , m_time_font(NULL)
  , m_perc_db_font(NULL)
{}

RSE_TransportWnd::~RSE_TransportWnd()
{
  if (m_bm) delete m_bm;
}

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

void RSE_TransportWnd::DoPaint(HWND hwnd, HDC dc)
{
  RECT r;
  GetClientRect(hwnd, &r);

  BitBlt(dc, r.left, r.top, r.right - r.left,
    r.bottom - r.top, m_bm->getDC(), 0, 0, SRCCOPY);
}

int RSE_TransportWnd::sort_by_file_path(const void *a, const void *b)
{
  WDL_FastString *s1, *s2;
  s1 = *(WDL_FastString **)a;
  s2 = *(WDL_FastString **)b;
  return stricmp(s1->Get(), s2->Get());
}

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

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

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

WDL_DLGRET RSE_TransportWnd::TransportWndProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
  switch (msg)
  {
  case WM_INITDIALOG:
    {
      g_transport_wnd = this;

      // Repeat/shuffle: H15 W15
      // Playback controls: H35, W31

      m_vwnd.SetRealParent(m_hwnd);

      m_bm = new LICE_SysBitmap();

      m_font = new LICE_CachedFont();
      m_font->SetFromHFont(CreateFontIndirect(&lf), LICE_FONT_FLAG_OWNS_HFONT);

      m_time_font = new LICE_CachedFont();
      m_time_font->SetFromHFont(CreateFontIndirect(&time_font), LICE_FONT_FLAG_OWNS_HFONT);

      m_perc_db_font = new LICE_CachedFont();
      m_perc_db_font->SetFromHFont(CreateFontIndirect(&perc_db_font), LICE_FONT_FLAG_OWNS_HFONT);

      RECT r, wr, sr;
      GetWindowRect(m_hwnd, &wr);
      ScreenToClient(m_hwnd, (LPPOINT)&wr);
      ScreenToClient(m_hwnd, ((LPPOINT)&wr)+1);

      r.top = 3;
      r.bottom = r.top + m_button_height;

      r.left = wr.left + 3 + 3;
      r.right = r.left + 90;
      m_time_static.SetFont(m_time_font);
      m_time_static.SetID(TIME_TEXT);
      m_time_static.SetPosition(&r);
      m_time_static.SetRealParent(m_hwnd);
      //m_time_static.SetBorder(true);
      m_time_static.SetAlign(0);
      m_time_static.SetColors(LICE_RGBA(0, 0, 0, 255));
      m_time_static.SetText("00:00");

      RECT s;
      m_time_static.GetPosition(&s);
      int lh = m_time_font->GetLineHeight();
      s.left = s.left - 3;
      s.right = s.left + 3;
      s.top = s.top - 1 + (s.bottom - s.top) / 2;
      s.bottom = s.top + 3;
      SetWindowPos(GetDlgItem(m_hwnd, IDC_STATIC1), NULL,
        s.left, s.top, s.right - s.left, s.bottom - s.top,
        SWP_NOACTIVATE | SWP_NOZORDER);
      m_bm->resize(s.right - s.left, s.bottom - s.top);
      LICE_Clear(m_bm, LICE_RGBA(255, 255, 255, 255));

      sr.left = r.left;
      sr.right = r.right;
      sr.top = r.top;
      sr.bottom = r.bottom;

      sr.left = sr.right + 3;
      sr.right = sr.left + 15;
      sr.bottom = sr.top + 15;
      m_repeat_button.SetFont(m_font);
      m_repeat_button.SetID(REPEAT_BUTTON);
      m_repeat_button.SetPosition(&sr);
      m_repeat_button.SetRealParent(m_hwnd);
      m_repeat_button.SetTextLabel("R");
      m_repeat_button.SetForceText(true, LICE_RGBA(255, 255, 255, 255));
      //m_repeat_button.SetForceBorder(true);

      sr.left = r.left;
      sr.right = r.right;
      sr.top = r.top;
      sr.bottom = r.bottom;

      sr.left = sr.right + 3;
      sr.right = sr.left + 15;
      sr.top = sr.bottom - 15;
      m_shuffle_button.SetFont(m_font);
      m_shuffle_button.SetID(SHUFFLE_BUTTON);
      m_shuffle_button.SetPosition(&sr);
      m_shuffle_button.SetRealParent(m_hwnd);
      m_shuffle_button.SetTextLabel("S");
      //m_shuffle_button.SetForceBorder(true);
      m_shuffle_button.SetForceText(true, LICE_RGBA(255, 255, 255, 255));

      r.left = sr.right + 3;
      r.right = r.left + 260;
      m_progress_slider.SetID(PROGRESS_SLIDER);
      m_progress_slider.SetPosition(&r);
      m_progress_slider.SetRealParent(m_hwnd);
      m_progress_slider.SetRange(0, 100, 0);
      m_progress_slider.SetSliderPosition(0);
      m_progress_slider.SetSkinImageInfo(
        &g_icon_theme.ts_progress);

      r.left = r.right + 3;
      r.right = r.left + 80;
      m_pdb_static.SetFont(m_perc_db_font);
      m_pdb_static.SetID(PERCDB_TEXT);
      m_pdb_static.SetPosition(&r);
      m_pdb_static.SetRealParent(m_hwnd);
      m_pdb_static.SetAlign(0);
      m_pdb_static.SetText("100% | -150dB");
      m_pdb_static.SetColors(LICE_RGBA(0, 0, 0, 255));

      r.left = r.right + 3;
      r.right = r.left + 92;
      m_volume_slider.SetID(VOLUME_SLIDER);
      m_volume_slider.SetPosition(&r);
      m_volume_slider.SetRealParent(m_hwnd);
      m_volume_slider.SetRange(0, 1000, 1000);
      m_volume_slider.SetSliderPosition(1000);
      m_volume_slider.SetSkinImageInfo(
        &g_icon_theme.ts_volume);

      r.left = wr.right - r.top - (m_button_width * 5) - 5 * 3;
      r.right = r.left + m_button_width;
      m_pause_button.SetFont(m_font);
      m_pause_button.SetID(PAUSE_BUTTON);
      m_pause_button.SetPosition(&r);
      m_pause_button.SetRealParent(m_hwnd);
      m_pause_button.SetTextLabel("PAUSE");
      //m_pause_button.SetForceBorder(true);
      m_pause_button.SetForceText(true, LICE_RGBA(255, 255, 255, 255));

      r.left = wr.right - r.top - (m_button_width * 4) - 4 * 3;
      r.right = r.left + m_button_width;
      m_previous_button.SetFont(m_font);
      m_previous_button.SetID(PREVIOUS_BUTTON);
      m_previous_button.SetPosition(&r);
      m_previous_button.SetRealParent(m_hwnd);
      m_previous_button.SetTextLabel("<"); //\xE2\x22\xB2
      //m_previous_button.SetForceBorder(true);
      m_previous_button.SetForceText(true, LICE_RGBA(255, 255, 255, 255));
      m_previous_button.SetIcon(&g_icon_theme.ts_previous);

      r.left = wr.right - r.top - (m_button_width * 3) - 3 * 3;
      r.right = r.left + m_button_width;
      m_next_button.SetFont(m_font);
      m_next_button.SetID(NEXT_BUTTON);
      m_next_button.SetPosition(&r);
      m_next_button.SetRealParent(m_hwnd);
      m_next_button.SetTextLabel(">"); //\xE2\x22\xB3
      //m_next_button.SetForceBorder(true);
      m_next_button.SetForceText(true, LICE_RGBA(255, 255, 255, 255));
      m_next_button.SetIcon(&g_icon_theme.ts_next);

      r.left = wr.right - r.top - (m_button_width * 2) - 2 * 3;
      r.right = r.left + m_button_width;
      m_play_button.SetFont(m_font);
      m_play_button.SetID(PLAY_BUTTON);
      m_play_button.SetPosition(&r);
      m_play_button.SetRealParent(m_hwnd);
      m_play_button.SetTextLabel("PLAY");
      //m_play_button.SetForceBorder(true);
      m_play_button.SetForceText(true, LICE_RGBA(255, 255, 255, 255));

      r.left = wr.right - r.top - (m_button_width * 1) - 1 * 3;
      r.right = r.left + m_button_width;
      m_stop_button.SetFont(m_font);
      m_stop_button.SetID(STOP_BUTTON);
      m_stop_button.SetPosition(&r);
      m_stop_button.SetRealParent(m_hwnd);
      m_stop_button.SetTextLabel("STOP");
      //m_stop_button.SetForceBorder(true);
      m_stop_button.SetForceText(true, LICE_RGBA(255, 255, 255, 255));
      m_stop_button.SetIcon(&g_icon_theme.ts_stop);

      m_vwnd.AddChild(&m_pause_button);
      m_vwnd.AddChild(&m_previous_button);
      m_vwnd.AddChild(&m_next_button);
      m_vwnd.AddChild(&m_play_button);
      m_vwnd.AddChild(&m_stop_button);
      m_vwnd.AddChild(&m_time_static);
      m_vwnd.AddChild(&m_repeat_button);
      m_vwnd.AddChild(&m_shuffle_button);
      //m_vwnd.AddChild(&m_artwork_button);
      m_vwnd.AddChild(&m_progress_slider);
      m_vwnd.AddChild(&m_pdb_static);
      m_vwnd.AddChild(&m_volume_slider);

      m_progress_slider.SetGrayed(true);
      m_vwnd.RequestRedraw(NULL);

      m_resize.init(m_hwnd);
      m_resize.init_itemvirt(m_vwnd.GetChildByID(PAUSE_BUTTON), 1.0f, 0.0f, 1.0f, 0.0f);
      m_resize.init_itemvirt(m_vwnd.GetChildByID(PREVIOUS_BUTTON), 1.0f, 0.0f, 1.0f, 0.0f);
      m_resize.init_itemvirt(m_vwnd.GetChildByID(NEXT_BUTTON), 1.0f, 0.0f, 1.0f, 0.0f);
      m_resize.init_itemvirt(m_vwnd.GetChildByID(PLAY_BUTTON), 1.0f, 0.0f, 1.0f, 0.0f);
      m_resize.init_itemvirt(m_vwnd.GetChildByID(STOP_BUTTON), 1.0f, 0.0f, 1.0f, 0.0f);

      SetTimer(m_hwnd, RSE_UPDATE_TRANSPORT_CONTROLS, RSE_UPDATE_TRANSPORT_CONTROLS_MS, NULL);
    }
    break;
  case WM_ERASEBKGND:
    {
      return 0;
    }
    break;
  case WM_PAINT:
    {
      RECT r;
      GetClientRect(m_hwnd, &r);
      m_vwnd.SetPosition(&r);

      m_painter.PaintBegin(m_hwnd, RGB(255, 255, 255));
      m_painter.PaintVirtWnd(&m_vwnd);
      m_painter.PaintEnd();

      PAINTSTRUCT ps;
      HWND sta = GetDlgItem(m_hwnd, IDC_STATIC1);
      HDC dc = BeginPaint(sta, &ps);
      DoPaint(sta, dc);
      EndPaint(sta, &ps);
    }
    break;
  case WM_TIMER:
    {
      if (wparam == RSE_UPDATE_TRANSPORT_CONTROLS)
      {
        g_main_loop_mutex.Enter();
        double time = g_main_loop->GetRunningTime();
        double duration = g_main_loop->GetDuration();
        bool is_time_elapsed = g_main_loop->IsTimeElapsed();
        bool is_paused = g_main_loop->IsPaused();
        bool is_playing = g_main_loop->IsPlaying();
        bool is_shuffle_on = g_main_loop->IsShuffleOn();
        bool is_repeat_on = g_main_loop->IsRepeatOn();
        bool is_muted = g_main_loop->IsMuted();
        double db = g_main_loop->GetVolume();
        bool has_stop_after_current = g_main_loop->HasStopAfterCurrent();
        g_main_loop_mutex.Leave();

        int minutes = 0;
        int seconds = 0;
        int current_range = 0;

        if (WDL_DefinitelyGreaterThan(time, 0.0))
        {
          current_range = (int)(time / duration * 100);

          if (!is_time_elapsed)
          {
            time = duration - time;
          }

          minutes = (int)time / 60;
          seconds = (int)time % 60;
        }

        m_progress_slider.SetSliderPosition(current_range);

        if (g_main_loop->IsPlaying())
        {
          m_progress_slider.SetGrayed(false);
          m_progress_slider.RequestRedraw(NULL);
        }
        else
        {
          m_progress_slider.SetGrayed(true);
          m_progress_slider.RequestRedraw(NULL);
        }

        m_strbuf.SetFormatted(64, is_time_elapsed ?
          "%02d:%02d" : "-%02d:%02d", minutes, seconds);
        m_time_static.SetText(m_strbuf.Get());

        m_volume_slider.SetSliderPosition(DB2SLIDER(db));

        if (is_paused)
        {
          m_pause_button.SetIcon(&g_icon_theme.ts_pause_on);
        }
        else
        {
          m_pause_button.SetIcon(&g_icon_theme.ts_pause);
        }

        if (is_playing)
        {
          m_play_button.SetIcon(&g_icon_theme.ts_play_on);
        }
        else
        {
          m_play_button.SetIcon(&g_icon_theme.ts_play);
        }

        if (is_shuffle_on)
        {
          m_shuffle_button.SetIcon(&g_icon_theme.ts_shuffle_on);
        }
        else
        {
          m_shuffle_button.SetIcon(&g_icon_theme.ts_shuffle);
        }

        if (is_repeat_on)
        {
          m_repeat_button.SetIcon(&g_icon_theme.ts_repeat_on);
        }
        else
        {
          m_repeat_button.SetIcon(&g_icon_theme.ts_repeat);
        }

        if (is_muted)
        {
          m_volume_slider.SetGrayed(true);
        }
        else
        {
          m_volume_slider.SetGrayed(false);
        }

        LICE_FillRect(m_bm, 0, 0, m_bm->getWidth(), m_bm->getHeight(),
          LICE_RGBA(255, 255, 255, 255), 1.0f, LICE_BLIT_MODE_COPY);
        if (has_stop_after_current)
        {
          LICE_FillRect(m_bm, 0, 0, m_bm->getWidth(), m_bm->getHeight(),
            LICE_RGBA(255, 0, 0, 255), 1.0f, LICE_BLIT_MODE_COPY);
        }

        RECT r;
        HWND sta = GetDlgItem(m_hwnd, IDC_STATIC1);
        GetClientRect(sta, &r);
        InvalidateRect(sta, &r, FALSE);

        m_strbuf.SetFormatted(64, "%d%% | %0.2fdB",
          m_progress_slider.GetSliderPosition(), db);
        m_pdb_static.SetText(m_strbuf.Get());
      }
    }
    break;
  case WM_COMMAND:
    {

    }
    break;
  case WM_SIZE:
    {
      m_resize.onResize();

      RECT pause, volume, progress, percdb, window;

      GetClientRect(m_hwnd, &window);

      m_pause_button.GetPosition(&pause);
      m_volume_slider.GetPosition(&volume);
      m_progress_slider.GetPosition(&progress);
      m_pdb_static.GetPosition(&percdb);

      if (pause.left < volume.right + 2)
      {
        m_pause_button.SetVisible(false);
        m_previous_button.SetVisible(false);
        m_next_button.SetVisible(false);
        m_play_button.SetVisible(false);
        m_stop_button.SetVisible(false);
      }
      else
      {
        m_pause_button.SetVisible(true);
        m_previous_button.SetVisible(true);
        m_next_button.SetVisible(true);
        m_play_button.SetVisible(true);
        m_stop_button.SetVisible(true);
      }

      if (window.right < volume.right + 2)
      {
        m_volume_slider.SetVisible(false);
      }
      else
      {
        m_volume_slider.SetVisible(true);
      }

      if (window.right < percdb.right + 2)
      {
        m_pdb_static.SetVisible(false);
      }
      else
      {
        m_pdb_static.SetVisible(true);
      }

      if (window.right < progress.right + 2)
      {
        m_progress_slider.SetVisible(false);
      }
      else
      {
        m_progress_slider.SetVisible(true);
      }
    }
    break;
  case WM_DESTROY:
    {
      KillTimer(m_hwnd, RSE_UPDATE_TRANSPORT_CONTROLS);
      m_vwnd.RemoveAllChildren(false);

      delete m_font;
      m_font = NULL;

      delete m_time_font;
      m_time_font = NULL;

      delete m_perc_db_font;
      m_perc_db_font = NULL;

      m_hwnd = NULL;
    }
    break;
  case WM_LBUTTONDBLCLK:
    {
      m_vwnd.OnMouseDblClick(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));

      //RECT r;
      //GetWindowRect(simg_, &r);
      //ScreenToClient(m_hwnd, (LPPOINT)&r);
      //ScreenToClient(m_hwnd, ((LPPOINT)&r)+1);

      //int x = GET_X_LPARAM(lparam);
      //int y = GET_Y_LPARAM(lparam);

      //if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom)
      //{
      //  MessageBox(NULL, "Artwork", "", MB_OK);
      //  break;
      //}
    }
    break;
  case WM_LBUTTONDOWN:
    {
      //SetFocus(m_hwnd);
      if (m_vwnd.OnMouseDown(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)) > 0)
      {
        SetCapture(m_hwnd);
      }
    }
    break;
  case WM_LBUTTONUP:
    {
      if (GetCapture() == m_hwnd)
      {
        m_vwnd.OnMouseUp(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
        ReleaseCapture();
      }
    }
    break;
  case WM_RBUTTONUP:
    {
      m_vwnd.OnMouseUp(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
    }
    break;
  case WM_MOUSEMOVE:
    {
      m_vwnd.OnMouseMove(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
    }
    break;
  case RSE_ENABLE_PROGRESS_TIMER:
    SetTimer(m_hwnd, RSE_UPDATE_TRANSPORT_CONTROLS, RSE_UPDATE_TRANSPORT_CONTROLS_MS, NULL);
    break;
  case RSE_DISABLE_PROGRESS_TIMER:
    KillTimer(m_hwnd, RSE_UPDATE_TRANSPORT_CONTROLS);
    break;
  case RSE_DISPLAY_SEEK_TIME:
    g_main_loop_mutex.Enter();
    double duration = g_main_loop->GetDuration();
    double db = g_main_loop->GetVolume();
    g_main_loop_mutex.Leave();

    int pos = m_progress_slider.GetSliderPosition();

    double time = duration / 100 * pos;

    int minutes = 0;
    int seconds = 0;
    int current_range = 0;

    if (WDL_DefinitelyGreaterThan(time, 0.0))
    {
      current_range = (int)(time / duration * 100);

      minutes = (int)time / 60;
      seconds = (int)time % 60;
    }

    m_progress_slider.SetSliderPosition(current_range);

    WDL_FastString ss;
    ss.SetFormatted(64, "%02d:%02d", minutes, seconds);
    m_time_static.SetText(ss.Get());

    ss.SetFormatted(64, "%d%% | %0.2fdB",
      m_progress_slider.GetSliderPosition(), db);
    m_pdb_static.SetText(ss.Get());
    break;
  } // switch

  return 0;
}
