/* 
 * © 2007-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#ifndef _PLUGIN_MANAGER_H_
#define _PLUGIN_MANAGER_H_

#include <grtpp.h>
#include <grtpp_module_cpp.h>

#include "grts/structs.h"
#include "grts/structs.app.h"
#include "wbpublic_public_interface.h"


#ifdef __GNUC__ 
typedef void* NativeHandle;
#else
typedef __int64 NativeHandle;
#endif

// GUI plugins with native code that are loaded and managed by the Workbench process
#define GUI_PLUGIN_TYPE "gui"
// GUI plugins that are standalone and can be called directly by the module system (eg mforms)
#define STANDALONE_GUI_PLUGIN_TYPE "standalone"
// normal plugins with no UI
#define NORMAL_PLUGIN_TYPE "normal"

namespace bec {

  #define PluginManager_VERSION "1.0.0"
  
  class BaseEditor;
  class GRTManager;

  typedef enum {
    NoFlags= 0,
    ForceNewWindowFlag = (1<<0)
  } GUIPluginFlags;


  class WBPUBLICBACKEND_PUBLIC_FUNC PluginManagerImpl : public grt::CPPModule
  {
    typedef grt::CPPModule superclass;

  public:
    typedef sigc::slot<NativeHandle, GRTManager*, grt::Module*, std::string, std::string, grt::BaseListRef, GUIPluginFlags> OpenGUIPluginSlot;
    typedef sigc::slot<void, NativeHandle> ShowGUIPluginSlot;
    typedef sigc::slot<void, NativeHandle> CloseGUIPluginSlot;
    
  public:
    // NOTE: not to be directly instantiated
    PluginManagerImpl(grt::CPPModuleLoader *loader);
    virtual ~PluginManagerImpl() {}

    void set_registry_paths(const std::string &plugins_path,
                            const std::string &groups_path);

    void rescan_plugins();

    DEFINE_INIT_MODULE(PluginManager_VERSION, "MySQL AB", grt::ModuleImplBase,
                       DECLARE_MODULE_FUNCTION(PluginManagerImpl::show_plugin),
                       DECLARE_MODULE_FUNCTION(PluginManagerImpl::close_plugin)
                       );

    // generic plugin interface

    // ordered by rating
    std::vector<app_PluginRef> get_plugins_for_objects(const grt::ObjectListRef &objects, 
                                                    const std::string &group="");

    std::vector<app_PluginRef> get_plugins_for_object(const grt::ObjectRef &object,
                                                   const std::string &group="");

    std::vector<app_PluginRef> get_plugins_for_group(const std::string &group);

    app_PluginRef get_plugin(const std::string &name);

    std::string open_plugin(const app_PluginRef &plugin, const grt::BaseListRef &args);
    std::string open_gui_plugin(const app_PluginRef &plugin, const grt::BaseListRef &args, GUIPluginFlags flags);

    std::string open_plugin_with_object(const app_PluginRef &plugin, GrtObjectRef object);
    std::string open_plugin_with_selection(const app_PluginRef &plugin, const grt::ObjectListRef &selection);
    std::string open_plugin_with_file(const app_PluginRef &plugin, const std::string &filename);


    int show_plugin(const std::string &handle);
    int close_plugin(const std::string &handle);

    app_PluginRef select_plugin_for_input(const std::string &group, const grt::BaseListRef &args);
    app_PluginRef select_editor_plugin(const std::string &group_path, GrtObject object);


    bool check_plugin_input(const app_PluginInputDefinitionRef &def, const grt::ValueRef &value);

  public: // for frontends
    void register_plugins(grt::ListRef<app_Plugin> plugins);

    void set_gui_plugin_callbacks(const OpenGUIPluginSlot &open,
                                  const ShowGUIPluginSlot &show,
                                  const CloseGUIPluginSlot &close);

    void forget_gui_plugin_handle(NativeHandle handle);

    std::vector<NativeHandle> get_similar_open_plugins(grt::Module*, const std::string &class_name, grt::BaseListRef);


  protected:
    GRTManager *_grtm;
    std::string _registry_path;
    std::string _group_registry_path;
    
    OpenGUIPluginSlot _open_gui_plugin_slot;
    ShowGUIPluginSlot _show_gui_plugin_slot;
    CloseGUIPluginSlot _close_gui_plugin_slot;

    // plugin-name+oid -> editor handle
    std::map<std::string, NativeHandle> _open_gui_plugins;
    
    // plugin name -> module name
    std::map<std::string, std::string> _plugin_source_module;

  private:
    grt::ListRef<app_PluginGroup> get_plugin_groups();
    grt::ListRef<app_Plugin> get_plugin_list(const std::string &group="");

    bool check_input_for_plugin(const app_PluginRef &plugin, const grt::BaseListRef &args);

    grt::ValueRef open_normal_plugin_grt(grt::GRT *grt, const app_PluginRef &plugin, const grt::BaseListRef &args);

    std::string open_gui_plugin_main(const app_PluginRef &plugin, const grt::BaseListRef &args, GUIPluginFlags flags);
    int show_gui_plugin_main(const std::string &handle);
    int close_gui_plugin_main(const std::string &handle);
    
    void open_standalone_plugin_main(const app_PluginRef &plugin, const grt::BaseListRef &args);

    app_PluginGroupRef get_group(const std::string &path);
    void add_plugin_to_group(const app_PluginRef &plugin, const std::string &path);
    
    bool check_plugin_validity(const app_PluginRef &plugin, grt::Module *module);
  };

  typedef ::bec::PluginManagerImpl PluginManager;
  
};




#endif /* _PLUGIN_MANAGER_H_ */
