#include <eter/py_tinker.h>

#include <string>

namespace py_tinker {

PyObject* PyEmbed_BuildMainModuleDict()
{
    PyObject* poModule=PyImport_AddModule((char *) "__main__");
    if (!poModule)
        return NULL;
    
    PyObject* poModuleDict = PyModule_GetDict(poModule);
    
    PyObject* poBuiltInModule = PyImport_ImportModule("__builtin__");
    // 2.2 대는 true/false 가 지원되지 않으므로 이런식으로 해서 사용
    PyModule_AddIntConstant(poBuiltInModule, "true", 1); 
    PyModule_AddIntConstant(poBuiltInModule, "false", 0); 
    PyDict_SetItemString(poModuleDict, "__builtins__", poBuiltInModule);
    Py_DECREF(poBuiltInModule);
    
    return poModuleDict;
}

bool PyEmbed_RunFile(const char* c_szFileName, PyObject* poDict)
{
    const char* szBegin=\
		"from weakref import proxy\n"\
		"class func_proxy:\n"\
		"	class __noarg_call__:\n"\
        "		def __init__(self, cls, obj, func):\n"\
		"			self.cls=cls\n"\
		"			self.obj=proxy(obj)\n"\
		"			self.func=proxy(func)\n"\
		"		def __call__(self, *arg):\n"\
		"			return self.func(self.obj)\n"\
		"	class __arg_call__:\n"\
		"		def __init__(self, cls, obj, func):\n"\
		"			self.cls=cls\n"\
		"			self.obj=proxy(obj)\n"\
		"			self.func=proxy(func)\n"\
		"		def __call__(self, *arg):\n"\
		"			return self.func(self.obj, *arg)\n"\
		"	def __init__(self, mfunc):\n"\
		"		if mfunc.im_func.func_code.co_argcount>1:\n"\
		"			self.call=func_proxy.__arg_call__(mfunc.im_class, mfunc.im_self, mfunc.im_func)\n"\
		"		else:\n"\
		"			self.call=func_proxy.__noarg_call__(mfunc.im_class, mfunc.im_self, mfunc.im_func)\n"\
		"	def __call__(self, *arg):\n"\
		"		return self.call(*arg)\n"\
        "def exc_traceback():\n"\
        "   import os\n"\
        "   import sys\n"\
        "   import traceback\n"\
        "\n"\
        "   (type, msg, tb)=sys.exc_info()\n"\
        "\n"\
        "   output='TraceBacks:'\n"\
        "   output+=os.linesep\n"\
        "\n"\
        "   for (fileName, lineIndex, funcName, lineData) in traceback.extract_tb(tb):\n"\
        "       output+=' '*2+'%s (line:%d) - %s' % (fileName, lineIndex, funcName)\n"\
        "       output+=os.linesep\n"\
        "\n"\
        "       if lineData:\n"\
        "           output+=' '*4+lineData\n"\
        "           output+=os.linesep\n"\
        "\n"\
        "   output+=os.linesep\n"\
        "\n"\
        "   output+='%s:' % (type)\n"\
        "   output+=os.linesep\n"\
        "   output+='%s' % (msg)\n"\
        "   output+=os.linesep\n"\
        "\n"\
        "   sys.stderr.write(output)\n"\
        "   return output\n"\
        "\n"\
        "__builtins__.exc_traceback=exc_traceback\n"\
        "\n"\
        "try:\n"\
        "   execfile('";
    
    const char* szEnd=\
        "')\n"\
        "except Exception, e:\n"\
        "   exc_traceback()\n"\
        "";
    
    int nBeginLen=strlen(szBegin);
    int nEndLen=strlen(szEnd);
    
    std::string stCodeBuf;
    stCodeBuf.append(szBegin, nBeginLen);
    stCodeBuf.append(c_szFileName);
    stCodeBuf.append(szEnd, nEndLen);
    
    PyObject* poResult=PyRun_String((char*)stCodeBuf.c_str(), Py_file_input, poDict, poDict);
    if (!poResult)
        return false;
    
    Py_DECREF(poResult);
    return true;
}

bool PyEmbed_RunMainFile(const char* c_szFileName)
{
	PyObject* poMainDict=PyEmbed_BuildMainModuleDict();

	{
		char szBuf[256];
		snprintf(szBuf, sizeof(szBuf)-1, "import sys; sys.argv = ['%s'];", c_szFileName);
		PyObject* poResult = PyRun_String(szBuf, Py_file_input, poMainDict, poMainDict);
		if (!poResult)
		{
			PyErr_Print();
			return false;
		}
		Py_DECREF(poResult);
	}

    return PyEmbed_RunFile(c_szFileName, poMainDict);
}


} // py_tinker