std::string PluginManagerImpl::open_gui_plugin_main(const app_PluginRef &plugin,
                                                    const grt::BaseListRef &args,
                                                    GUIPluginFlags flags)
{
  NativeHandle handle;
  grt::Module *module= _grtm->get_grt()->get_module(_plugin_source_module[plugin->name()]);
  std::string open_plugin_id= make_open_plugin_id(module, plugin->moduleFunctionName(), args);

  if (_open_gui_plugins.find(open_plugin_id) != _open_gui_plugins.end())
  {
    handle= _open_gui_plugins[open_plugin_id];
    _show_gui_plugin_slot(handle);
  }
  else
  {
    grt::Module *module= _grtm->get_grt()->get_module(_plugin_source_module[plugin->name()]);

    // open the editor and get a handle for the GUI object to pass to the frontend
    NativeHandle handle= _open_gui_plugin_slot(_grtm,
                                               module,
                                               *plugin->moduleName(),
                                               *plugin->moduleFunctionName(),
                                               args,
                                               flags);
    if (handle)
    {
      _open_gui_plugins[open_plugin_id]= handle;
      _show_gui_plugin_slot(handle);
    }
  }

  return open_plugin_id;
}
void PluginManagerImpl::set_plugin_enabled(const app_PluginRef &plugin, bool flag)
{
  grt::StringListRef disabled_list(get_disabled_plugin_names());  
  size_t idx= disabled_list.get_index(plugin->name());
  
  if (flag && idx != grt::BaseListRef::npos)
  {
    disabled_list.remove(idx);
    if (plugin->groups().count() == 0)
      add_plugin_to_group(plugin, "Others/Menu/Ungrouped");
    else
    {
      for (size_t d= plugin->groups().count(), j= 0; j < d; j++)
        add_plugin_to_group(plugin, plugin->groups()[j]);
    }
  }
  else if (!flag && idx == grt::BaseListRef::npos)
  {
    disabled_list.insert(plugin->name());
    // remove the plugin from all groups
    grt::ListRef<app_PluginGroup> groups(get_plugin_groups());
    for (size_t c = groups.count(), i = 0; i < c; i++)
      groups[i]->plugins().remove_value(plugin);
  }
}
void PluginManagerImpl::open_standalone_plugin_main(const app_PluginRef &plugin, const grt::BaseListRef &args)
{
  grt::Module *module= _grtm->get_grt()->get_module(plugin->moduleName());
  
  if (!module)
    throw grt::grt_runtime_error("Cannot execute plugin "+*plugin->name(), "Called module "+*plugin->moduleName()+" not found");
  
  module->call_function(*plugin->moduleFunctionName(), args);
}
bool PluginManagerImpl::check_plugin_validity(const app_PluginRef &plugin, grt::Module *module)
{
  if (plugin->pluginType() == GUI_PLUGIN_TYPE)
  {
    // not much that can be tested here, maybe check if the dll actually exists
    return true;
  }
  else if (plugin->pluginType() == STANDALONE_GUI_PLUGIN_TYPE
           || plugin->pluginType() == NORMAL_PLUGIN_TYPE)
  {
    // check if the module matches and the function exists
    if (plugin->moduleName() != module->name())
    {
      g_warning("Plugin '%s' from module %s declares moduleName() as '%s', which doesn't match the module it belongs to",
                plugin->name().c_str(), module->name().c_str(), plugin->moduleName().c_str());
      return false;
    }
    
    {
      std::string f= plugin->moduleFunctionName();
      if (!module->has_function(f))
      {
         g_warning("Plugin '%s' from module %s has invalid moduleFunctionName '%s'",
                  plugin->name().c_str(), module->name().c_str(), f.c_str());
        return false;
      }
    } 
    return true;
  }
  else if (plugin->pluginType() == INTERNAL_PLUGIN_TYPE)
  {
    return true;
  }
  else if (0 == (*plugin->pluginType()).find(CUSTOM_PLUGIN_TYPE))
  {
    return true;
  }
  else
  {    
    g_warning("Plugin '%s' from module %s has invalid type '%s'", plugin->name().c_str(), 
              module->name().c_str(), plugin->pluginType().c_str());
  }
  return false;
}
grt::ValueRef PluginManagerImpl::open_normal_plugin_grt(grt::GRT *grt, const app_PluginRef &plugin,
                                                            const grt::BaseListRef &args)
{
  grt::Module *module= _grtm->get_grt()->get_module(plugin->moduleName());

  if (!module)
    throw grt::grt_runtime_error("Cannot execute plugin "+*plugin->name(), "Called module "+*plugin->moduleName()+" not found");

  return module->call_function(*plugin->moduleFunctionName(), args);
}
grt::BaseListRef ArgumentPool::build_argument_list(const app_PluginRef &plugin)
{
  // build the argument list
  grt::BaseListRef fargs(plugin->get_grt());
  
  const size_t c= plugin->inputValues().count();
  for (size_t i= 0; i < c; i++)
  {
    app_PluginInputDefinitionRef pdef(plugin->inputValues().get(i));
    std::string searched_key;
    grt::ValueRef argument= find_match(pdef, searched_key);
    if (!argument.is_valid())
    {
      log_warning("Cannot satisfy plugin input for %s: %s", plugin->name().c_str(), searched_key.c_str());
      log_warning("Missing input: %s", pdef.repr().c_str());
      
      throw grt::grt_runtime_error("Cannot execute "+*plugin->name(),
                                   "Plugin requires unavailable argument value.");
    }
    fargs.ginsert(argument);
  }  
  return fargs;
}
bool GRTManager::check_plugin_runnable(const app_PluginRef &plugin, const bec::ArgumentPool &argpool,
                                       bool debug_output)
{
  bool debug_args = strstr(plugin->name().c_str(), "-debugargs-") != 0 || debug_output;
  
  for (size_t c= plugin->inputValues().count(), i= 0; i < c; i++)
  {
    app_PluginInputDefinitionRef pdef(plugin->inputValues()[i]);
    std::string searched_key;
    if (!argpool.find_match(pdef, searched_key, false).is_valid())
    {
      if (debug_args)
      {
        _grt->send_output(base::strfmt("Debug: Plugin %s cannot execute because argument %s is not available\n",
                                       plugin->name().c_str(), searched_key.c_str()));
        _grt->send_output("Debug: Available arguments:\n");
        argpool.dump_keys(boost::bind(&grt::GRT::send_output, _grt, _1, (void*)0));
      }
      return false;
    }
  }
  return true;
}
std::string PluginManagerImpl::open_gui_plugin(const app_PluginRef &plugin, const grt::BaseListRef &args,
  GUIPluginFlags flags)
{
  if (!plugin.is_valid())
    throw std::invalid_argument("Attempt to open an invalid plugin");
  
  GRTDispatcher::Ref dispatcher = _grtm->get_dispatcher();
  if (*plugin->pluginType() == GUI_PLUGIN_TYPE)
  {
    if (_grtm->in_main_thread())
      return open_gui_plugin_main(plugin, args, flags);
    else
    {
      // Request the plugin to be executed and opened by the frontend in the main thread.
      DispatcherCallback<std::string>::Ref cb = DispatcherCallback<std::string>::create_callback(
        boost::bind(&PluginManagerImpl::open_gui_plugin_main, this, plugin, args, flags)
      );

      dispatcher->call_from_main_thread(cb, false, false);
      
      grt::Module *module= _grtm->get_grt()->get_module(_plugin_source_module[plugin->name()]);

      // Build the handle name ourselves.
      return make_open_plugin_id(module, plugin->moduleFunctionName(), args);
    }
  }
  else if (*plugin->pluginType() == STANDALONE_GUI_PLUGIN_TYPE)
  {
    if (_grtm->in_main_thread())
      open_standalone_plugin_main(plugin, args);
    else
    {
      // Request the plugin to be executed and opened by the frontend in the main thread.
      DispatcherCallback<void>::Ref cb = DispatcherCallback<void>::create_callback(
        boost::bind(&PluginManagerImpl::open_standalone_plugin_main, this, plugin, args)
      );
      dispatcher->call_from_main_thread(cb, false, false);
    }
  }
  else if (*plugin->pluginType() == INTERNAL_PLUGIN_TYPE)
  {
    if (_grtm->in_main_thread())
      open_normal_plugin_grt(_grtm->get_grt(), plugin, args);
    else
    {
      // Request the plugin to be executed and opened by the frontend in the main thread.
      DispatcherCallback<grt::ValueRef>::Ref cb = DispatcherCallback<grt::ValueRef>::create_callback(
        boost::bind(&PluginManagerImpl::open_normal_plugin_grt, this, _grtm->get_grt(), plugin, args)
      );
      
      dispatcher->call_from_main_thread(cb, false, false);
    }
  }
  else // A normal plugin implemented by a GRT module.
  {
    // Opening a normal plugin is usually done in the context of the grt thread and we want to
    // continue that way. But if we are currently in the main thread switch here to the grt thread
    // for opening the plugin.
    if (_grtm->in_main_thread())
    {
      _grtm->get_dispatcher()->execute_sync_function("Open normal plugin",
        boost::bind(&PluginManagerImpl::open_normal_plugin_grt, this, _1, plugin, args));
    }
    else
      open_normal_plugin_grt(_grtm->get_grt(), plugin, args);
  }
  return "";
}