// Copyright 2010-2020, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef MOZC_WIN32_TIP_TIP_LANG_BAR_MENU_H_
#define MOZC_WIN32_TIP_TIP_LANG_BAR_MENU_H_

#include <msctf.h>
#include <rpcsal.h>
#include <windows.h>

#include <string>
#include <vector>

#include "win32/tip/tip_lang_bar.h"
#include "win32/tip/tip_ref_count.h"

namespace mozc {
namespace win32 {
namespace tsf {

// MIDL_INTERFACE expects a string literal rather than a constant array of
// characters.
#ifdef GOOGLE_JAPANESE_INPUT_BUILD
#define IIDSTR_IMozcLangBarItem "C6057858-8A94-4B40-8C99-D1C4B4A0B9DB"
#define IIDSTR_IMozcLangBarToggleItem "72B4C4E3-B9F3-478A-B8A8-753AFF37EB94"
#else
#define IIDSTR_IMozcLangBarItem "75B2153A-504B-48C9-9257-BA8D60E523E6"
#define IIDSTR_IMozcLangBarToggleItem "9ABF0C3B-4AC6-4DED-9EF6-97E728852CF3"
#endif

class TipBarCallback;

enum TipLangBarItemFlags {
  kTipLangBarItemTypeDefault = 0,
  kTipLangBarItemTypeChecked = TF_LBMENUF_CHECKED,  // 0x1
  // ImeLangBarItemTypeSubMenu = TF_LBMENUF_SUBMENU  // 0x2 (not supported)
  kTipLangBarItemTypeSeparator = TF_LBMENUF_SEPARATOR,        // 0x4
  kTipLangBarItemTypeRadioChecked = TF_LBMENUF_RADIOCHECKED,  // 0x8
  kTipLangBarItemTypeGrayed = TF_LBMENUF_GRAYED,              // 0x10
};

// Represents a tuple to specify the content of a language bar menu item.
struct TipLangBarMenuItem {
  int flags_;
  UINT item_id_;
  UINT text_id_;
  UINT icon_id_for_non_theme_;
  UINT icon_id_for_theme_;
};

// Reperesents the data possessed internally by a language bar menu item.
struct TipLangBarMenuData {
  int flags_;
  UINT item_id_;
  UINT text_id_;
  UINT icon_id_for_non_theme_;
  UINT icon_id_for_theme_;
  int length_;
  wchar_t text_[TF_LBI_DESC_MAXLEN];
};

// Reperesents the data possessed by a language bar menu.
class TipLangBarMenuDataArray {
 public:
  HRESULT Init(HINSTANCE instance, const TipLangBarMenuItem *menu, int count);

  size_t size() const;
  TipLangBarMenuData *data(size_t i);

 private:
  std::vector<TipLangBarMenuData> data_;
};

MIDL_INTERFACE(IIDSTR_IMozcLangBarItem)
IMozcLangBarItem : public IUnknown {
  // Sets the status of this language bar menu.
  virtual STDMETHODIMP SetEnabled(bool enabled) = 0;
};

MIDL_INTERFACE(IIDSTR_IMozcLangBarToggleItem)
IMozcLangBarToggleItem : public IUnknown {
  // Selects a menu item which has the given |menu_id|.
  virtual STDMETHODIMP SelectMenuItem(UINT menu_id) = 0;
};

// Represents the common operations for a button-menu item in the language bar.
class TipLangBarButton : public ITfLangBarItemButton,
                         public ITfSource,
                         public IMozcLangBarItem {
 public:
  TipLangBarButton(TipLangBarCallback *langbar_callback, const GUID &guid,
                   bool is_menu, bool show_in_tray);
  // It is OK to declare the destructor as non-virtual because all the
  // insbtances will be deleted from and only from the Release() method by
  // |delete this| where |this| has the true (derived) type of the instance.
  ~TipLangBarButton();

  // The IUnknown interface methods
  virtual STDMETHODIMP QueryInterface(REFIID guid, void **object) = 0;
  virtual STDMETHODIMP_(ULONG) AddRef() = 0;
  virtual STDMETHODIMP_(ULONG) Release() = 0;

  // The ITfLangBarItem interface methods
  virtual STDMETHODIMP GetInfo(TF_LANGBARITEMINFO *item_info) = 0;
  virtual STDMETHODIMP GetStatus(DWORD *status);
  virtual STDMETHODIMP Show(BOOL show);
  virtual STDMETHODIMP GetTooltipString(BSTR *tooltip);

  // The ITfLangBarItemButton interface methods
  virtual STDMETHODIMP OnClick(TfLBIClick clink, POINT point, const RECT *rect);
  virtual STDMETHODIMP InitMenu(ITfMenu *menu) = 0;
  virtual STDMETHODIMP OnMenuSelect(UINT menu_id) = 0;
  virtual STDMETHODIMP GetIcon(HICON *icon) = 0;
  virtual STDMETHODIMP GetText(BSTR *text);

  // The ITfSource interface methods
  virtual STDMETHODIMP AdviseSink(REFIID interface_id, IUnknown *unknown,
                                  DWORD *cookie);
  virtual STDMETHODIMP UnadviseSink(DWORD cookie);

  // The IMozcLangBarItem interface method
  virtual STDMETHODIMP SetEnabled(bool enabled);

  // Initializes an ImeButtonMenu instance.
  // This function allocates resources for an ImeButtonMenu instance.
  HRESULT Init(HINSTANCE instance, int string_id,
               const TipLangBarMenuItem *menu, int count);

  // Notifies the language bar of a change in a language bar item.
  STDMETHODIMP OnUpdate(DWORD update_flag);

  // Returns true if a 32-bpp icon can be displayed as a context menu item on
  // the LangBar.  See http://b/2260057 and http://b/2265755
  // for details.
  static bool CanContextMenuDisplay32bppIcon();

 protected:
  STDMETHODIMP QueryInterfaceBase(REFIID guid, void **object);

  // Update the item description. The caller is also responsible for calling
  // OnUpdate method to notify the change to the system.
  void SetDescription(const std::wstring &description);

  // Returns the i-th data in the language bar menu.
  // Returns nullptr if i is out of bounds.
  TipLangBarMenuData *menu_data(size_t i);

  // Returns the size of the language bar menu.
  size_t menu_data_size() const;

  // Returns the item information for langbar menu.
  const TF_LANGBARITEMINFO *item_info() const;

  // Returns true if the attribute is menu button.
  bool IsMenuButton() const;

  // Sets if context menu is enabled or not. Is setting affects only when
  // IsMenuButton() returns false.
  void SetContextMenuEnabled(bool enabled);

  ITfLangBarItemSink *item_sink_;
  TipLangBarCallback *langbar_callback_;

 private:
  // Represents the information of an instance copied to the TSF manager.
  // The TSF manager uses this information to identifies an instance as
  // a menu button.
  TF_LANGBARITEMINFO item_info_;

  // Represents the data possessed by the language bar menu.
  TipLangBarMenuDataArray menu_data_;

  // Records TF_LBI_STATUS_* bits and represents the status of the this langbar
  // menu.
  DWORD status_;

  // Represents if context menu is enabled or not. This flag is not used when
  // IsMenuButton() returns true.
  bool context_menu_enabled_;
};

// Represents the common operations for a button-menu item with an icon in the
// language bar.
class TipLangBarMenuButton : public TipLangBarButton {
 public:
  TipLangBarMenuButton(TipLangBarCallback *langbar_callback, const GUID &guid,
                       bool show_in_tray);

  // The IUnknown interface methods
  virtual STDMETHODIMP QueryInterface(REFIID guid, void **object);
  virtual STDMETHODIMP_(ULONG) AddRef();
  virtual STDMETHODIMP_(ULONG) Release();

  virtual STDMETHODIMP GetInfo(TF_LANGBARITEMINFO *item_info);

  // A part of the ITfLangBarItemButton interface methods
  virtual STDMETHODIMP InitMenu(ITfMenu *menu);
  virtual STDMETHODIMP OnMenuSelect(UINT menu_id);
  virtual STDMETHODIMP GetIcon(HICON *icon);

  // Initializes an ImeButtonMenu instance.
  // This function allocates resources for an ImeButtonMenu instance.
  HRESULT Init(HINSTANCE instance, UINT string_id,
               const TipLangBarMenuItem *menu, int count,
               UINT menu_icon_id_for_non_theme, UINT menu_icon_id_for_theme);

 private:
  TipRefCount ref_count_;

  // Represents the icon of the language bar menu.
  UINT menu_icon_id_for_theme_;
  UINT menu_icon_id_for_non_theme_;
};

// Represents the common operations for a toggle button-menu item in the
// language bar.
class TipLangBarToggleButton : public TipLangBarButton,
                               public IMozcLangBarToggleItem {
 public:
  TipLangBarToggleButton(TipLangBarCallback *langbar_callback, const GUID &guid,
                         bool is_menu, bool show_in_tray);
  virtual ~TipLangBarToggleButton();

  // The IUnknown interface methods
  virtual STDMETHODIMP QueryInterface(REFIID guid, void **object);
  virtual STDMETHODIMP_(ULONG) AddRef();
  virtual STDMETHODIMP_(ULONG) Release();

  // The IMozcLangBarToggleItem interface methods
  virtual STDMETHODIMP SelectMenuItem(UINT menu_id);

  // The IMozcLangBarItem interface method
  // Overridden from TipLangBarButton.
  virtual STDMETHODIMP SetEnabled(bool enabled);

  virtual STDMETHODIMP GetInfo(TF_LANGBARITEMINFO *item_info);

  virtual STDMETHODIMP InitMenu(ITfMenu *menu);
  virtual STDMETHODIMP OnMenuSelect(UINT menu_id);
  virtual STDMETHODIMP GetIcon(HICON *icon);

  // Initializes an ImeButtonMenu instance.
  // This function allocates resources for an ImeButtonMenu instance.
  HRESULT Init(HINSTANCE instance, int string_id,
               const TipLangBarMenuItem *menu, int count,
               const TipLangBarMenuItem &menu_for_disabled);

 private:
  TipRefCount ref_count_;

  // Represents the index of the selected menu item.
  UINT menu_selected_;
  bool disabled_;
  std::wstring description_for_enabled_;
  TipLangBarMenuData menu_data_for_disabled_;
};

// Represents the common operations for a button-menu item in the system
// language bar.
class TipSystemLangBarMenu : public ITfSystemLangBarItemSink {
 public:
  TipSystemLangBarMenu(TipLangBarCallback *langbar_callback, const GUID &guid);
  virtual ~TipSystemLangBarMenu();

  // The IUnknown interface methods
  virtual STDMETHODIMP QueryInterface(REFIID guid, void **object);
  virtual STDMETHODIMP_(ULONG) AddRef();
  virtual STDMETHODIMP_(ULONG) Release();

  // The ITfLangBarSystemItem interface methods
  virtual STDMETHODIMP InitMenu(ITfMenu *menu);
  virtual STDMETHODIMP OnMenuSelect(UINT menu_id);

  // Initializes an ImeButtonMenu instance.
  // This function allocates resources for an ImeButtonMenu instance.
  HRESULT Init(HINSTANCE instance, const TipLangBarMenuItem *menu, int count);

 private:
  TipRefCount ref_count_;
  TipLangBarCallback *langbar_callback_;

  // Represents the data possessed by the language bar menu.
  TipLangBarMenuDataArray menu_data_;
};

}  // namespace tsf
}  // namespace win32
}  // namespace mozc

#endif  // MOZC_WIN32_TIP_TIP_LANG_BAR_MENU_H_
