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

#include "thalia/about_wnd.h"

// 3:1 (ultra wide)
#define THA_ABOUT_WIDTH 630
#define THA_ABOUT_HEIGHT 210

#define THA_ABOUT_UPDATE_ID 330
#define THA_ABOUT_UPDATE_MS 41

#include "WDL/aggarray.h"

static const char *master_project =
  "\xce\x98\xce\xac\xce\xbb\xce\xb5\xce\xb9\xce\xb1";

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 *thalia_credits[] =
{
  THA_NAME_MARKETING,
  "Version: " THA_NAKED_VERSION " (" THA_ARCH ")",
  "Build timestamp: " THA_TIMESTAMP,
  "Git commit: " THA_GIT_SHA,
  "",
  "Developed by:",
  "Giorgos Vougioukas",
  "",
  "WDL:",
  "Cockos Incorporated",
  "(when you care enough)",
  //"",
  //"Cool Scrollbar:",
  //"J Brown",
  "",
  "cJSON:",
  "Dave Gamble",
  "cJSON contributors",
  "",
  "libogg:",
  "Monty",
  "Greg Maxwell",
  "Ralph Giles",
  "Cristian Adam",
  "Tim Terriberry",
  "Xiph.org Foundation",
  "",
  "libFLAC:",
  "Josh Coalson",
  "Erik de Castro Lopo ",
  "Janne Hyv\xc3\xa4rinen",
  "Andrey Astafiev",
  "Miroslav Lichvar",
  "Brady Patterson",
  "Daisuke Shimamura",
  "Matt Zimmerman",
  "Xiph.org Foundation",
  "",
  "MP3 based on reaper_mp3dec:",
  "MP3 Library 0.2a",
  "Cockos Incorporated",
  "",
  "libvorbis:",
  "Monty",
  "Xiph.org Foundation",
  "",
  "libopus:",
  "Jean-Marc Valin",
  "Koen Vos",
  "Timothy Terriberry",
  "Karsten Vandborg Sorensen",
  "Soren Skak Jensen",
  "Gregory Maxwell",
  "",
  "libopusfile:",
  "Timothy B. Terriberry",
  "Ralph Giles",
  "Christopher \"Monty\" Montgomery",
  "Gregory Maxwell",
  "nu774",
  "",
  "WavPack:",
  "David Bryant",
  "Sebastian Dr\xc3\xb6ge",
  "Joachim Henke",
  "Jo\xc3\xabl R. Langlois",
  "Alexis Ballier",
  "Stephen",
  "Phil Eichinger",
  "Sebastian Ramacher",
  "luxagen",
  "Martin Koegler",
  "nu774",
  "David Seifert",
  "evpobr",
  "Ozkan Sezer",
  "Anonymous Maarten",
  "",
  "libsndfile:",
  "Erik de Castro Lopo",
  "Jutta Degener",
  "Carsten Bormann",
  "Sun Microsystems, Inc.",
  "Michael Pruett",
  "Chris Roberts",
  "IOhannes m zmoelnig",
  "Jan Starry",
  "Bodo",
  "Tim van der Molen",
  "Tim Blechmann",
  "Matti Nykyri",
  "Brian Lewis",
  "Robin Gareus",
  "Christian Weisgerber",
  "Jacob Meuserto",
  "Olivier Tristan",
  "Uli Franke",
  "Conrad Parker",
  "Lennart Poettering",
  "Fons Adriaensen",
  "David Yeo",
  "Yair K.",
  "Robs",
  "Ed Schouten",
  "Trent Apted",
  "Andr\xc3\xa9 Pang",
  "Reuben Thomas",
  "Jonathan Woithe",
  "Diego 'Flameeyes' Petten\xc3\xb2",
  "Paul Davis",
  "Jesse Chappell",
  "John ffitch",
  "David A. van Leeuwen",
  "Mo DeJong",
  "David Viens",
  "Steve Baker",
  "Denis Cote",
  "Stanko Juzbasic",
  "Frank Neumann",
  "Axel R\xc3""\xb6""bel",
  "Peter Miller",
  "Tero Pelander",
  "Antoine Mathys",
  "Marek Peteraj",
  "",
  "SQLite:",
  "D. Richard Hipp",
  "",
  "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",
  "",
  "PortAudio:",
  "Ross Bencina",
  "Phil Burk",
  "David Viens",
  "Dmitry Kostjuchenko",
  "",
  "TagLib:",
  "Scott Wheeler",
  "Lukas Lalinsky",
  "Tsuda Kageyu",
  "Stephen F. Booth",
  "Ismael Orenstein",
  "Allan Sandfeld Jensen",
  "Teemu Tervo",
  "Mathias Panzenb\xc3""\xb6""ck",
  "Damien Plisson",
  "Urs Fleisch",
  "",
  "Mersenne Twister:",
  "Makoto Matsumoto (MT inventor)",
  "Takuji Nishimura (MT inventor)",
  "Shawn Cokus",
  "Richard J. Wagner",
  "",
  "zlib:",
  "Jean-loup Gailly",
  "Mark Adler",
  "",
  "Windows installer:",
  "Nullsoft Scriptable Install System (NSIS)",
  "Compressor | ZLIB",
  "",
  "Windows portable:",
  "Archive format | ZIP",
  //"",
  //"Linux tarball:",
  //"gzip",
  "",
  "Giorgos wishes to thank the following",
  "for their assistance:",
  "Asimina",
  "Manolis",
  "Justin Frankel",
  "and",
  "Snoopy",
  "",
  "Contact | email:",
  "support@grafmin.gr",
  "",
  THA_NAME_MARKETING,
  THA_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"
};

static WDL_PtrArray<const char *, WDL_ARRAYCOUNT(thalia_credits)> credits(thalia_credits);

int THA_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 = THA_ABOUT_HEIGHT - 32;
  fr.bottom = fr.top + THA_ABOUT_HEIGHT;

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

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

      if (fr.top >= -16 && fr.top <= THA_ABOUT_HEIGHT)
      {
        if (!strcmp(credits.Get()[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(credits.Get()[i], "\x54\x68\x61\x6c\x69\x61")
          && (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, credits.Get()[i],
            (int)strlen(credits.Get()[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, credits.Get()[i],
            (int)strlen(credits.Get()[i]), &fr,
            LICE_DT_NEEDALPHA | LICE_DT_USEFGALPHA |
            DT_NOPREFIX | DT_SINGLELINE);
        }
      }
    }
    else
    {
      if (i == m_disjunction.Get()[m_disjunction.GetSize() - 1])
      {
        fr.top += THA_ABOUT_HEIGHT - 60;
        fr.bottom += THA_ABOUT_HEIGHT - 60;
      }
      else
      {
        fr.top += 32;
        fr.bottom += 32;
      }
    }
  }

  if (m_calc)
  {
    m_credits_height = fr.bottom - (THA_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;
}

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

void THA_AboutWnd::OnInitDialog(WPARAM wparam, LPARAM lparam)
{
  HWND s = GetDlgItem(m_hwnd, IDC_STATIC_ABOUT);

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

  int x = GetPrivateProfileInt(THA_NAME, "about_wnd_x", 0, g_inipath.Get());
  int y = GetPrivateProfileInt(THA_NAME, "about_wnd_y", 50, g_inipath.Get());
  int w = THA_ABOUT_WIDTH;
  int h = THA_ABOUT_HEIGHT;
  SetWindowPos(m_hwnd, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE);

  for (int i = 0; i < credits.GetSize(); i++)
  {
    if (!strcmp(credits.Get()[i], "")) m_disjunction.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));
  SetTimer(m_hwnd, THA_ABOUT_UPDATE_ID, THA_ABOUT_UPDATE_MS, NULL);
}

void THA_AboutWnd::OnPaint(WPARAM wparam, LPARAM lparam)
{
#if _WIN32
  PAINTSTRUCT ps;
  HWND sta = GetDlgItem(m_hwnd, IDC_STATIC_ABOUT);
  HDC dc = BeginPaint(sta, &ps);
  DoPaint(dc);
  EndPaint(sta, &ps);
#endif
}

void THA_AboutWnd::OnTimer(WPARAM wparam, LPARAM lparam)
{
  if (wparam == THA_ABOUT_UPDATE_ID)
  {
    Run();
#if defined(_WIN32)
    InvalidateRect(m_hwnd, NULL, FALSE);
#else
    {
      HWND h = GetDlgItem(m_hwnd, IDC_STATIC_ABOUT);
      HDC dc = GetWindowDC(h);
      DoPaint(dc);
      ReleaseDC(h,dc);
      //SWELL_FlushWindow(h); // for macos
    }
#endif
  }
}

void THA_AboutWnd::OnSize(WPARAM wparam, LPARAM lparam)
{
  if (wparam != SIZE_MINIMIZED)
  {
    m_resize.onResize();
  }
}

void THA_AboutWnd::OnDestroy(WPARAM wparam, LPARAM lparam)
{
  KillTimer(m_hwnd, THA_ABOUT_UPDATE_ID);

  RECT r;
  GetWindowRect(m_hwnd, &r);

  WDL_FastString rleft, rtop;
  rleft.SetFormatted(32, "%d", r.left);
  rtop.SetFormatted(32, "%d", r.top);

  WritePrivateProfileString(THA_NAME,"about_wnd_x", rleft.Get(), g_inipath.Get());
  WritePrivateProfileString(THA_NAME,"about_wnd_y", rtop.Get(), g_inipath.Get());
}

void THA_AboutWnd::OnCommand(WPARAM wparam, LPARAM lparam)
{
  switch(LOWORD(wparam))
  {
  case IDCANCEL:
    {
      if (g_aboutwnd) { delete g_aboutwnd; g_aboutwnd = NULL; }
    }
    break;
  }
}

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

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

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

WDL_DLGRET THA_AboutWnd::AboutWndLoop(UINT msg, WPARAM wparam, LPARAM lparam)
{
  switch (msg)
  {
    case WM_INITDIALOG: OnInitDialog(wparam, lparam); break;
    case WM_PAINT: OnPaint(wparam, lparam); break;
    case WM_TIMER: OnTimer(wparam, lparam); break;
    case WM_SIZE: OnSize(wparam, lparam); break;
    case WM_ERASEBKGND: return 1; break;
    case WM_DESTROY: OnDestroy(wparam, lparam); break;
    case WM_COMMAND: OnCommand(wparam, lparam); break;
  }

  return 0;
}
