#pragma once

#ifndef TNZ_POPUPMENU_INCLUDED
#define TNZ_POPUPMENU_INCLUDED

#include "tw/action.h"
#include "tw/popup.h"
#include "tw/button.h"

#undef DVAPI
#undef DVVAR
#ifdef TWIN_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif

//-------------------------------------------------------------

class TPopupMenu;
class TPopupMenuItem;

//-------------------------------------------------------------

class DVAPI TPopupMenuListener {
public:
  TPopupMenuListener() {}
  virtual ~TPopupMenuListener() {}

  virtual void onMenuSelect(TPopupMenuItem *item) = 0;
};

//-------------------------------------------------------------

class DVAPI TPopupMenuItem : public TButton {
  wstring m_title;
  bool m_selected;

public:
  TPopupMenuItem(TPopupMenu *parent, string name);
  void repaint();

  void enter(const TPoint &);
  void leave(const TPoint &);

  void leftButtonDown(const TMouseEvent &e);
  void leftButtonUp(const TMouseEvent &e);

  void setTitle(wstring title);

  TPopupMenu *getPopup();

  void select(bool on);
  bool isSelected() const { return m_selected; }

  virtual int getWidth();
};

//-------------------------------------------------------------

class DVAPI TPopupMenuSeparator : public TWidget {
public:
  TPopupMenuSeparator(TPopupMenu *parent);
  void repaint();
};

//-------------------------------------------------------------

//
// Note: to implement right-mouse-bottom menu use
// the class TContextMenu (see below)
//

class DVAPI TPopupMenu : public TPopup {
  TPopupMenuItem *m_currentItem;
  TPopupMenuListener *m_listener;
  int m_firstVisibleItem;
  int m_visibleItemCount;
  bool m_leftAlignment;

public:
  TPopupMenu(TWidget *parent, string name = "popupMenu");
  void draw();
  void configureNotify(const TDimension &);

  void leftButtonDrag(const TPoint &, UCHAR);
  void leftButtonUp(const TPoint &);

  void popup(const TPoint &pos, int width = 120);
  void close();

  TPopupMenuItem *getCurrentItem() { return m_currentItem; }
  void setListener(TPopupMenuListener *);

  static TPopupMenu *getCurrentMenu();

  void setLeftAlignment(bool a) { m_leftAlignment = a; }

private:
  void updateItemsVisibility();
  void updateSize();
  void computeSize(TPoint &pos, int maxY);

  friend class TPopupMenuArrow;
};

//-------------------------------------------------------------

//
// TContextMenu :
//  a class specifically dedicated to
//  right-mouse-button popup menu (aka Context Menu)
//
// Note: DON'T use the method popup() (inherited from TPopupMenu)
//
// Note: the context menu will be automatically destroyed
// DON'T keep a reference to the context menu
//
// see examples below
//

/*---- Example 1 (position independent) ----

   void Pluto::rightButtonUp(const TMouseEvent &e) {
     TContextMenu *menu = new TContextMenu(this);
     menu->addCommand("MI_Cut");
     menu->addCommand("MI_Copy");
     menu->addCommand("MI_Paste");
     menu->addCommand("MI_Clear");
     TContextMenu::open(menu, e.m_pos);
   }


  ---- Example 2 (position dependent) ----


   class MyContextMenu : public TContextMenu {
     int m_myValue;
   public:
     MyContextMenu(TWidget*parent, int myValue)
     : TContextMenu(parent), m_myValue(myValue), m_col(col) {
        tconnect(this, "foo",  this, &CellContextMenu::onFoo);
        tconnect(this, "bar",  this, &CellContextMenu::onBar);
     }
     void onFoo() { ... }
     void onBar() { ... }
   };

   void Pluto::rightButtonUp(const TMouseEvent &e) {
     int row = ....
     int col = ....
     TContextMenu::open(new CellContextMenu(this, row, col), e.m_pos);
   }

  -----------------------------------------*/

class DVAPI TContextMenu : public TPopupMenu {
public:
  class CommandFilter {
  public:
    virtual bool check(string cmdName) const = 0;
    virtual ~CommandFilter() {}
  };

  TContextMenu(TWidget *parent);

  void add(string name, TGenericCommandAction *action);
  void addCommand(string cmdName);
  void addCommand(string cmdName, TGenericCommandAction *action);

  void addSeparator() { new TPopupMenuSeparator(this); }

  /*
template <class T>
inline void addCommand(string cmdName, T*target, void (T::*method)()) {
//addCommand(cmdName, new TCommandAction<T>(target, method));
}
*/
  static void open(TContextMenu *menu, const TPoint &pos);

  static void setCommandFilter(CommandFilter *filter);

  void onTimer(int);
};

template <class T>
inline void tconnect(TContextMenu *menu, string cmdName, T *target,
                     void (T::*method)()) {
  menu->addCommand(cmdName, new TCommandAction<T>(target, method));
}

template <class T, class Arg>
inline void tconnect(TContextMenu *menu, string cmdName, T *target,
                     void (T::*method)(Arg), Arg arg) {
  menu->addCommand(cmdName, new TCommandAction1<T, Arg>(target, method, arg));
}

#endif
