#Region - TimeStamp
; 2013-10-21 12:06:31   v 0.1
#EndRegion - TimeStamp

;----------------------------------------------------------------------------------------------------
;
;  based on: http://www.autoitscript.com/forum/topic/120498-embedding-lua-scripts-in-autoit/#entry837248
;
;  Some changes made by BugFix
;
;  NEW:
;  • All needed Lua files as binary source "LuaSource.au3"
;  • Auto detection parameter type
;  • _Lua_AddPathRequire()
;  • _Lua_DoString()
;  • _Lua_LoadString()
;  • _Lua_PushBoolean()
;  • _Lua_PushNil()
;  • _Lua_RunFuncFile()
;  • _Lua_RunFuncLocal()
;  • _Lua_ToString()
;
;  You must now not manage push and pop, my functions will do this for you.
;  You only need to call:
;  	• _Lua_StartUp()
;  and:
;	• _Lua_DoString()       Run lua-code string, (no return possible)           or _
;  	• _Lua_RunFuncLocal()   Creates lua-function at runtime, (return possible)  or _
;	• _Lua_RunFuncFile()    Run lua-function from existing file, (return possible)
;   • _AddPathRequire()     Allowed to add libraries (dll or lua) for using with require
;                           @ScriptDir is added by default at startup
;
;----------------------------------------------------------------------------------------------------

#include-once
#include <LuaSource.au3>

Opt("MustDeclareVars", 1)
OnAutoItExitRegister("__Lua_ShutDown")

_LuaFiles_Create()

#region Main Globals

Global $__g_sluadll      = "lua51.dll"
Global $__g_hluadll      = 0
Global $__g_pluanewstate = 0

Global Const $LUA_VERSION       = "Lua 5.1"
Global Const $LUA_RELEASE       = "Lua 5.1.1"
Global Const $LUA_VERSION_NUM   = 501
Global Const $LUA_COPYRIGHT     = "Copyright (C) 1994-2006 Lua.org, PUC-Rio"
Global Const $LUA_AUTHORS       = "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
Global Const $LUA_SIGNATURE     = "Lua"
Global Const $LUA_MULTRET       = (-1)
Global Const $LUA_REGISTRYINDEX = (-10000)
Global Const $LUA_ENVIRONINDEX  = (-10001)
Global Const $LUA_GLOBALSINDEX  = (-10002)
Global Const $LUA_YIELD_        = 1
Global Const $LUA_ERRRUN        = 2
Global Const $LUA_ERRSYNTAX     = 3
Global Const $LUA_ERRMEM        = 4
Global Const $LUA_ERRERR        = 5

#endregion Main Globals

#region Functions

;****************************************************************************************************
Func _Lua_StartUp()
	If Not _Lua_Initiate() Then Exit 1
	_Lua_Open()
	_Lua_OpenLibs()
	_Lua_AddPathRequire(@ScriptDir)
EndFunc  ;==>_Lua_StartUp

Func __Lua_ShutDown() ; == OnAutoItExit
	_Lua_Close()
	_Lua_DeInitiate()
	_DelTempLuaFiles()
EndFunc  ;==>__Lua_ShutDown
;****************************************************************************************************

;====================================================================================================
; Function Name....: _AddPathRequire
; Description......: Adds given path(es) to package.cpath and package.path for use *.dll and *.lua with require
; Note.............: Libraries can be stored in this path(es) as: "PATH\name.dll", "PATH\name\name.dll", "PATH\name.lua", "PATH\name\name.lua"
;                    @ScriptDir is added as default by _Lua_StartUp()
; Parameter(s).....: $s_Path     One or more path to add. If more than one path, separate it with ";".
;====================================================================================================
Func _Lua_AddPathRequire($s_Path)
	Local $sPathDll = '', $sPathLua = '', $aPath = StringSplit($s_Path, ';')
	For $i = 1 To $aPath[0]
		If $aPath[$i] = @ScriptDir Then ContinueLoop
		$aPath[$i] = StringReplace($aPath[$i], '\', '/')
		$sPathDll &= $aPath[$i] & '/?.dll;' & $aPath[$i] & '/?/?.dll;'
		$sPathLua &= $aPath[$i] & '/?.lua;' & $aPath[$i] & '/?/?.lua;'
	Next
	_Lua_DoString('package.cpath = ' & $sPathDll & '..package.cpath')
	_Lua_DoString('package.path = ' & $sPathLua & '..package.path')
EndFunc

Func _Lua_Call($i_args, $i_results, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "lua_call", "ptr", $p_state, "int", Int($i_args), "int", Int($i_results))
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_Call

Func _Lua_Close($p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "luaL_close", "ptr", $p_state)
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_Close

Func _Lua_DeInitiate()
	If $__g_hluadll = 0 Then Return 1
	DllClose($__g_hluadll)
	$__g_hluadll = 0
	Return 1
EndFunc  ;==>_Lua_DeInitiate

Func _Lua_DoFile($s_filename, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	Local $i_load = _Lua_LoadFile($s_filename)
	Local $i_pcall = _Lua_PCall(0, $LUA_MULTRET, 0)
	If BitOR($i_load, $i_pcall) = 0 Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_DoFile

Func _Lua_DoString($s_string, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	Local $i_load = _Lua_LoadString($s_string)
	Local $i_pcall = _Lua_PCall(0, $LUA_MULTRET, 0)
	If BitOR($i_load, $i_pcall) = 0 Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_DoString

Func _Lua_GetField($s_char, $i_index = $LUA_GLOBALSINDEX, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "lua_getfield", "ptr", $p_state, "int", Int($i_index), "str", $s_char)
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_GetField

Func _Lua_GetGlobal($s_name, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	_Lua_GetField($s_name, $LUA_GLOBALSINDEX, $p_state)
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_GetGlobal

Func _Lua_Initiate()
	If $__g_hluadll <> 0 Then Return 1
	$__g_hluadll = DllOpen($__g_sluadll)
	If $__g_hluadll = -1 Then
		$__g_hluadll = 0
		Return SetError(-1, 0, 0)
	EndIf
	Return 1
EndFunc  ;==>_Lua_Initiate

Func _Lua_LoadFile($s_filename, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	Local $a_ret = DllCall($__g_hluadll, "int:cdecl", "luaL_loadfile", "ptr", $p_state, "str", $s_filename)
	If @error Or $a_ret[0] <> 0 Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_LoadFile

Func _Lua_LoadString($s_string, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	Local $a_ret = DllCall($__g_hluadll, "int:cdecl", "luaL_loadstring", "ptr", $p_state, "str", $s_string & Chr(0))
	If @error Or $a_ret[0] <> 0 Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_LoadString

Func _Lua_Open()
	$__g_pluanewstate = 0
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	Local $a_ret = DllCall($__g_hluadll, "ptr:cdecl", "luaL_newstate", "ptr", 0, "ptr", 0)
	If @error Or $a_ret[0] = 0 Then Return SetError(1, 0, 0)
	$__g_pluanewstate = $a_ret[0]
	Return $a_ret[0]
EndFunc  ;==>_Lua_Open

Func _Lua_OpenLibs($p_state = 0)  ; == Ersetzen durch "luaL_register"
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "luaL_openlibs", "ptr", $p_state)
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_OpenLibs

Func _Lua_PCall($i_args, $i_results, $i_errfunc = 0, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	Local $a_ret = DllCall($__g_hluadll, "int:cdecl", "lua_pcall", _
		"ptr", $p_state, "int", Int($i_args), "int", Int($i_results), "int", Int($i_errfunc))
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_PCall

Func _Lua_Pop($i_pop, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "lua_pop", "ptr", $p_state, "int", Int($i_pop))
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_Pop

Func _Lua_PushBoolean($i_bool, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "lua_pushboolean", "ptr", $p_state, "int", $i_bool)
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_PushBoolean

Func _Lua_PushInteger($i_num, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "lua_pushinteger", "ptr", $p_state, "int", Int($i_num))
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_PushInteger

Func _Lua_PushNil($p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "lua_pushnil", "ptr", $p_state)
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_PushNil

Func _Lua_PushNumber($n_num, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "lua_pushnumber", "ptr", $p_state, "double", Number($n_num))
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_PushNumber

Func _Lua_PushString($s_str, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	DllCall($__g_hluadll, "none:cdecl", "lua_pushstring", "ptr", $p_state, "str", $s_str & Chr(0))
	If @error Then Return SetError(1, 0, 0)
	Return 1
EndFunc  ;==>_Lua_PushString

Func _Lua_RunFuncFile($_sFileLua, $_sFuncLua, $_aParam="", $_sRetType="") ; $_sRetType = comma seperated string with return type(s) in order of return
	If Not FileExists($_sFileLua) Then Return SetError(1, 0, 0)
	_Lua_DoFile($_sFileLua)
	_Lua_GetGlobal($_sFuncLua)
	If $_aParam <> "" Then
		For $i = 0 To UBound($_aParam) -1
			Switch __ParamGetType($_aParam[$i])
				Case "nil"
					_Lua_PushNil()
				Case "bool"
					_Lua_PushBoolean($_aParam[$i])
				Case "int"
					_Lua_PushInteger($_aParam[$i])
				Case "num"
					_Lua_PushNumber($_aParam[$i])
				Case "str"
					_Lua_PushString($_aParam[$i])
			EndSwitch
		Next
	EndIf
	Local $aRetType = StringSplit($_sRetType, ',', 2)
	Local $iRetCount = UBound($aRetType)
	_Lua_Call(UBound($_aParam), $iRetCount)
	Local $aReturn[$iRetCount]
	For $i = 0 To $iRetCount -1
		Switch $aRetType[$i]
			Case "str", "nil"
				$aReturn[$i] = _Lua_ToString((-1)*$iRetCount + $i)
			Case "bool"
				$aReturn[$i] = _Lua_ToBoolean((-1)*$iRetCount + $i)
			Case "int", "num"
				$aReturn[$i] = _Lua_ToNumber((-1)*$iRetCount + $i)
		EndSwitch
		_Lua_Pop(1)
	Next
	If $iRetCount = 1 Then Return $aReturn[0]
	Return $aReturn
EndFunc  ;==>_Lua_RunFuncFile

Func __ParamGetType($_vParam)
	If $_vParam = "nil"   Then Return "nil"
	If IsBool  ($_vParam) Then Return "bool"
	If IsInt   ($_vParam) Then Return "int"
	If IsNumber($_vParam) Then Return "num"
	                           Return "str"
EndFunc  ;==>__ParamGetType

Func _Lua_RunFuncLocal($_strFunc, $_sFuncLua, $_aParam='', $_sRetType='') ; $_sRetType = comma seperated string with return type(s) in order of return
	Local $sFuncPath = @ScriptDir & '\tmp_LuaFunc.lua'
	Local $fH = FileOpen($sFuncPath, 8+2)
	FileWrite($fH, $_strFunc)
	FileClose($fH)
	Local $ret = _Lua_RunFuncFile($sFuncPath, $_sFuncLua, $_aParam, $_sRetType)
	If @error Then
		FileDelete($sFuncPath)
		Return SetError(@error, 0, 0)
	Else
		FileDelete($sFuncPath)
		Return $ret
	EndIf
EndFunc  ;==>_Lua_RunFuncLocal

Func _Lua_ToBoolean($i_index, $p_state = 0)
    If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
    If $p_state = 0 Then $p_state = $__g_pluanewstate
    Local $a_ret = DllCall($__g_hluadll, "int:cdecl", "lua_toboolean", "ptr", $p_state, "int", Int($i_index))
    If @error Then Return SetError(1, 0, 0)
    Return Not Not $a_ret[0]
EndFunc  ;==>_Lua_ToBoolean

Func _Lua_ToNumber($i_index, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	Local $a_ret = DllCall($__g_hluadll, "double:cdecl", "lua_tonumber", "ptr", $p_state, "int", Int($i_index))
	If @error Then Return SetError(1, 0, 0)
	Return $a_ret[0]
EndFunc  ;==>_Lua_ToNumber

Func _Lua_ToString($i_index, $p_state = 0)
	If Not _Lua_Initiate() Then Return SetError(-1, 0, 0)
	If $p_state = 0 Then $p_state = $__g_pluanewstate
	Local $tLen = DllStructCreate("int")
	Local $a_ret = DllCall($__g_hluadll, "ptr:cdecl", "lua_tolstring", "ptr", $p_state, "int", Int($i_index), "ptr", DllStructGetPtr($tLen))
	If @error Then Return SetError(1, 0, 0)
	Local $tStr = DllStructCreate('char[' & DllStructGetData($tLen, 1) +1 & ']', $a_ret[0])
	Return DllStructGetData($tStr, 1)
EndFunc  ;==>_Lua_ToString

#endregion Functions