/* 
 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program 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, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#ifndef _MFORMS_MENUBAR_H_
#define _MFORMS_MENUBAR_H_

#include "base/trackable.h"
#include <mforms/box.h>
#include <mforms/app.h>
#include <vector>

namespace mforms {
  class MenuItem;
  class MenuBar;
  class MenuBase;

  enum MenuItemType
  {
    NormalMenuItem = 0,
    CheckedMenuItem,
    SeparatorMenuItem
  };

  // This merges functionality of menus and menu items.
  struct MFORMS_EXPORT MenuItemImplPtrs
  {
    bool (__stdcall *create_menu_bar)(MenuBar *item);
    bool (__stdcall *create_menu_item)(MenuItem *item, const std::string &, const MenuItemType type);
    void (__stdcall *set_title)(MenuItem *item, const std::string&);
    std::string (__stdcall *get_title)(MenuItem *item);
    void (__stdcall *set_shortcut)(MenuItem *item, const std::string&);
    void (__stdcall *set_enabled)(MenuBase *item, bool);
    bool (__stdcall *get_enabled)(MenuBase *item);
    void (__stdcall *set_checked)(MenuItem *item, bool);
    bool (__stdcall *get_checked)(MenuItem *item);

    void (__stdcall *insert_item)(MenuBase *menu, int index, MenuItem *item);
    void (__stdcall *remove_item)(MenuBase *menu, MenuItem *item); // NULL item to remove all
  }; 

  
  // base abstract class for menuitem and menubase
  class MFORMS_EXPORT MenuBase : public Object, public base::trackable
  {
  protected:
    MenuBase();

    MenuItemImplPtrs *_impl;
    MenuBase *_parent;
    std::vector<MenuItem*> _items;

  public:
    virtual ~MenuBase();
    
    std::vector<MenuItem*> &get_subitems() { return _items; }
    
    MenuItem *find_item(const std::string &name);
    
    void add_item(MenuItem *item);
    void insert_item(int index, MenuItem *item);
    void remove_all();
    void remove_item(MenuItem *item);
    void set_enabled(bool flag);
    bool get_enabled();
    
    virtual void validate();
    
    MenuBase *get_parent() { return  _parent; }
    MenuBar *get_menubar();
  };
  
  /** A menu item that can be added to the host application menus.
   
   */
  class MFORMS_EXPORT MenuItem : public MenuBase
  {
  public:
    /** Constructor
     
     @param title - passing an empty title in the constructor will make the item be a separator
     */
    MenuItem(const std::string &title, const MenuItemType type = NormalMenuItem); 
    
    void set_title(const std::string &title);
    std::string get_title();
    
    void set_shortcut(const std::string &shortcut);
        
    void set_checked(bool flag);
    bool get_checked();
    
    boost::signals2::signal<void ()>* signal_clicked() { return &_clicked_signal; }
    
    void set_name(const std::string &name);
    std::string get_name() { return _name; }
    
    void set_validator(const boost::function<bool ()> &slot);
    
  public:
    void callback();
    virtual void validate();

  private:
    std::string _name;
    boost::function<bool ()> _validate;
    boost::signals2::signal<void ()> _clicked_signal;
  };

  
  
  /** A menu that can be added to the host application.
   
   */
  class MFORMS_EXPORT MenuBar : public MenuBase
  {
  public:
    /** Constructor
     
     @param 
     */
    MenuBar();
    
    boost::signals2::signal<void (MenuItem*)>* signal_will_show() { return &_signal_will_show; }

    void set_item_enabled(const std::string &item_name, bool flag);
    void set_item_checked(const std::string &item_name, bool flag);
    
  public:
    void will_show_submenu_from(MenuItem *item);
    
  private:
    boost::signals2::signal<void (MenuItem*)> _signal_will_show;
  };

};

#endif
