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

#include "mnemosyne/main_wnd.h"
#include "mnemosyne/app_info.h"
#include "mnemosyne/picture_wnd.h"
#include "mnemosyne/about_wnd.h"
#include "mnemosyne/changelog_wnd.h"
#include "mnemosyne/license_wnd.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"

RSM_MainWnd::RSM_MainWnd()
  : m_hwnd(NULL)
  , m_x(0)
  , m_y(0)
  , m_w(0)
  , m_h(0)
{}

RSM_MainWnd::~RSM_MainWnd()
{}

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

  //InitializeCoolSB(m_hwnd);

  if (IsStableRelease())
  {
    SetWindowText(m_hwnd, MNEMOSYNE_NAME_MARKETING);
  }
  else
  {
    SetWindowText(m_hwnd, MNEMOSYNE_FULL_VERSION " (" MNEMOSYNE_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(MNEMOSYNE_NAME, "main_wnd_x", 50, g_inipath.Get());
  m_y = GetPrivateProfileInt(MNEMOSYNE_NAME, "main_wnd_y", 50, g_inipath.Get());
  m_w = GetPrivateProfileInt(MNEMOSYNE_NAME, "main_wnd_w", 1024, g_inipath.Get());
  m_h = GetPrivateProfileInt(MNEMOSYNE_NAME, "main_wnd_h", 768, g_inipath.Get());
  SetWindowPos(m_hwnd, NULL, m_x, m_y, m_w, m_h, SWP_NOACTIVATE);

  int maximized = GetPrivateProfileInt(MNEMOSYNE_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);

  double wall1 = time_precise();

  if (!IsStableRelease())
  {
    const char warn_msg[] =
    {
      "Welcome to " MNEMOSYNE_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"
      MNEMOSYNE_NAME_MARKETING " version: " MNEMOSYNE_NAKED_VERSION " (" MNEMOSYNE_ARCH ")\n\n"
      "For the latest production release visit: " MNEMOSYNE_WEBSITE_URL "\n\n"
      "Startup time: %.3f\n\n"
      MNEMOSYNE_COPYRIGHT
    };

    WDL_FastString tmp;

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

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

  SetFocus(m_hwnd);
}

void RSM_MainWnd::OnSysCommand()
{
  if (m_wparam == SC_CLOSE)
  {
    DestroyWindow(m_hwnd);
  }
}

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

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

    //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 RSM_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;
  }
}

int RSM_MainWnd::OnDestroy()
{
#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(MNEMOSYNE_NAME, "main_wnd_maximized", "1", g_inipath.Get());
  }
  else
  {
    WritePrivateProfileString(MNEMOSYNE_NAME, "main_wnd_maximized", "0", g_inipath.Get());
    WritePrivateProfileString(MNEMOSYNE_NAME, "main_wnd_x", xstr.Get(), g_inipath.Get());
    WritePrivateProfileString(MNEMOSYNE_NAME, "main_wnd_y", ystr.Get(), g_inipath.Get());
    WritePrivateProfileString(MNEMOSYNE_NAME, "main_wnd_w", wstr.Get(), g_inipath.Get());
    WritePrivateProfileString(MNEMOSYNE_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(MNEMOSYNE_NAME, "main_wnd_x", xstr.Get(), g_inipath.Get());
    WritePrivateProfileString(MNEMOSYNE_NAME, "main_wnd_y", ystr.Get(), g_inipath.Get());
    WritePrivateProfileString(MNEMOSYNE_NAME, "main_wnd_w", wstr.Get(), g_inipath.Get());
    WritePrivateProfileString(MNEMOSYNE_NAME, "main_wnd_h", hstr.Get(), g_inipath.Get());
  }

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

  return 0;
}

void RSM_MainWnd::OnCommand()
{
  switch (LOWORD(m_wparam))
  {
  case ID_FILE_OPENFILES:
    {
      g_picwnd->OpenFiles();
    } break;
  case ID_FILE_NEXT:
    {
      g_picwnd->NextImage();
    } break;
  case ID_FILE_PREVIOUS:
    {
      g_picwnd->PreviousImage();
    } break;
  case ID_EDIT_BW:
    {
      g_picwnd->BlackAndWhite();
    } break;
  case ID_EDIT_BLUR:
    {
      g_picwnd->Blur();
    } break;
  case ID_EDIT_FLIPVERTICALLY:
    {
      g_picwnd->FlipVertically();
    } break;
  case ID_EDIT_FLIPHORIZONTALLY:
    {
      g_picwnd->FlipHorizontally();
    } break;
  case ID_EDIT_NEGATIVE:
    {
      g_picwnd->Negative();
    } break;
  case ID_EDIT_LOGTRANSFORMATION:
    {
      g_picwnd->LogTransformation();
    } break;
  case ID_EDIT_ILLINIFY:
    {
      g_picwnd->Illinify();
    } break;
  case ID_EDIT_ROTATEBY0DEGREES:
    {
      g_picwnd->Rotate0();
    } break;
  case ID_EDIT_ROTATEBY90DEGREES:
    {
      g_picwnd->Rotate90();
    } break;
  case ID_EDIT_ROTATEBY180DEGREES:
    {
      g_picwnd->Rotate180();
    } break;
  case ID_EDIT_ROTATEBY270DEGREES:
    {
      g_picwnd->Rotate270();
    } 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_ABOUT:
    {
      if (!g_aboutwnd)
      {
        g_aboutwnd = new RSM_AboutWnd;
        CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_ABOUT), m_hwnd,
          RSM_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 RSM_ChangelogWnd;
        CreateDialogParam(g_inst, MAKEINTRESOURCE(IDD_CHANGELOG), m_hwnd,
          RSM_ChangelogWnd::ChangelogWndProc, (LPARAM)g_changelogwnd);
        ShowWindow(g_changelogwnd->Handle(), SW_SHOW);
      }
      else
      {
        SetFocus(g_changelogwnd->Handle());
      }
    } break;
  case ID_HELP_VERSION:
    {
      const char version_string[] =
      {
        MNEMOSYNE_NAME_MARKETING " version: " MNEMOSYNE_NAKED_VERSION " (" MNEMOSYNE_ARCH ")\n\n"
        "Build timestamp: " MNEMOSYNE_TIMESTAMP "\n"
        "Git commit: " MNEMOSYNE_GIT_SHA
      };

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


void RSM_MainWnd::OnTimer()
{}

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

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

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

WDL_DLGRET RSM_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: return OnDestroy(); break;
    case WM_COMMAND: OnCommand(); break;
    case WM_TIMER: OnTimer(); 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"

// an app should implement these
int WDL_STYLE_WantGlobalButtonBorders()
{
  return 0;
}

bool WDL_STYLE_WantGlobalButtonBackground(int *col)
{
  return false;
}

int WDL_STYLE_GetSysColor(int p)
{
  return GetSysColor(p);
}

void WDL_STYLE_ScaleImageCoords(int *x, int *y)
{}

bool WDL_Style_WantTextShadows(int *col)
{
  return false;
}

// this is the default, you can override per painter if you want.
// return values 0.0-1.0 for each, return false if no gradient desired
bool WDL_STYLE_GetBackgroundGradient(double *gradstart, double *gradslope)
{
  return false;
}

// for slider
LICE_IBitmap *WDL_STYLE_GetSliderBitmap2(bool vert)
{
  return NULL;
}

bool WDL_STYLE_AllowSliderMouseWheel()
{
  return false;
}

int WDL_STYLE_GetSliderDynamicCenterPos()
{
  return 0;
}

// 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()
{}
