//-*-c++-*
/**
 Author: David Auber
 Email : auber@labri.fr
 Last modification : 26/09/2001
 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; either version 2 of the License, or     
 (at your option) any later version.
*/
//====================================================================================
#include <iostream>
#include <dlfcn.h>
#include <dirent.h>

//implemented in TlpTools.cpp
int __tulip_selectSO(struct dirent *ent);

template<class ObjectFactory, class ObjectType, class Parameter>
bool TemplateFactory<ObjectFactory, ObjectType, Parameter>::exists(const std::string &pluginName) {
  return (objMap.find(pluginName) != objMap.end());
}

template<class ObjectFactory, class ObjectType, class Parameter>
void TemplateFactory<ObjectFactory,ObjectType,Parameter>::load(std::string pluginPath,std::string type,PluginLoader *loader) {
  bool result=true;std::string msg;
  struct dirent **namelist;
  if (loader!=0) loader->start(pluginPath.c_str(),type);
  int n = scandir(pluginPath.c_str(), &namelist, __tulip_selectSO, alphasort);
  if (loader!=0) loader->numberOfFile(n);
  if (n < 0) {
    msg=std::string("Scandir error");//perror("scandir");
    result=false;
  }
  else {
    while(n-->0) {
      char *error;
      std::string tmpStr;
      tmpStr= pluginPath +"/"+ std::string(namelist[n]->d_name);
      if (loader!=0) loader->loading(std::string(namelist[n]->d_name));
      handle = dlopen (tmpStr.c_str() , RTLD_NOW);
      if (!handle){ 
	if (loader!=0) loader->aborted(std::string(namelist[n]->d_name),std::string(dlerror()));
      }
      else {
	createObj =(func) dlsym(handle, "_creator");
	if ((error=(char*)dlerror())!=0) {
	  dlclose(handle);
	  if (loader!=0) loader->aborted(std::string(namelist[n]->d_name),std::string(error));
	}
	else {
	  ObjectFactory *tmpObjectFactory=(ObjectFactory *)createObj();
	  objMap[tmpObjectFactory->getName()]=tmpObjectFactory;
	  if (loader!=0) loader->loaded(
					tmpObjectFactory->getName(),
					tmpObjectFactory->getAuthor(),
					tmpObjectFactory->getDate(),
					tmpObjectFactory->getInfo(),
					tmpObjectFactory->getRelease(),
					tmpObjectFactory->getVersion()
					);
	  Parameter p = Parameter();
	  WithParameter *withParam=tmpObjectFactory->createObject(p);
	  objParam[tmpObjectFactory->getName()]=withParam->getParameters();
	  //		delete withParam;
	}
      }
    }
  }
  if (loader!=0) loader->finished(result,msg);
}


template<class ObjectFactory, class ObjectType, class Parameter>
bool TemplateFactory<ObjectFactory,ObjectType,Parameter>::load(std::string file) {
  char *error;
  handle = dlopen (file.c_str() , RTLD_NOW);
  if (!handle) { 
#ifndef DNDEBUG
    std::cerr << dlerror() << std::endl;
#endif
  }
  else {
    createObj =(func) dlsym(handle, "_creator");
    if ((error=dlerror())!=0) {
      dlclose(handle);
#ifndef DNDEBUG
      std::cerr << error << std::endl;
#endif
      return false;
    }
    else {
      ObjectFactory *tmpObjectFactory=(ObjectFactory *)createObj();
      objMap[tmpObjectFactory->getName()]=tmpObjectFactory;
      Parameter p = Parameter();
      WithParameter *withParam=tmpObjectFactory->createObject(p);
      objParam[tmpObjectFactory->getName()]=withParam->getParameters();
    }
  }
  return true;
}

template<class ObjectFactory, class ObjectType, class Parameter>
ObjectType * TemplateFactory<ObjectFactory,ObjectType,Parameter>::getObject(std::string name,Parameter p)
{
  typename ObjectCreator::iterator it;
#ifndef NDEBUG 
  std::cerr << "TemplateFactory::GetObject :" << name << std::endl;  
#endif
  it=objMap.find(name);
  if (it!=objMap.end()) return (*it).second->createObject(p);
  return 0;
}
template<class ObjectFactory, class ObjectType, class Parameter>
StructDef TemplateFactory<ObjectFactory,ObjectType,Parameter>::getParam(std::string name){
  assert(objMap.find(name)!=objMap.end());
  return objParam[name];
}
