package org.luaj.vm2;

import java.io.StringReader;
import java.util.Hashtable;

import org.luaj.vm2.libs.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;

public final class Lua54LuaJcSmokeTestMain {
	private static void check(String name, Varargs actual, LuaValue... expected) {
		if (actual.narg() != expected.length) {
			throw new IllegalStateException(name + " expected " + expected.length + " values but got " + actual.narg() + ": " + actual);
		}
		for (int i = 0; i < expected.length; i++) {
			LuaValue value = actual.arg(i + 1);
			if (!value.eq_b(expected[i])) {
				throw new IllegalStateException(name + " mismatch at #" + (i + 1) + ": expected " + expected[i] + " but got " + value);
			}
		}
		System.out.println("ok  " + name + " -> " + actual);
	}

	private static LuaValue loadChunk(String name, String script) throws Exception {
		Globals globals = JsePlatform.debugGlobals();
		LuaJC.install(globals);
		return globals.load(new StringReader(script), name);
	}

	private static void checkChunkType(String name, LuaValue chunk) {
		if (chunk instanceof LuaClosure) {
			throw new IllegalStateException(name + " expected luajc-generated function but got LuaClosure fallback");
		}
		System.out.println("ok  " + name + "_type -> " + chunk.getClass().getName());
	}

	private static void checkCompileAll(String name, String script) throws Exception {
		Globals globals = JsePlatform.debugGlobals();
		Hashtable classes = LuaJC.instance.compileAll(new StringReader(script), name, name + ".lua", globals, true);
		if (classes == null || classes.isEmpty()) {
			throw new IllegalStateException(name + " expected generated classes");
		}
		if (!classes.containsKey(name)) {
			throw new IllegalStateException(name + " expected generated top-level class '" + name + "' but got " + classes.keySet());
		}
		System.out.println("ok  " + name + "_compileAll -> " + classes.size() + " classes");
	}

	public static void main(String[] args) throws Exception {
		String closeScript =
			"local mt = { __close = function(self, err) _G.marker = err or 'closed' end }\n" +
			"do local h <close> = setmetatable({}, mt) end\n" +
			"return marker\n";
		LuaValue closeChunk = loadChunk("luajc_close_scope", closeScript);
		checkChunkType("luajc_close_scope", closeChunk);
		check("luajc_close_scope", closeChunk.invoke(), LuaValue.valueOf("closed"));

		String errorCloseScript =
			"local mt = { __close = function(self, err) _G.marker = err end }\n" +
			"local ok, err = pcall(function()\n" +
			"  local h <close> = setmetatable({}, mt)\n" +
			"  error('boom')\n" +
			"end)\n" +
			"return ok, marker == err and string.find(err, 'boom', 1, true) ~= nil\n";
		LuaValue errorChunk = loadChunk("luajc_close_error", errorCloseScript);
		checkChunkType("luajc_close_error", errorChunk);
		check("luajc_close_error", errorChunk.invoke(), LuaValue.FALSE, LuaValue.TRUE);

		checkCompileAll("luajc_compile_all_close", closeScript);
	}
}
