/*
 * Deskflow -- mouse and keyboard sharing utility
 * Copyright (C) 2012-2016 Symless Ltd.
 * Copyright (C) 2002 Chris Schoeneman
 *
 * This package is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * found in the file LICENSE that should have accompanied this file.
 *
 * This package is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "base/String.h"
#include "common/stdset.h"
#include "common/stdstring.h"

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#include <Tlhelp32.h>

//! Miscellaneous win32 functions.
class ArchMiscWindows
{
public:
  enum EValueType
  {
    kUNKNOWN,
    kNO_VALUE,
    kUINT,
    kSTRING,
    kBINARY
  };
  enum EBusyModes
  {
    kIDLE = 0x0000,
    kSYSTEM = 0x0001,
    kDISPLAY = 0x0002
  };

  typedef int (*RunFunc)(void);

  //! Initialize
  static void init();

  //! Delete memory
  static void cleanup();

  //! Set the application icons
  /*!
  Set the application icons.
  */
  static void setIcons(HICON largeIcon, HICON smallIcon);

  //! Get the application icons
  /*!
  Get the application icons.
  */
  static void getIcons(HICON &largeIcon, HICON &smallIcon);

  //! Run the daemon
  /*!
  Delegates to ArchDaemonWindows.
  */
  static int runDaemon(RunFunc runFunc);

  //! Indicate daemon is in main loop
  /*!
  Delegates to ArchDaemonWindows.
  */
  static void daemonRunning(bool running);

  //! Indicate failure of running daemon
  /*!
  Delegates to ArchDaemonWindows.
  */
  static void daemonFailed(int result);

  //! Get daemon quit message
  /*!
  Delegates to ArchDaemonWindows.
  */
  static UINT getDaemonQuitMessage();

  //! Open and return a registry key, closing the parent key
  static HKEY openKey(HKEY parent, const TCHAR *child);

  //! Open and return a registry key, closing the parent key
  static HKEY openKey(HKEY parent, const TCHAR *const *keyPath);

  //! Open/create and return a registry key, closing the parent key
  static HKEY addKey(HKEY parent, const TCHAR *child);

  //! Open/create and return a registry key, closing the parent key
  static HKEY addKey(HKEY parent, const TCHAR *const *keyPath);

  //! Close a key
  static void closeKey(HKEY);

  //! Delete a key (which should have no subkeys)
  static void deleteKey(HKEY parent, const TCHAR *name);

  //! Delete a value
  static void deleteValue(HKEY parent, const TCHAR *name);

  //! Test if a value exists
  static bool hasValue(HKEY key, const TCHAR *name);

  //! Get type of value
  static EValueType typeOfValue(HKEY key, const TCHAR *name);

  //! Set a string value in the registry
  static void setValue(HKEY key, const TCHAR *name, const std::string &value);

  //! Set a DWORD value in the registry
  static void setValue(HKEY key, const TCHAR *name, DWORD value);

  //! Set a BINARY value in the registry
  /*!
  Sets the \p name value of \p key to \p value.data().
  */
  static void setValueBinary(HKEY key, const TCHAR *name, const std::string &value);

  //! Read a string value from the registry
  static std::string readValueString(HKEY, const TCHAR *name);

  //! Read a DWORD value from the registry
  static DWORD readValueInt(HKEY, const TCHAR *name);

  //! Read a BINARY value from the registry
  static std::string readValueBinary(HKEY, const TCHAR *name);

  //! Add a dialog
  static void addDialog(HWND);

  //! Remove a dialog
  static void removeDialog(HWND);

  //! Process dialog message
  /*!
  Checks if the message is destined for a dialog.  If so the message
  is passed to the dialog and returns true, otherwise returns false.
  */
  static bool processDialog(MSG *);

  //! Disable power saving
  static void addBusyState(DWORD busyModes);

  //! Enable power saving
  static void removeBusyState(DWORD busyModes);

  //! Briefly interrupt power saving
  static void wakeupDisplay();

  //! Returns true if this process was launched via NT service host.
  static bool wasLaunchedAsService();

  //! Returns true if we got the parent process name.
  static bool getParentProcessName(String &name);

  static HINSTANCE instanceWin32();

  static void setInstanceWin32(HINSTANCE instance);

  static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID);
  static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32 &entry);
  static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32 &entry);

private:
  //! Open and return a registry key, closing the parent key
  static HKEY openKey(HKEY parent, const TCHAR *child, bool create);

  //! Open and return a registry key, closing the parent key
  static HKEY openKey(HKEY parent, const TCHAR *const *keyPath, bool create);

  //! Read a string value from the registry
  static std::string readBinaryOrString(HKEY, const TCHAR *name, DWORD type);

  //! Set thread busy state
  static void setThreadExecutionState(DWORD);

  static DWORD WINAPI dummySetThreadExecutionState(DWORD);

private:
  using Dialogs = std::set<HWND>;
  typedef DWORD(WINAPI *STES_t)(DWORD);

  static Dialogs *s_dialogs;
  static DWORD s_busyState;
  static STES_t s_stes;
  static HICON s_largeIcon;
  static HICON s_smallIcon;
  static HINSTANCE s_instanceWin32;
};
