#include "PluginThread.h"
/**
 * PluginThread
 */

#include "MonitorLogging.h"

#ifdef WIN32
	#define usleep Sleep
#endif

#define MAX_QUEUESIZE (100)

PluginThread::PluginThread() : ThreadBase(-1)
{
	FILE_LOG(logDEBUG) << "Erstellt PT:"  ;
	m_iLockNum=-1 ;
	m_plugin=NULL ;
	m_bStop=false ;
	dll=NULL ;
}

bool PluginThread::initPlugin(int LOCKNUM, std::string dllfile,XMLNode *pConfig)
{
	m_iLockNum=LOCKNUM ;

	char dllname[255] ;
	memset(dllname,0,255) ;
	strncpy(dllname,dllfile.c_str(),255) ;
	FILE_LOG(logDEBUG) << "DLL Name:" << dllname  ;

	dll= new DLLFactory<MonitorPlugInFactory>(dllname);

	FILE_LOG(logDEBUG) << "done" ;
	//
	// If it worked we should have dll.factory pointing
	// to a subclass of PlugInFactory
	//
	if (dll)
	{
		if( dll->factory )
		{
			m_plugin=dll->factory->CreatePlugIn() ;
			if (m_plugin==NULL)
			{
				ThrowMonitorException("Error creating Plugin !") ;
			} else
			{
				// Plugin ist erstellt, nun konfigurieren
				m_plugin->initProcessing(NULL,*pConfig) ;
			}
		} else {
			ThrowMonitorException("Error accessing factory from " + dllfile) ;
		}
	} else {
		ThrowMonitorException("Error loading dll:" + dllfile) ;
	}
	return true ;
}


PluginThread::PluginThread(int LOCKNUM, std::string dllfile,XMLNode *pConfig)
:ThreadBase(LOCKNUM)
{
	initPlugin(LOCKNUM,dllfile,pConfig) ;
}

PluginThread::~PluginThread()
{

}


void *PluginThread::Thread()
{
	ModuleResultBase* pRes ;


	FILE_LOG(logINFO) << "PluginThread starting"  ;
	this->ThreadStarted() ; // Erstmal Bescheid geben, dass wir laufen
	createLock() ;

	while (!m_bStop)
	{
		m_signal.WaitForSignal() ;
		// Daten an Plugin uebergeben
		memLock(m_Lock) ;
		while (m_queue.size()>0)
		{
			FILE_LOG(logDEBUG) << "plugin processing - size=" << m_queue.size()  ;
			pRes=m_queue.back() ;
			m_queue.pop_back() ;
			memUnlock(m_Lock) ;

			/* to avoid a lock caused by a crashed plugin we release our lock*/
			if (m_plugin)
			{
				m_plugin->processResult(pRes) ;
			}
			delete pRes ;
			memLock(m_Lock) ;
		}
		memUnlock(m_Lock) ;

	}
	FILE_LOG(logINFO) << "PluginThread was stopped"  ;

	m_plugin->quitProcessing();
	return NULL;
}

void PluginThread::addResult(ModuleResultBase* pRes)
{
	ModuleResultBase* localResult=new ModuleResultBase;
	pRes->copyTo(*localResult) ;

	memLock(m_Lock) ;
	if (m_queue.size()<MAX_QUEUESIZE)
	{
		m_queue.insert(m_queue.begin(),localResult) ;
	} else {
		FILE_LOG(logERROR) << "max plugin queue size exceeded. moduleresult not queued"  ;
	}

	memUnlock(m_Lock) ;

	m_signal.SetSignal() ;
}

// ----------------------------------------
// MonitorPluginsManager

MonitorPluginsManager GlobalMonitorPluginsManager ;
MonitorPluginsManager& GetPluginsManager() { return (GlobalMonitorPluginsManager); }


MonitorPluginsManager::MonitorPluginsManager()
{
	FILE_LOG(logINFO) << "PluginManager erstellt"  ;

	if ( memLockCreate( 12348, & m_MemLock) < 0) {
   		ThrowMonitorException("PluginManager: memLockCreate failed") ;
    }
    m_bStop=false ;
}
MonitorPluginsManager::~MonitorPluginsManager()
{
}

bool MonitorPluginsManager::addModule(PluginThread* pThread)
{
	m_Modules.push_back(pThread) ;
	return true ;
}

bool MonitorPluginsManager::removeModule(PluginThread* pThread)
{
	return false ;
}


bool MonitorPluginsManager::dispatchResult(ModuleResultBase *pRes)
{
	tMonitorPluginThreadVector::iterator i ;

	for (i= m_Modules.begin(); i< m_Modules.end(); i++)
	{
			(*i)->addResult(pRes) ;
	}
	return true ;
}

bool MonitorPluginsManager::loadPlugin(std::string dllfile, XMLNode *pConfig)
{
 	PluginThread* pt=new PluginThread() ;
 	if (pt->initPlugin(4000,dllfile,pConfig))
 	{
		FILE_LOG(logDEBUG) << "startet plugin " << dllfile ;
		pt->Start() ;
		addModule(pt) ;

		return true ;
	} else	{
		FILE_LOG(logERROR) << "DLL Factory konnte nicht initialisiert werden !" ;
		return false ;
	}
}

bool MonitorPluginsManager::loadPluginsFromConfigNode(XMLNode *pConfig)
{
	// Plugins durchgehen

	std::string pluginName ;
	std::string pluginFile ;
	XMLNode parameterNode ;
	XMLNode *pParameters ;
	XMLNode pluginNode; // = pConfig->getChildNode("plugin",sndCard) ;

	FILE_LOG(logINFO) << "reading plugin configuration" ;
	int nPlugins=pConfig->nChildNode("plugin");
	for (int plugin=0;plugin<nPlugins;++plugin)
	{
		// Plugin auslesen
		if (!((pluginNode=pConfig->getChildNode("plugin",plugin))).isEmpty())
		{
			pluginName=pluginNode.getAttribute("name");
			pluginFile=getNodeText(pluginNode,"file","") ;
			parameterNode=pluginNode.getChildNode("parameters");

			FILE_LOG(logDEBUG) << "Plugin found: "  ;
			FILE_LOG(logDEBUG) << "Name:" << pluginName ;
			FILE_LOG(logDEBUG) << "File:" << pluginFile ;
			if (parameterNode.isEmpty()==false)
			{
				FILE_LOG(logDEBUG) << "found parameters" ;
				pParameters=&parameterNode ;
			} else
			{
				FILE_LOG(logDEBUG) << "no parameters found"  ;
				pParameters=NULL;
			}

			if (pluginFile.size()>0)
			{
				loadPlugin(pluginFile,pParameters) ;
			}
		}
	}
	return true ;
}






