/****************************************************************************
 * KONOHA COPYRIGHT, LICENSE NOTICE, AND DISCRIMER  
 * 
 * Copyright (c) 2005-2008, Kimio Kuramitsu <kimio at ynu.ac.jp>
 *           (c) 2008-      Konoha Software Foundation  
 * All rights reserved.
 * 
 * You may choose one of the following two licenses when you use konoha. 
 * See www.konohaware.org/license.html for further information.
 * 
 * (1) GNU General Public License 2.0      (with    KONOHA_UNDER_GPL2)
 * (2) Konoha Software Foundation License 1.0
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 ****************************************************************************/

#include"commons.h"

/* ------------------------------------------------------------------------ */
/* [dlopen] */

/* ------------------------------------------------------------------------ */

#ifdef KONOHA_OS__MACOSX
	#define KNH_LOADER_DLL_SUPPORTED       1
	#define KNH_LOADER_DLL_PREFIX          "lib"
	#define KNH_LOADER_DLL_EXT             ".dylib"
#endif

/* ------------------------------------------------------------------------ */

#ifdef KONOHA_OS__LINUX
	#define KNH_LOADER_DLL_PREFIX          "lib"
	#define KNH_LOADER_DLL_EXT             ".so"
	#define KNH_LOADER_DLL_WITH_VERSION    1
#endif

/* ------------------------------------------------------------------------ */

#ifdef KONOHA_OS__CYGWIN
	#define KNH_LOADER_DLL_PREFIX          "/usr/lib/lib"
	#define KNH_LOADER_DLL_EXT             ".dll"
	#define KNH_LOADER_DLL_WITH_VERSION    1
#endif

/* ------------------------------------------------------------------------ */

#ifdef KONOHA_OS__WIN32
//	#define KNH_LOADER_DLL_SUPPORTED       1
	#define KNH_LOADER_DLL_EXT             "dll"
#endif


/* ************************************************************************ */

#ifdef __cplusplus 
extern "C" {
#endif

/* ======================================================================== */
/* [global] */

#define _knh_rootDir                DP(knh_rootSystem)->rootDir
#define _knh_pkgmgrDictSet          DP(knh_rootSystem)->pkgmgrDictSet
#define _knh_dylibDictSet           DP(knh_rootSystem)->dylibDictSet
#define _knh_funcDictSet            DP(knh_rootSystem)->funcDictSet

/* ======================================================================== */
/* [SLOCK] */

#define KNH_SLOCK(lock)                
#define KNH_SUNLOCK(lock)
#define LOCK_FUNC                   1
#define LOCK_PKGMGR                 1
#define LOCK_DYLIB                  1

/* ======================================================================== */
/* [rootDir] */

/* ======================================================================== */
/* [rootDir] */


/* ------------------------------------------------------------------------ */

#ifndef KONOHA_OS_PATH
#define KONOHA_OS_PATH    "/"
#endif

String *knh_rootdir()
{
	char *p = knh_getenv("KONOHA_HOME");
	if(p != NULL) {
		return new_String0(NULL, B(p), NULL);
	}
	else {
#ifdef KNH_ROOTDIR_DEPS
		return knh_rootdir_deps();
#else
		return new_String__T(NULL, KONOHA_OS_PATH "konoha");
#endif
	}
}

///* ------------------------------------------------------------------------ */
//
//char* knh_system_path(char *buf, size_t bufsiz, char *sub, char *file)
//{
//	if(file == NULL || file[0] == 0) {
//		knh_snprintf(buf, bufsiz, "%s/%s", knh_system_rootDir(), sub);
//	}
//	else{
//		knh_snprintf(buf, bufsiz, "%s/%s/%s", knh_system_rootDir(), sub, file);
//	}
//#ifdef KONOHA_OS__WIN32
//	size_t i;
//	for(i = 0; i < bufsiz; i++) {
//		if(buf[i] == 0) break;
//		if(buf[i] == '/') {
//			buf[i] = '¥¥';
//		}
//	}
//#endif
//	return buf;
//}

/* ======================================================================== */
/* [pkgmgr] */

#ifndef KONOHA_OS_DLLEXT
#define KONOHA_OS_DLLEXT   ""
#endif

/* ------------------------------------------------------------------------ */

//typedef struct {
//	knh_struct_t (*add_struct)(char *name, size_t size, 
//			f_tStruct_init f0, f_tStruct_copy f1, f_tStruct_traverse f3, 
//			f_hashCode f4, f_compareTo f5);
//	knh_class_t  (*add_class)(char *name, knh_struct_t sid);
//	void (*add_method)(char *decl, f_method)
//} knhloader_t;
//
//typedef int (*f_package_load)(knh_loader_t);

/* ------------------------------------------------------------------------ */

int knh_System_loadPackage(Ctx *ctx, knh_bytes_t pkgname)
{
//	knh_uint_t serialid;
//	KNH_SLOCK(LOCK_PKGMGR);
//	serialid = knh_DictSet_get__b(knh_pkgmgrDictSet, funcname);
//	KNH_SUNLOCK(LOCK_PKGMGR);
//	if(serialid == 1) {
//		DBG2_P("Naitive package has been loaded: %s", funcname.buf);
//		return 1;
//	}
//	else {
//		char bufp[FILENAME_BUFSIZ];
//		knh_snprintf(bufp, sizeof(bufp), "%s/package/%s/libknh%s%s", 
//				knh_String_tochar(knh_rootDir), (char*)pkgname.buf, (char*)pkgname.buf, KONOHA_OS_DLLEXT);
//		DBG2_P("Loading %s", bufp);
//		{
//			void *dlhdr;
//			KNH_SLOCK(LOCK_DYLIB);
//			dlhdr = (void*)knh_DictSet_get__b(knh_dylibDictSet, B(bufn));
//			if(dlhdr == NULL) {
//				//DEBUG("Opening dll %s ..", bufp);
//				dlhdr =knh_dlopen(bufp, KNH_RTLD_LAZY);
//				if (dlhdr == NULL) {
//					KNH_SUNLOCK(LOCK_DYLIB);
//					KNH_NOTICE(ctx, "cannot open '%s': %s", bufn, knh_dlerror());
//					goto L_LOAD_KONOHA;
//				}
//				else {
//					knh_DictSet_set(ctx, knh_dylibDictSet, new_String(ctx, B(bufn), NULL), (knh_uint_t)dlhdr);
//					KNH_SUNLOCK(LOCK_DYLIB);
//				}
//			}
//			KNH_ASSERT(dlhdr != NULL);
//			knh_snprintf(bufp, sizeof(bufp), "%s_load", (char*)pkgname.buf);
//			{
//				f_package_load package_load = (f_package_load)dlsym(dlhdr, bufp);
//				if(package_load == NULL) {
//					KNH_NOTICE("canot load: %s", bufp);
//					goto L_LOAD_KONOHA;
//				}
//				return package_load(NULL);
//			}
//		}
//	}
//}
//		void *func = dlsym(dlhdr, "knh");
//		if(func == NULL) {
//			KNH_NOTICE("not found %s: %s", funcname, dlerror());
//			return deffunc;
//		}
//		return func;
//
//	}
//	TODO();
	return 0;
}

	
/* ======================================================================== */
/* [func] */

void KNH_TFUNC(Ctx *ctx, String *fname, void *func)
{
	if(func != NULL) {
		KNH_SLOCK(LOCK_FUNC);
		knh_DictSet_set(ctx, knh_funcDictSet, fname, (knh_uint_t)func);
		KNH_SUNLOCK(LOCK_FUNC);
	}
}

/* ------------------------------------------------------------------------ */

void *knh_System_getFunc(Ctx *ctx, knh_bytes_t funcname, void *deffunc)
{
	void *func;
	KNH_SLOCK(LOCK_FUNC);
	func = (void*)knh_DictSet_get__b(knh_funcDictSet, funcname);
	KNH_SUNLOCK(LOCK_FUNC);
	if(func == NULL) {
		return deffunc;
	}
	DBG2_P("using built-in function: %s", funcname.buf);
	return func;
}

/* ======================================================================== */
/* [LibDictSet] */

void *
knh_system_loadFunc(Ctx *ctx, char *dirname, char *libname, char *funcname, void *deffunc)
{
#if defined(KNH_USING_DL)
#define IMPL_knh_loader_loaddll
	char bufn[FILENAME_BUFSIZ];
	knh_snprintf(bufn, sizeof(bufn), "%s%s%s", KNH_LOADER_DLL_PREFIX, libname, KNH_LOADER_DLL_EXT);

	char bufp[FILENAME_BUFSIZ];
	if(dirname == NULL) {
		knh_system_path(bufp, sizeof(bufp), "lib", bufn);
	}
	else {
		knh_snprintf(bufp, sizeof(bufp), "%s/%s", dirname, bufn);
	}
	
#endif

#if !defined(IMPL_knh_loader_loaddll)
	KNH_NOTICE(ctx, "unsupported");
	return deffunc;
#endif
}

/* ------------------------------------------------------------------------ */

void *knh_system_loadPackageFunc(Ctx *ctx, knh_bytes_t pname, knh_bytes_t fname)
{
//#ifdef KONOHA_MONOLITHIC
//	return knh_System_getFunc(ctx, fname, NULL);
//#else
//	void *func;
//	char bufp[FILENAME_BUFSIZ];
//	knh_index_t idx;
//
//	func = knh_System_getFunc(ctx, fname, NULL);
//	if(func != NULL) {
//		return func;
//	}
//	
//	knh_system_path(bufp, sizeof(bufp), "package", (char*)pname.buf);
//	idx = knh_bytes_rindex(pname, '.');
//	if(idx != -1) {
//		pname = knh_bytes_last(pname, idx + 1);
//	}
//	return knh_system_loadFunc(ctx, bufp, (char*)pname.buf, (char*)fname.buf, NULL);
//#endif/*KONOHA_MONOLITHIC*/
	return NULL;
}

/* ------------------------------------------------------------------------ */

void *knh_system_loadDriverFunc(Ctx *ctx, knh_bytes_t drvname, char *funcbase, void *deffunc)
{
//#ifdef KONOHA_MONOLITHIC
//	char buff[FILENAME_BUFSIZ];
//	knh_snprintf(buff, sizeof(buff), "%s__%s", funcbase, (char*)drvname.buf);
//	return knh_System_getFunc(ctx, B(buff), deffunc);
//#else
//	char buff[FILENAME_BUFSIZ];
//	char bufp[FILENAME_BUFSIZ];
//	void *func;
//	knh_snprintf(buff, sizeof(buff), "%s__%s", funcbase, (char*)drvname.buf);
//	func = knh_System_getFunc(ctx, B(buff), NULL);
//	if(func != NULL) {
//		return func;
//	}
//	knh_system_path(bufp, sizeof(bufp), "driver", (char*)drvname.buf);
//	return knh_system_loadFunc(ctx, bufp, (char*)drvname.buf, buff, deffunc);
//#endif/*KONOHA_MONOLITHIC*/
	return NULL;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

#ifdef __cplusplus
}
#endif
