package ragefist.core.environment.bindings;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import static org.luaj.vm2.LuaValue.NIL;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.ZeroArgFunction;
import ragefist.core.environment.EnvironmentCallTask;
import ragefist.core.environment.EnvironmentProcessor.EnvironmentBindingAPI;
import ragefist.core.util.FormatTools;
/*
* Created by Andrey Cherkashin (acherkashin)
* http://acherkashin.me
*
* License
* Copyright (c) 2015 Andrey Cherkashin
* The project released under the MIT license: http://opensource.org/licenses/MIT
*/
/**
*
* @author acherkashin
*/
public class LuaProcessor extends TwoArgFunction
{
public static class LuaProcessorTask
{
private static int _nextId;
private final int _id;
private LuaValue _coroutine;
private boolean _isPaused = false;
private LuaValue _args;
public LuaProcessorTask() {
_id = ++_nextId;
if (_nextId == Integer.MAX_VALUE) {
_nextId = 1;
}
}
}
private Queue<LuaProcessorTask> _tasks = new ArrayDeque<>();
private Map<LuaValue,LuaProcessorTask> _tasksByCoroutineMap = new HashMap<>();
private Map<Integer,LuaProcessorTask> _tasksByIdMap = new HashMap<>();
private final EnvironmentBindingAPI _environment;
// ---------------------------------------------------------------------- //
// PUBLIC
// ---------------------------------------------------------------------- //
public LuaProcessor(EnvironmentBindingAPI environment) {
_environment = environment;
}
public void processTasks() {
LuaValue coroutine = _environment.getGlobals().get("coroutine");
// processing tasks
Iterator<LuaProcessorTask> it = _tasks.iterator();
while(it.hasNext()) {
LuaProcessorTask task = it.next();
if (task._isPaused) {
continue;
}
String status = coroutine.get("status").call(task._coroutine).tojstring();
if ("suspended".equals(status)) {
Varargs result;
if (task._args != null) {
result = coroutine.get("resume").invoke(task._coroutine, task._args);
task._args = null;
} else {
result = coroutine.get("resume").invoke(task._coroutine);
}
if (result.toboolean(1) == false) {
Logger.getGlobal().severe("LUA PROCESS TASK ERROR: "+result.tojstring(1)+", "+result.tojstring(2));
} else {
status = coroutine.get("status").call(task._coroutine).tojstring();
if ("dead".equals(status)) {
it.remove();
_tasksByCoroutineMap.remove(task._coroutine);
_tasksByIdMap.remove(task._id);
}
}
}
}
}
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable table = LuaValue.tableOf();
table.set("addTask", lua_addTask);
table.set("onTaskFinish", lua_onTaskFinish);
table.set("pauseCurrent", lua_pauseCurrent);
table.set("unpauseTask", lua_unpauseTask);
table.set("yield", lua_yield);
env.set("Processor", table);
return table;
}
ZeroArgFunction lua_yield = new ZeroArgFunction() {
@Override
public LuaValue call() {
return _environment.getGlobals().get("coroutine").get("yield").call();
}
};
ZeroArgFunction lua_pauseCurrent = new ZeroArgFunction() {
@Override
public LuaValue call() {
LuaValue coroutine = _environment.getGlobals().get("coroutine").get("running").call();
if (!_tasksByCoroutineMap.containsKey(coroutine)) {
Logger.getLogger(LuaProcessor.class.getName()).log(Level.WARNING, "Failed to pause current coroutine cause it does not exist");
return NIL;
}
LuaProcessorTask task = _tasksByCoroutineMap.get(coroutine);
task._isPaused = true;
return LuaValue.valueOf(task._id);
}
};
TwoArgFunction lua_unpauseTask = new TwoArgFunction() {
@Override
public LuaValue call(LuaValue lv1, LuaValue lv2) {
Integer taskId = lv1.toint();
LuaProcessorTask task = _tasksByIdMap.get(taskId);
task._isPaused = false;
if (lv2.isnil() == false) {
task._args = lv2;
}
return NIL;
}
};
OneArgFunction lua_addTask = new OneArgFunction() {
@Override
public LuaValue call(LuaValue lv) {
LuaProcessorTask task = new LuaProcessorTask();
task._coroutine = (LuaValue) _environment.getGlobals().get("coroutine").get("create").call(lv);
_tasks.add(task);
_tasksByCoroutineMap.put(task._coroutine, task);
_tasksByIdMap.put(task._id, task);
return NIL;
}
};
TwoArgFunction lua_onTaskFinish = new TwoArgFunction()
{
@Override
public LuaValue call(LuaValue lv, LuaValue lv1) {
EnvironmentCallTask task = (EnvironmentCallTask)lv.touserdata();
Object data = FormatTools.fromLuaToJUniformObject(lv1);
task.completeWithData(data);
return NIL;
}
};
}