/*------------------------------------------------------------------------------
 src/lib/dj/plugin.cxx
 
 Copyright (c) 2004-2006 Darby Johnston.
 All rights reserved.
 Use is subject to license terms.
------------------------------------------------------------------------------*/

//#define DJ_DBG
#include "djPlugin.h"
#include <djDir.h>
#include <dlfcn.h>

namespace dj {

Plugin::~Plugin() {}

bool Plugin::attrSet(const PluginAttr & in)
{
  const StrList keyList = in.keyList();
  for (ConstStrListIt it = keyList; it.isValid(); ++it)
    if (! attr(it(), in[it()])) return false;
  return true;
}

const Map<Str, StrList> Plugin::attrGet() const
{
  Map<Str, StrList> out;
  const StrList keyList = attrNameList();
  for (ConstStrListIt it = keyList; it.isValid(); ++it)
    out[it()] = attr(it());
  return out;
}

PluginFactory::PluginFactory()
{
  DJ_DBG_FNC("dj::PluginFactory::PluginFactory");
}

PluginFactory::~PluginFactory()
{
  DJ_DBG_FNC("dj::PluginFactory::~PluginFactory");
  
  del();
}

void PluginFactory::set(const StrList & searchPathList)
{
  DJ_DBG_FNC("dj::PluginFactory::set");
  DJ_DBG_PRN("search paths = " << searchPathList);
  
  del();
  
  // XXX Find unique plugins by filename.
  //
  Map<Str, Str> pluginMap;
  for (ConstStrListIt it = searchPathList; it.isValid(); ++it) {

    StrList filterList;

    // XXX OS specific.
    //
#   if defined(DJ_OSX)
    filterList += Str("lib") + pluginPrefix() + Str("*.dylib");
#   else
    filterList += Str("lib") + pluginPrefix() + Str("*.so");
#   endif

    Dir dir(it());
    const List<FileInfo> itemList =
      filter(dir.itemList(), FILE_FILTER_FILES, filterList);
    ConstListIt<FileInfo> itemIt = itemList;
    for (; itemIt.isValid(); ++itemIt)
      pluginMap.set(itemIt().get(0, false), itemIt().path());
  }
  
  // Load plugins.
  //
  const StrList pluginList = pluginMap.keyList();
  for (ConstStrListIt it = pluginList; it.isValid(); ++it) {
    DJ_DBG_PRN("plugin = " << it());

    // Open.
    //
    void * handle = dlopen(Str(pluginMap[it()] + it()).toAscii(), RTLD_LAZY);
    if (! handle) {
      DJ_DBG_PRN("dlerror = " << dlerror());
      continue;
    }
    
    // Initialize.
    //
    if (init(handle)) {
    
      DJ_DBG_PRN("add");
      
      _handleList += handle;
      
    } else {

      // XXX IRIX dlopen/pthread bug.
      //
      //dlclose(handle);
    }
  }
}

void PluginFactory::del()
{
  DJ_DBG_FNC("dj::PluginFactory::del");

  // XXX IRIX dlopen/pthread bug.
  //
  //for (ListIt<void *> it = _handleList; it.isValid(); ++it) dlclose(it());

  _handleList.del();
}

}
