#include "factoryconfig.h"
//(c) Adrian Boeing 2004, see liscence.txt (BSD liscence)
/*
	Abstract:
		The "configuration" setting for the factory templates I choose to use.
	Author: 
		Adrian Boeing
	Revision History:
		Version 1.1	  28/06/07 Group DLL reimplementation
		Version 1.0.4 18/08/04 PAL modifications
	TODO:
		proper virtual inheritance of free objects
*/

typedef void *(*pt2CreateFunction) (void);
typedef void *(*pt2CreateGroupFunction) (int);
typedef UINT32 (*pt2PropertiesFunction) (void);
//typedef void (*pt2StatusTrackerFunction) (StatusTracker<StatusInfo> *pInstance);

#ifndef NDEBUG
#include <stdio.h>
#endif

#if defined (OS_WINDOWS)
#include <windows.h>
#pragma message("Remember to set to Multithreaded DLL (/MDd or /MD)")
static VECTOR<HINSTANCE> svDlls;
#elif defined (OS_LINUX)
#include <dirent.h>
#include <dlfcn.h>
static VECTOR<void *> svDlls;
#endif
//class myAbstractFOS : public myFactoryObject, public Serializable  {};
static VECTOR<myFactoryObject *> svDllObjects;

void myFactory::FreeObjects() {
	unsigned int i;
	for (i=0;i<svDllObjects.size();i++) {
		delete svDllObjects[i];
	}
#if defined (WIN32)
	for (i=0;i<svDlls.size();i++)
		FreeLibrary(svDlls[i]);
#endif
}

void myFactory::LoadObjects(char *szPath) {
#if defined (WIN32)
	char current_directory[MAX_PATH];
	if (szPath != NULL) {
	GetCurrentDirectory(MAX_PATH,current_directory);
	SetCurrentDirectory(szPath);
	}
	WIN32_FIND_DATA FindFileData;
	HANDLE hFind;
	hFind = FindFirstFile("*.dll", &FindFileData);
	if (hFind!=INVALID_HANDLE_VALUE) {
		do {
			char *filename = FindFileData.cFileName;
			HINSTANCE hInst=LoadLibrary(filename);
			if (hInst==NULL) {
//				LOG(SNOTFOUND,"Could not load DLL library %s",filename);
				continue;
			}
			svDlls.push_back(hInst);
/*			pt2StatusTrackerFunction sfp = (pt2StatusTrackerFunction) GetProcAddress((HMODULE)hInst,"SetStatusTrackerInstance");
			if (sfp==NULL) {
//				LOG(SWARNING,"%s does not contain a valid status tracking component\n",filename);
				//continue;
			} else {
				//connect the status trackers.
				sfp(StatusTracker<StatusInfo>::GetInstance());
				printf("st connected\n");
			}
			*/

			//group creation functions
			pt2CreateGroupFunction fpg = (pt2CreateGroupFunction) GetProcAddress((HMODULE)hInst,"Group_CreateComponent");
			if (fpg == NULL) {
//				LOG(SWARNING,"%s does not contain a valid factory group component",filename);
			} else {
				int *num = (int *)fpg(-1); //get the number of components in here.
#ifndef NDEBUG
				printf("%d components found in group\n",*num);
#endif
				for (int i=0;i<*num;i++) {
					void *vo=fpg(i); //void object pointer, construct a copy of the object for registration purposes
					myFactoryObject *fo= (myFactoryObject *) vo;
					fo->RegisterWithFactory(myFactory::sInfo());
					svDllObjects.push_back(fo);	
				}
			}

			//individual dll component creation functions
			pt2CreateFunction fp = (pt2CreateFunction) GetProcAddress((HMODULE)hInst,"CreateComponent");
			if (fp==NULL) {
//				LOG(SWARNING,"%s does not contain a valid factory component",filename);
			} else {

				void *vo=fp(); //void object pointer, construct a copy of the object for registration purposes
				myFactoryObject *fo= (myFactoryObject *) vo;
				fo->RegisterWithFactory(myFactory::sInfo());
				svDllObjects.push_back(fo);
#ifndef NDEBUG
				printf("constructor connected and registered\n");
#endif

				bool serializable;
				serializable=false;
				pt2PropertiesFunction pfp = (pt2PropertiesFunction) GetProcAddress((HMODULE)hInst,"GetProperties");
				if (pfp==NULL) {
					//serialization is not supported
				} else {
					if (pfp()&1) serializable = true;
				}
				if (serializable) {
#ifndef NDEBUG
					printf("this is serializable!\n");
#endif
/*					myAbstractFOS *s=(myAbstractFOS *)vo;
					SerialFactory::SerialRegister(s);*/
				}

			}

		} while (FindNextFile(hFind,&FindFileData));
	}
	FindClose(hFind);
	if (szPath != NULL) {
	SetCurrentDirectory(current_directory);
	}
#elif defined (OS_LINUX)
	char current_directory[4096];
	if (szPath != NULL) {
	//GetCurrentDirectory(MAX_PATH,current_directory);
	//SetCurrentDirectory(szPath);
	}
	DIR * dir = opendir (".");
	if (dir == NULL){
		LOG(SERROR,"Could not open directory\n");
		return;
	}
	struct dirent *d;
	while ((d = readdir (dir)) != NULL){
		printf ("\"%s\"\n", d->d_name);
		STRING filename = d->d_name;
		//"bla.txt"
		size_t index=filename.find_last_of('.');
		filename.erase(0,index);
		printf("%s\n",filename.c_str());

		if (filename == ".so") {
			printf("THIS IS A SO FILE\n");
			void *handle;
			handle = dlopen(d->d_name,RTLD_LAZY);
			if (!handle) {
				LOG(SNOTFOUND,"Could not load DLL library %s [%s]",d->d_name,dlerror());
				continue;
			}
			svDlls.push_back(handle);
			pt2StatusTrackerFunction sfp = (pt2StatusTrackerFunction)  dlsym(handle,"SetStatusTrackerInstance");
			if (sfp==NULL) {
				LOG(SWARNING,"%s does not contain a valid status tracking component\n",d->d_name);
				//continue;
			} else {
				//connect the status trackers.
				sfp(StatusTracker<StatusInfo>::GetInstance());
				printf("st connected\n");
			}

			pt2CreateFunction fp = (pt2CreateFunction) dlsym(handle,"CreateComponent");
			if (fp==NULL) {
				LOG(SWARNING,"%s does not contain a valid factory component",d->d_name);
			} else {

				void *vo=fp(); //void object pointer, construct a copy of the object for registration purposes
				myFactoryObject *fo= (myFactoryObject *) vo;
				fo->RegisterWithFactory(myFactory::sInfo());
				svDllObjects.push_back(fo);
				printf("constructor connected and registered\n");

				bool serializable;
				serializable=false;
				pt2PropertiesFunction pfp = (pt2PropertiesFunction) dlsym(handle,"GetProperties");
				if (pfp==NULL) {
					//serialization is not supported
				} else {
					if (pfp()&1) serializable = true;
				}
				if (serializable) {
					printf("this is serializable!\n");
					myAbstractFOS *s=(myAbstractFOS *)vo;
					SerialFactory::SerialRegister(s);
				}

			}


		}

	}
	// Now, close the directory.
	closedir (dir);

#else
	LOG(SERROR,"Loading dynamic library objects is not supported with this operating environment");
#endif
}


myFactoryObject *myFactory::Construct(STRING ClassName) {
	myFactoryObject *ret;
	ret=newObject(ClassName);
	if (ret==NULL) return NULL;
	Add(ret);
	return ret;
}

#ifdef INTERNAL_DEBUG
void myFactory::DisplayAllObjects() {
	//typename 
	VECTOR<myFactoryInfo>::iterator itv;
	itv=myFactory::sInfo().begin();
	printf("sInfo (%d : %d entries) contents:\n",&myFactory::sInfo(),myFactory::sInfo().size());
	while (itv!=myFactory::sInfo().end()) {
		printf("sInfo entry:%s\n",itv->mUniqueName.c_str());
			/*
			STRING mClassName;
	STRING mGroupName;
	STRING mUniqueName;
	unsigned long mVersion;
			*/
		itv++;
	}
	printf("Current registry contents:\n");
	DisplayContents();
}
#endif