package nl.rug.ai.mas.oops.lua;
import java.awt.FontFormatException;
import java.io.IOException;
import nl.rug.ai.mas.oops.AxiomSystem;
import nl.rug.ai.mas.oops.ObserveProver;
import nl.rug.ai.mas.oops.Prover;
import nl.rug.ai.mas.oops.TableauErrorException;
import nl.rug.ai.mas.oops.formula.Formula;
import nl.rug.ai.mas.oops.model.ModelConstructingObserver;
import nl.rug.ai.mas.oops.parser.FormulaParser;
import nl.rug.ai.mas.oops.render.TableauObserverSwing;
import nl.rug.ai.mas.oops.tableau.SystemOutObserver;
import nl.rug.ai.mas.oops.theory.Theory;
import org.luaj.vm.LFunction;
import org.luaj.vm.LTable;
import org.luaj.vm.LUserData;
import org.luaj.vm.LuaState;
public class LuaTheory {
private LuaFormula d_formula;
public LuaTheory(LuaFormula formula) {
d_formula = formula;
}
private static class TheoryData {
private Theory d_theory;
private FormulaParser d_parser;
private ModelConstructingObserver d_constructor;
public TheoryData(Prover prover) {
d_theory = new Theory(prover);
d_parser = new FormulaParser(prover.getContext());
d_constructor = new ModelConstructingObserver(prover.getModel());
}
public Theory getTheory() {
return d_theory;
}
public FormulaParser getParser() {
return d_parser;
}
public ModelConstructingObserver getModelConstructor() {
return d_constructor;
}
public String toString() {
return d_theory.getProver().getAxiomSystem().toString() + d_theory.toString();
}
}
public static TheoryData checkTheory(LuaState L, int pos) {
Object o = L.touserdata(pos);
if (!(o instanceof TheoryData)) {
L.error("Expected a TheoryAndParser");
}
TheoryData theory = (TheoryData)o;
return theory;
}
private Formula checkFormula(LuaState L, int pos, TheoryData theory) {
Formula f = d_formula.checkFormula(L, pos, theory.getParser());
if (!theory.getTheory().getProver().validate(f)) {
L.error("Formula failed to validate");
}
return f;
}
/**
* Register LuaTheory with the Lua VM. Leaves a constructor method on the stack.
* @param L
*/
public void register(LuaState L) {
final LTable table = new LTable();
table.put("__index", table);
table.put("add", new FunctionAdd());
table.put("provable", new FunctionProvable());
table.put("satisfiable", new FunctionSatisfiable());
table.put("consistent", new FunctionConsistent());
table.put("attachTableauVisualizer", new FunctionAttachTableauVisualizer());
table.put("attachTableauObserver", new FunctionAttachTableauObserver());
table.put("attachModelConstructor", new FunctionAttachModelConstructor());
table.put("getModel", new FunctionGetModel());
table.put("showModel", new FunctionShowModel());
L.pushfunction(new Constructor(table));
}
private final class Constructor extends LFunction {
private final LTable table;
private Constructor(LTable table) {
this.table = table;
}
public int invoke(LuaState L) {
AxiomSystem system = AxiomSystem.S5;
if (!L.isnil(1)) {
String systemStr = L.tostring(1);
system = AxiomSystem.valueOf(systemStr);
}
Prover prover = system.buildProver();
L.pushlvalue(new LUserData(new TheoryData(prover), table));
return 1;
}
}
private final class FunctionConsistent extends LFunction {
public int invoke(LuaState L) {
TheoryData theory = LuaTheory.checkTheory(L, 1);
try {
L.pushboolean(theory.getTheory().consistent());
} catch (TableauErrorException e) {
L.error(e.toString());
}
return 1;
}
}
private final class FunctionSatisfiable extends LFunction {
public int invoke(LuaState L) {
TheoryData theory = LuaTheory.checkTheory(L, 1);
Formula f = checkFormula(L, 2, theory);
try {
L.pushboolean(theory.getTheory().satisfiable(f));
} catch (TableauErrorException e) {
L.error(e.toString());
}
return 1;
}
}
private final class FunctionProvable extends LFunction {
public int invoke(LuaState L) {
TheoryData theory = LuaTheory.checkTheory(L, 1);
Formula f = checkFormula(L, 2, theory);
try {
L.pushboolean(theory.getTheory().provable(f));
} catch (TableauErrorException e) {
L.error(e.toString());
}
return 1;
}
}
private final class FunctionAdd extends LFunction {
public int invoke(LuaState L) {
TheoryData theory = LuaTheory.checkTheory(L, 1);
Formula f = checkFormula(L, 2, theory);
theory.getTheory().add(f);
return 0;
}
}
private final class FunctionGetModel extends LFunction {
public int invoke(LuaState L) {
TheoryData data = LuaTheory.checkTheory(L, 1);
L.pushlvalue(new LUserData(data.getModelConstructor().getModel()));
return 1;
}
}
private final class FunctionShowModel extends LFunction {
public int invoke(LuaState L) {
TheoryData data = LuaTheory.checkTheory(L, 1);
ObserveProver.showModel(data.getModelConstructor().getModel());
return 0;
}
}
private final class FunctionAttachModelConstructor extends LFunction {
public int invoke(LuaState L) {
TheoryData data = LuaTheory.checkTheory(L, 1);
data.getTheory().getProver().getTableau().attachObserver(data.getModelConstructor());
return 0;
}
}
private final class FunctionAttachTableauVisualizer extends LFunction {
public int invoke(LuaState L) {
try {
TheoryData data = LuaTheory.checkTheory(L, 1);
Prover prover = data.getTheory().getProver();
prover.getTableau().attachObserver(new TableauObserverSwing());
} catch (IOException e) {
throw new RuntimeException(e);
} catch (FontFormatException e) {
throw new RuntimeException(e);
}
return 0;
}
}
private final class FunctionAttachTableauObserver extends LFunction {
public int invoke(LuaState L) {
TheoryData data = LuaTheory.checkTheory(L, 1);
Prover prover = data.getTheory().getProver();
prover.getTableau().attachObserver(new SystemOutObserver());
return 0;
}
}
}