/*!
  Load the plugins.
  \param server The server object to use.
 */
int
PluginsManager::load (Server *server)
{
  list<string*> toRemove;
  HashMap<string, list<string>*> dependsOn;
  HashMap<string, PluginInfo*>::Iterator it = pluginsInfos.begin ();
  HashMap<string, bool> remove;
  while (it != pluginsInfos.end ())
    {
      string name (it.getKey ());
      PluginInfo* pinfo = *it;
      HashMap<string, pair<int, int>* >::Iterator depIt = pinfo->begin ();

      string msversion (MYSERVER_VERSION);
      size_t i = msversion.find ("-", 0);
      if (i != string::npos)
        msversion = msversion.substr (0, i);

      int msVersion = PluginInfo::convertVersion (msversion);
      if (msVersion < pinfo->getMyServerMinVersion ()
          || msVersion > pinfo->getMyServerMaxVersion ())
        server->log (MYSERVER_LOG_MSG_WARNING,
                            _("Plugin `%s' not compatible with this version"),
                            name.c_str ());
      else
        remove.put (name, false);

      for (; depIt != pinfo->end (); depIt++)
        {
          string dname = depIt.getKey ();

          list<string>* deps = dependsOn.get (dname);
          if (!deps)
            {
              deps = new list<string > ();
              dependsOn.put (dname, deps);
            }

          deps->push_front (name);
        }

      it++;
    }

  list<string*>::iterator tRIt = toRemove.begin ();
  for (; tRIt != toRemove.end (); tRIt++)
    removePlugin (**tRIt);
  toRemove.clear ();

  HashMap<string, list<string>*>::Iterator dIt = dependsOn.begin ();
  for (; dIt != dependsOn.end (); dIt++)
    {
      string logBuf;
      string dname = dIt.getKey ();

      PluginInfo* pinfo = getPluginInfo (dname);

      if (!pinfo || pinfo->getVersion () == 0)
        remove.put (dname, true);

      list<string>* dependsList = (*dIt);
      if (!dependsList)
        continue;
      if (dependsList->empty ())
        continue;

      bool rem = remove.get (dname);
      if (rem)
        {
          recursiveDependencesFallDown (server, dname, remove, dependsOn);
          continue;
        }

      HashMap<string, pair<int, int>* >::Iterator lit = pinfo->begin ();
      for (; lit != pinfo->end (); lit++)
        {
          string depN = lit.getKey ();
          PluginInfo* dep = getPluginInfo (depN);
          if (!dep || remove.get (depN))
            {
              server->log (MYSERVER_LOG_MSG_WARNING,
                                  _("Missing plugin dependence `%s' --> `%s'"),
                                  dname.c_str (), depN.c_str ());
              recursiveDependencesFallDown (server, dname, remove, dependsOn);
              break;
            }


          pair<int, int>* pdep = *lit;
          if (dep->getVersion () < pdep->first
              || dep->getVersion () > pdep->second)
            {
              recursiveDependencesFallDown (server, dname, remove, dependsOn);
              server->log (MYSERVER_LOG_MSG_WARNING,
                            _("Plugin `%s' not compatible with this version"),
                            dname.c_str ());
              break;
            }
        }
    }


  HashMap<string, bool>::Iterator rIt = remove.begin ();
  for (; rIt != remove.end (); rIt++)
    {
      string name (rIt.getKey ());
      if (*rIt)
        removePlugin (name);
    }

  for (it = pluginsInfos.begin (); it != pluginsInfos.end (); it++)
    (*it)->getPlugin ()->load (server);

  return 0;
}
bool PluginInfo::pluginSignInfoIsEqual(const PluginInfo& pluginInfo)
{
	return pluginName    == pluginInfo.getName() &&
	       pluginAuthor  == pluginInfo.getAuthor() &&
	       pluginVersion == pluginInfo.getVersion();
}
/*!
  Loads the plugin info.
  \param name The plugin name.
  \param path the plugin xml descriptor path.
 */
PluginInfo*
PluginsManager::loadInfo (Server* server, string &name, string &path)
{
  PluginInfo* pinfo = getPluginInfo (name);
  auto_ptr<PluginInfo> pinfoAutoPtr (NULL);
  if (!pinfo)
    pinfoAutoPtr.reset (pinfo = new PluginInfo (name));
  else if (pinfo->getVersion () != 0)
    return NULL;

  XmlParser xml;

  if (xml.open (path, true))
    {
      server->log (MYSERVER_LOG_MSG_ERROR,
                          _("Error loading plugin `%s'"), name.c_str ());
      return NULL;
    }

  auto_ptr<XmlXPathResult> xpathResPlugin = auto_ptr<XmlXPathResult>
    (xml.evaluateXpath ("/PLUGIN"));
  xmlNodeSetPtr nodes = xpathResPlugin->getNodeSet ();

  int size = (nodes) ? nodes->nodeNr : 0;
  if (size != 1)
    {
      server->log (MYSERVER_LOG_MSG_ERROR,
                          _("Error loading plugin `%s': invalid plugin.xml"),
                          name.c_str ());
      return NULL;
    }

  if (xmlHasProp (nodes->nodeTab[0], (const xmlChar*) "min-version"))
    {
      xmlChar *minVersion = xmlGetProp (nodes->nodeTab[0],
                                        (const xmlChar*) "min-version");

      string sMinVer ((char*) minVersion);
      pinfo->setMyServerMinVersion (PluginInfo::convertVersion (sMinVer));
    }
  else
    {
      server->log (MYSERVER_LOG_MSG_ERROR,
                          _("Error loading plugin `%s': invalid plugin.xml"),
                          name.c_str ());
      return NULL;
    }

  if (xmlHasProp (nodes->nodeTab[0], (const xmlChar*) "max-version"))
    {
      xmlChar* maxVersion = xmlGetProp (nodes->nodeTab[0],
                                        (const xmlChar*) "max-version");

      string sMaxVer ((char*)maxVersion);
      pinfo->setMyServerMaxVersion (PluginInfo::convertVersion (sMaxVer));
    }
  else
    {
      server->log (MYSERVER_LOG_MSG_ERROR,
                          _("Error loading plugin `%s': invalid plugin.xml"),
                          name.c_str ());
      return NULL;
    }

  auto_ptr<XmlXPathResult> xpathResPluginName = auto_ptr<XmlXPathResult>
    (xml.evaluateXpath ("/PLUGIN/NAME/text ()"));
  nodes = xpathResPluginName->getNodeSet ();
  size = (nodes) ? nodes->nodeNr : 0;

  if (size != 1)
    {
      server->log (MYSERVER_LOG_MSG_ERROR,
                          _("Error loading plugin `%s': invalid plugin.xml"),
                          name.c_str ());
      return NULL;
    }

  const char* cname = (const char*) nodes->nodeTab[0]->content;
  if (strcmp (name.c_str (), cname))
    return NULL;

  auto_ptr<XmlXPathResult> xpathResPluginVersion = auto_ptr<XmlXPathResult>
    (xml.evaluateXpath ("/PLUGIN/VERSION/text ()"));
  nodes = xpathResPluginVersion->getNodeSet ();
  size = (nodes) ? nodes->nodeNr : 0;

  if (size != 1)
    {
      server->log (MYSERVER_LOG_MSG_ERROR,
                          _("Error loading plugin `%s': invalid plugin.xml"),
                          name.c_str ());
      return NULL;
    }

  string verStr ((char*) nodes->nodeTab[0]->content);
  int version = PluginInfo::convertVersion (verStr);

  if (version != -1)
    pinfo->setVersion (version);
  else
    {
      server->log (MYSERVER_LOG_MSG_ERROR,
                          _("Error loading plugin `%s': invalid plugin.xml"),
                          name.c_str ());
      return NULL;
    }

  auto_ptr<XmlXPathResult> xpathResDeps = auto_ptr<XmlXPathResult>
    (xml.evaluateXpath ("/PLUGIN/DEPENDS"));
  nodes = xpathResDeps->getNodeSet ();
  size = (nodes) ? nodes->nodeNr : 0;

  for (int i = 0; i < size; i++)
    {
      const char* depends = (const char*) nodes->nodeTab[i]->children->content;

      string nameDep (depends);

      if (!xmlHasProp (nodes->nodeTab[i], (const xmlChar*) "min-version") ||
          !xmlHasProp (nodes->nodeTab[i], (const xmlChar*) "max-version"))
        {
          server->log (MYSERVER_LOG_MSG_ERROR,
                              _("Error loading plugin `%s': invalid plugin.xml"),
                              name.c_str ());
          return NULL;
        }

      string minVerStr = ((char*) xmlGetProp (nodes->nodeTab[i],
                                              (const xmlChar*) "min-version"));
      string maxVerStr = ((char*) xmlGetProp (nodes->nodeTab[i],
                                              (const xmlChar*) "max-version"));

      int minVersion = PluginInfo::convertVersion (minVerStr);
      int maxVersion = PluginInfo::convertVersion (maxVerStr);

      if (minVersion == -1 || maxVersion == -1)
        {
          server->log (MYSERVER_LOG_MSG_ERROR,
                              _("Error loading plugin `%s': invalid plugin.xml"),
                              name.c_str ());
          return NULL;
        }

      pinfo->addDependence (nameDep, minVersion, maxVersion);
    }

  pinfoAutoPtr.release ();
  return pinfo;
}