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

#include "euterpe/about_wnd.h"
#include "euterpe/app_info.h"

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

#include "WDL/wdlstring.h"

// 3:1 (ultra wide)
#define RSE_ABOUT_WIDTH 630
#define RSE_ABOUT_HEIGHT 210

#define RSE_ABOUT_RENDER 505
#define RSE_ABOUT_RENDER_MS 41

static const char *master_project =
  "\xce\x95\xcf\x85\xcf\x84\xce\xad\xcf\x81\xcf\x80\xce\xb7";

static const char *different =
  "\xce\x93\xce\xb9\xcf\x8e\xcf\x81\xce\xb3\xce\xbf"
  "\xcf\x82\x20\xce\x92\xce\xbf\xcf\x85\xce\xb3\xce"
  "\xb9\xce\xbf\xcf\x8d\xce\xba\xce\xb1\xcf\x82";

static const char *euterpe_credits[] =
{
  EUTERPE_NAME_MARKETING,
  "Version: " EUTERPE_NAKED_VERSION " (" EUTERPE_ARCH ")",
  "Build timestamp: " EUTERPE_TIMESTAMP,
  "Git commit: " EUTERPE_GIT_SHA,
  "",
  "Developed by:",
  "Giorgos Vougioukas",
  "",
  "WDL:",
  "Cockos Incorporated",
  //"(when you care enough to use the very best)",
  "",
  "Cool Scrollbar:",
  "J Brown",
  "",
  "FFmpeg:",
  "Fabrice Bellard",
  "FFmpeg team",
  "",
  "msinttypes:",
  "Alexander Chemeris",
  "",
  "PortAudio:",
  "Ross Bencina",
  "Phil Burk",
  "",
  "libpng:",
  "Glenn Randers-Pehrson",
  "Simon-Pierre Cadieux",
  "Eric S. Raymond",
  "Mans Rullgard",
  "Cosmin Truta",
  "Gilles Vollant",
  "James Yu",
  "Tom Lane",
  "Willem van Schaik",
  "John Bowler",
  "Kevin Bracey",
  "Sam Bushell",
  "Magnus Holmgren",
  "Greg Roelofs",
  "Tom Tanner",
  "Andreas Dilger",
  "Dave Martindale",
  "Guy Eric Schalnat",
  "Paul Schmidt",
  "Tim Wegner",
  "",
  "jpeglib:",
  "Tom Lane",
  "Philip Gladstone",
  "Jim Boucher",
  "Lee Crocker",
  "Julian Minguillon",
  "Luis Ortiz",
  "George Phillips",
  "Davide Rossi",
  "Guido Vollbeding",
  "Ge' Weijers",
  "Independent JPEG Group",
  "",
  "A few helper classes:",
  "The Chromium Authors",
  "",
  "Mersenne Twister:",
  "Makoto Matsumoto (MT inventor)",
  "Takuji Nishimura (MT inventor)",
  "Shawn Cokus",
  "Richard J. Wagner",
  "",
  "zlib:",
  "Jean-loup Gailly",
  "Mark Adler",
  "",
  "minizip:",
  "Gilles Vollant",
  "Even Rouault",
  "Mathias Svensson",
  "",
  "Windows installer:",
  "Nullsoft Scriptable Install System (NSIS)",
  "Compressor | ZLIB",
  "",
  "Windows portable:",
  "Archive format | ZIP",
  "",
  "Giorgos wishes to thank the following",
  "for their assistance:",
  "Asimina",
  "Manolis",
  "Justin Frankel",
  "and",
  "Snoopy",
  "",
  "Contact | email:",
  "support@grafmin.gr",
  "",
  EUTERPE_NAME_MARKETING,
  EUTERPE_COPYRIGHT
};

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

RSE_AboutWnd::RSE_AboutWnd()
  : m_hwnd(NULL)
  , m_par(NULL)
  , m_x(0)
  , m_y(0)
  , m_w(0)
  , m_h(0)
  , m_bm(NULL)
  , m_font(NULL)
  , m_font_alpha(255)
  , m_scroll_offset_y(0)
  , m_credits_height(0)
  , m_calc(true)
  , m_thread(NULL)
  , m_kill_thread(false)
{}

RSE_AboutWnd::~RSE_AboutWnd()
{}

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

int RSE_AboutWnd::Run()
{
  RECT r, fr;
  int half_screen, half_text;

  HWND sta = GetDlgItem(m_hwnd, IDC_STATIC_ABOUT);

  GetWindowRect(sta, &r);
  ScreenToClient(m_hwnd, (LPPOINT)&r);
  ScreenToClient(m_hwnd, ((LPPOINT)&r)+1);

  GetWindowRect(sta, &fr);
  ScreenToClient(m_hwnd, (LPPOINT)&fr);
  ScreenToClient(m_hwnd, ((LPPOINT)&fr)+1);

  LICE_Clear(m_bm, LICE_RGBA(0, 0, 0, 255));

  m_font->SetBkColor(LICE_RGBA(0, 0, 0, 255));
  m_font->SetTextColor(LICE_RGBA(192, 192, 192, m_font_alpha));
  m_font->SetFromHFont(CreateFontIndirect(&lf),LICE_FONT_FLAG_OWNS_HFONT);

  half_screen = (r.right - r.left) / 2;

  fr.top = RSE_ABOUT_HEIGHT - 32;
  fr.bottom = fr.top + RSE_ABOUT_HEIGHT;

  fr.top -= m_scroll_offset_y;
  fr.bottom -= m_scroll_offset_y;

  for (int i = 0; i < sizeof(euterpe_credits) /
    sizeof(euterpe_credits[0]); i++)
  {
    if (m_break.Find(i) < 0)
    {
      if (i > m_break.Get()[m_break.GetSize() - 1])
      {
        fr.top += 32;
        fr.bottom += 32;
      }
      else
      {
        fr.top += 16;
        fr.bottom += 16;
      }

      if (fr.top >= -16 && fr.top <= RSE_ABOUT_HEIGHT)
      {
        if (!strcmp(euterpe_credits[i],
          "\x47\x69\x6f\x72\x67\x6f\x73\x20\x56\x6f\x75\x67\x69\x6f\x75\x6b\x61\x73")
          && (GetAsyncKeyState(VK_CONTROL) & 0x8000))
        {
          m_font->DrawText(m_bm, different,
            (int)strlen(different),
            &fr, DT_CALCRECT| DT_NOPREFIX | DT_SINGLELINE);
          half_text = (fr.right - fr.left) / 2;
          fr.left = 0;
          fr.left += half_screen - half_text;
          fr.right += half_screen - half_text;
          m_font->DrawText(m_bm, different,
            (int)strlen(different), &fr,
            LICE_DT_NEEDALPHA | LICE_DT_USEFGALPHA |
            DT_NOPREFIX | DT_SINGLELINE);
        }
        else if (!strcmp(euterpe_credits[i],
          "\x45\x75\x74\x65\x72\x70\x65")
          && (GetAsyncKeyState(VK_CONTROL) & 0x8000))
        {
          m_font->DrawText(m_bm, master_project,
            (int)strlen(master_project),
            &fr, DT_CALCRECT| DT_NOPREFIX | DT_SINGLELINE);
          half_text = (fr.right - fr.left) / 2;
          fr.left = 0;
          fr.left += half_screen - half_text;
          fr.right += half_screen - half_text;
          m_font->DrawText(m_bm, master_project,
            (int)strlen(master_project), &fr,
            LICE_DT_NEEDALPHA | LICE_DT_USEFGALPHA |
            DT_NOPREFIX | DT_SINGLELINE);
        }
        else
        {
          m_font->DrawText(m_bm, euterpe_credits[i],
            (int)strlen(euterpe_credits[i]),
            &fr, DT_CALCRECT| DT_NOPREFIX | DT_SINGLELINE);
          half_text = (fr.right - fr.left) / 2;
          fr.left = 0;
          fr.left += half_screen - half_text;
          fr.right += half_screen - half_text;
          m_font->DrawText(m_bm, euterpe_credits[i],
            (int)strlen(euterpe_credits[i]), &fr,
            LICE_DT_NEEDALPHA | LICE_DT_USEFGALPHA |
            DT_NOPREFIX | DT_SINGLELINE);
        }
      }
    }
    else
    {
      if (i == m_break.Get()[m_break.GetSize() - 1])
      {
        fr.top += RSE_ABOUT_HEIGHT - 60;
        fr.bottom += RSE_ABOUT_HEIGHT - 60;
      }
      else
      {
        fr.top += 32;
        fr.bottom += 32;
      }
    }
  }

  if (m_calc)
  {
    m_credits_height = fr.bottom - (RSE_ABOUT_HEIGHT / 2);
    m_calc = false;
  }

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

  LICE_Blit(m_bm, m_bm, m_x, m_y, m_w, m_h, m_bm->getWidth(),
    m_bm->getHeight(), 1.0f, LICE_BLIT_MODE_COPY);

  if (m_scroll_offset_y > m_credits_height)
  {
    if (m_font_alpha > 220) m_font_alpha -= 1;
    else m_font_alpha -= 20;

    if (m_font_alpha <= 0)
    {
      m_font_alpha = 255;
      m_scroll_offset_y = -32;
    }
  }
  else
  {
    m_scroll_offset_y++;
  }

  return 1;
}

unsigned int WINAPI RSE_AboutWnd::ThreadFunction(void *arg)
{
  RSE_AboutWnd *self = (RSE_AboutWnd *)arg;

  if (WDL_NORMALLY(self))
  {
    self->m_kill_thread = false;

    while (!self->m_kill_thread)
    {
      self->m_mutex.Enter();
      while (!self->Run());
      self->m_mutex.Leave();
      Sleep(41); // 24 FPS
    }
  }

  return 0;
}

void RSE_AboutWnd::DoPaint(HWND hwnd, HDC dc)
{
  BitBlt(dc, m_x, m_y, m_w, m_h, m_bm->getDC(), 0, 0, SRCCOPY);
}

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

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

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

WDL_DLGRET RSE_AboutWnd::AboutWndProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
  switch (msg)
  {
  case WM_INITDIALOG:
    {
      HWND s = GetDlgItem(m_hwnd, IDC_STATIC_ABOUT);

      m_resize.init(m_hwnd);
      m_resize.init_itemhwnd(s);

      int x = g_ini_file->read_int("about_wnd_x", 0, EUTERPE_NAME);
      int y = g_ini_file->read_int("about_wnd_y", 50, EUTERPE_NAME);
      int w = RSE_ABOUT_WIDTH;
      int h = RSE_ABOUT_HEIGHT;
      SetWindowPos(m_hwnd, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE);

      for (int i = 0; i < sizeof(euterpe_credits) /
        sizeof(euterpe_credits[0]); i++)
      {
        if (!strcmp(euterpe_credits[i], "")) m_break.Add(&i, 1);
      }

      m_bm = new LICE_SysBitmap(w, h);
      m_font = new LICE_CachedFont();

      m_x = x;
      m_y = y;
      m_w = w;
      m_h = h;
      LICE_Clear(m_bm, LICE_RGBA(0, 0, 0, 255));

      WDL_ASSERT(m_thread == NULL);

      //if (!m_thread)
      //{
      //  unsigned int thread_id;
      //  m_thread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, (void *)this, 0, &thread_id);
      //}

      SetTimer(m_hwnd, RSE_ABOUT_RENDER, RSE_ABOUT_RENDER_MS, NULL);
    }
    break;
  case WM_PAINT:
    {
      PAINTSTRUCT ps;
      HWND sta = GetDlgItem(m_hwnd, IDC_STATIC_ABOUT);
      HDC dc = BeginPaint(sta, &ps);
      DoPaint(m_hwnd, dc);
      EndPaint(sta, &ps);
    }
    break;
  case WM_TIMER:
    {
      if (wparam == RSE_ABOUT_RENDER)
      {
        Run();
#if defined(_WIN32)
        InvalidateRect(m_hwnd, NULL, FALSE);
#else
        {
          HWND h = GetDlgItem(m_hwnd, IDC_STATIC_ABOUT);
          HDC dc = GetWindowDC(h);
          DoPaint(m_hwnd,dc);
          ReleaseDC(h,dc);
          //SWELL_FlushWindow(h); // for macos
        }
#endif
      }
    }
    break;
  case WM_SIZE:
    {
      if (wparam != SIZE_MINIMIZED)
      {
        m_resize.onResize();
      }
    }
    break;
  case WM_ERASEBKGND:
    {
      return 1;
    }
    break;
  case WM_MOVE:
    {

    }
    break;
  case WM_DESTROY:
    {
      //m_kill_thread = true;

      //if (m_thread)
      //{
      //  WaitForSingleObject(m_thread, INFINITE);
      //  CloseHandle(m_thread);
      //  m_thread = NULL;
      //}

      KillTimer(m_hwnd, RSE_ABOUT_RENDER);

      RECT r;
      GetWindowRect(m_hwnd, &r);

      g_ini_file->write_int("about_wnd_x", r.left, EUTERPE_NAME);
      g_ini_file->write_int("about_wnd_y", r.top, EUTERPE_NAME);

      delete m_bm;
      m_bm = NULL;
      delete m_font;
      m_font = NULL;
      m_font_alpha = 255;
      m_scroll_offset_y = 0;
      m_credits_height = 0;
      m_calc = true;
      m_break.Resize(0, true);
      m_hwnd = NULL;
    }
    break;
  case WM_COMMAND:
    {
      switch(LOWORD(wparam))
      {
      case IDCANCEL:
        {
          DestroyWindow(m_hwnd);
        }
        break;
      }
    }
    break;
  }

  return 0;
}
