var renderClass = "jp.ngt.rtm.render.MachinePartsRenderer";

importPackage(Packages.jp.ngt.rtm);
importPackage(Packages.jp.ngt.ngtlib.util);
importPackage(Packages.net.minecraft.tileentity);
importPackage(Packages.net.minecraft.command.server);
importPackage(Packages.net.minecraft.util.math);
importPackage(Packages.net.minecraft.nbt);

var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");
var Base64 = Java.type("java.util.Base64");

function onUpdate(entity, scriptExecuter) {
    if (entity === null) return;

    var dataMap = entity.getResourceState().getDataMap();
    var commandBlock = searchTileEntity(entity, TileEntityCommandBlock);
    var command = readCommandBlockCommand(commandBlock);

    dataMap.setString("trapidsCommand", "", 1);
    dataMap.setString("trapidsCommandB64", encodeSyncedCommand(command), 1);
}

function toCommandString(value) {
    if (value === null || value === undefined) return null;
    var command = String(value);
    return command === "" ? null : command;
}

function encodeSyncedCommand(value) {
    var command = toCommandString(value);
    if (command === null) return "";
    try {
        return Base64.getEncoder().encodeToString(new java.lang.String(command).getBytes(StandardCharsets.UTF_8));
    } catch (e) {
        return "";
    }
}

function readCommandFromNBT(nbt) {
    var command = null;
    try { command = toCommandString(nbt.func_74779_i("Command")); } catch (e) {}
    if (command !== null) return command;
    try { command = toCommandString(nbt.getString("Command")); } catch (e) {}
    return command;
}

function readCommandBlockCommand(commandBlock) {
    if (commandBlock === null) return null;

    var logic = null;
    try { logic = commandBlock.func_145993_a(); } catch (e) {}
    if (logic === null) return null;

    var command = null;
    try { command = toCommandString(logic.func_145753_i()); } catch (e) {}
    if (command !== null) return command;

    try {
        var version = RTMCore.VERSION;
        if (version.indexOf("1.7.10") != -1){
            command = NGTUtil.getField(CommandBlockLogic.class, logic, ["Command", "field_145763_e"]);
        }else{
            command = NGTUtil.getField(CommandBlockBaseLogic.class, logic, ["Command", "field_145763_e"]);
        }
        command = toCommandString(command);
    } catch (e) {
        command = null;
    }
    if (command !== null) return command;

    try {
        var nbt = new NBTTagCompound();
        try {
            logic.func_145759_b(nbt);
        } catch (e1) {
            commandBlock.func_145841_b(nbt);
        }
        command = readCommandFromNBT(nbt);
    } catch (e) {
        command = null;
    }
    return command;
}

function MCVersionChecker() {
    var varsion = RTMCore.VERSION;
    if (varsion.indexOf("1.7.10") >= 0) return "1.7.10";
    else if (varsion.indexOf("2.0") >= 0) return "1.8.9";
    else if (varsion.indexOf("2.1") >= 0) return "1.9.4";
    else if (varsion.indexOf("2.2") >= 0) return "1.10.2";
    else if (varsion.indexOf("2.4") >= 0) return "1.12.2";
    else return "unknown";
}

function searchTileEntity(entity, typeName) {
    if(entity === null) return null;
    var searchMaxCount = 32;
    var world = entity.func_145831_w();
    if(world === null) return null;
    for (var i = 1; i <= searchMaxCount; i++) {
        var version = MCVersionChecker();
        if (version === "1.7.10"){
            var x = Math.floor(entity.field_145851_c);
            var y = Math.floor(entity.field_145848_d);
            var z = Math.floor(entity.field_145849_e);
            var block = world.func_147438_o(x, y - i, z);
            if (block instanceof typeName) return block;
        }else{
            var cmdPos = entity.func_174877_v();
            var x = Math.floor(cmdPos.func_177958_n());
            var y = Math.floor(cmdPos.func_177956_o());
            var z = Math.floor(cmdPos.func_177952_p());
            var cmdPosA = new BlockPos(x, y - i, z);
            var block = world.func_175625_s(cmdPosA);
            if (block instanceof typeName) return block;
        }
    }
    return null;
}
