package org.luaj.vm2;

import java.io.StringReader;

import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.libs.BaseLib;
import org.luaj.vm2.libs.CjsonLib;
import org.luaj.vm2.libs.CoroutineLib;
import org.luaj.vm2.libs.MathLib;
import org.luaj.vm2.libs.OsLib;
import org.luaj.vm2.libs.PackageLib;
import org.luaj.vm2.libs.StringLib;
import org.luaj.vm2.libs.TableLib;
import org.luaj.vm2.libs.Utf8Lib;

public final class Lua54JmeCoreSmokeTestMain {
	private static Globals newGlobals() {
		Globals globals = new Globals();
		globals.load(new BaseLib());
		globals.load(new PackageLib());
		globals.load(new CjsonLib());
		globals.load(new OsLib());
		globals.load(new MathLib());
		globals.load(new TableLib());
		globals.load(new StringLib());
		globals.load(new Utf8Lib());
		globals.load(new CoroutineLib());
		LoadState.install(globals);
		LuaC.install(globals);
		return globals;
	}

	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 Varargs run(String name, String script) throws Exception {
		Globals globals = newGlobals();
		return globals.load(new StringReader(script), name).invoke();
	}

	private static void checkCompileError(String name, String script, String expectedMessagePart) throws Exception {
		Globals globals = newGlobals();
		try {
			globals.load(new StringReader(script), name);
			throw new IllegalStateException(name + " expected compile error containing: " + expectedMessagePart);
		} catch (LuaError e) {
			if (e.getMessage() == null || e.getMessage().indexOf(expectedMessagePart) < 0) {
				throw new IllegalStateException(name + " unexpected compile error: " + e.getMessage(), e);
			}
			System.out.println("ok  " + name + " -> " + e.getMessage());
		}
	}

	public static void main(String[] args) throws Exception {
		check(
			"bit32_absent_jme_core",
			run("bit32_absent_jme_core", "return bit32 == nil\n"),
			LuaValue.TRUE);

		check(
			"randomseed_54_jme_core",
			run("randomseed_54_jme_core",
				"local a, b = math.randomseed(7, 9)\n" +
				"local x1, x2 = math.random(), math.random(1, 1000000)\n" +
				"math.randomseed(7, 9)\n" +
				"local y1, y2 = math.random(), math.random(1, 1000000)\n" +
				"return a, b, x1 == y1 and x2 == y2\n"),
			LuaValue.valueOf(7),
			LuaValue.valueOf(9),
			LuaValue.TRUE);

		checkCompileError(
			"const_local_jme_core",
			"local x <const> = 1\nx = 2\n",
			"const variable");

		check(
			"close_scope_jme_core",
			run("close_scope_jme_core",
				"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.valueOf("closed"));
	}
}
