/*
 * Deskflow -- mouse and keyboard sharing utility
 * Copyright (C) 2012-2016 Symless Ltd.
 * Copyright (C) 2003 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 "arch/IArchMultithread.h"
#include "arch/IArchTaskBar.h"
#include "common/stdmap.h"
#include "common/stdvector.h"

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#define ARCH_TASKBAR ArchTaskBarWindows

//! Win32 implementation of IArchTaskBar
class ArchTaskBarWindows : public IArchTaskBar
{
public:
  ArchTaskBarWindows();
  virtual ~ArchTaskBarWindows();

  virtual void init();

  //! Add a dialog window
  /*!
  Tell the task bar event loop about a dialog.  Win32 annoyingly
  requires messages destined for modeless dialog boxes to be
  dispatched differently than other messages.
  */
  static void addDialog(HWND);

  //! Remove a dialog window
  /*!
  Remove a dialog window added via \c addDialog().
  */
  static void removeDialog(HWND);

  // IArchTaskBar overrides
  virtual void addReceiver(IArchTaskBarReceiver *);
  virtual void removeReceiver(IArchTaskBarReceiver *);
  virtual void updateReceiver(IArchTaskBarReceiver *);

private:
  class ReceiverInfo
  {
  public:
    UINT m_id;
  };

  using ReceiverToInfoMap = std::map<IArchTaskBarReceiver *, ReceiverInfo>;
  using CIDToReceiverMap = std::map<UINT, ReceiverToInfoMap::iterator>;
  using CIDStack = std::vector<UINT>;
  using Dialogs = std::map<HWND, bool>;

  UINT getNextID();
  void recycleID(UINT);

  void addIcon(UINT);
  void removeIcon(UINT);
  void updateIcon(UINT);
  void addAllIcons();
  void removeAllIcons();
  void modifyIconNoLock(ReceiverToInfoMap::const_iterator, DWORD taskBarMessage);
  void removeIconNoLock(UINT id);
  void handleIconMessage(IArchTaskBarReceiver *, LPARAM);

  bool processDialogs(MSG *);
  LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
  static LRESULT CALLBACK staticWndProc(HWND, UINT, WPARAM, LPARAM);
  void threadMainLoop();
  static void *threadEntry(void *);

  HINSTANCE instanceWin32();

private:
  static ArchTaskBarWindows *s_instance;

  // multithread data
  ArchMutex m_mutex;
  ArchCond m_condVar;
  bool m_ready;
  int m_result;
  ArchThread m_thread;

  // child thread data
  HWND m_hwnd;
  UINT m_taskBarRestart;

  // shared data
  ReceiverToInfoMap m_receivers;
  CIDToReceiverMap m_idTable;
  CIDStack m_oldIDs;
  UINT m_nextID;

  // dialogs
  Dialogs m_dialogs;
  Dialogs m_addedDialogs;
};
