//script core ver 3.0.4

include(Resources.id("mtrsteamloco:scripts/js_util.js"));
include(Resources.id("fangsu:scripts/config_sc.js"));
include(Resources.id("fangsu:scripts/model_select_screen.js"));
include(Resources.id("fangsu:scripts/pzx_helper.js"));
include(Resources.id("fangsu:scripts/costom_item_helper.js"));
include(Resources.id("fangsu:scripts/block_connector.js"));
importPackage(java.awt);
importPackage(java.awt.geom);

// var res = {};

function create(ctx, state, block) {
    state.mainModel = checkAndCacheConfig(block, state, "mainModel", "fangsu:screendoor/kaba.json");

    state.subModel = checkAndCacheConfig(block, state, "subModel", "common");

    state.isLeft = checkAndCacheConfig(block, state, "isLeft", true);

    state.forceState = checkAndCacheConfig(block, state, "forceState", 0);

    state.jikongState = checkAndCacheConfig(block, state, "jikongState", 0);

    state.dmh = [];
    if (state.forceState) {
        if (state.forceState == 1) state.doorVal = block.doorTarget ? 1 : 0;
        if (state.forceState == 2) state.doorVal = 0;
        if (state.forceState == 3) state.doorVal = 1;
    } else if (state.jikongState) {
        if (state.jikongState == 1) state.doorVal = 0;
        if (state.jikongState == 2) state.doorVal = 1;
    } else state.doorVal = block.doorTarget ? 1 : 0;

    state.needRef = true;
    state.needRefBox = true;
    state.cacheMat = {};
    state.config = {};
    state.doorOpenTime = block.doorTarget ? 10000 : 0;
    state.doorCloseTime = block.doorTarget ? 0 : 10000;

    let blockConnector = getBlockConnector();
    blockConnector.initBlockState(block, { type: "screendoor", cacheJikongState: state.jikongState });
}

function render(ctx, state, block) {
    // if (state.cacheMainMod != block.getCustomConfig("mainModel") || state.cacheSubMod != block.getCustomConfig("subModel")) {
    //     state.needRef = true;
    // }
    // if (state.isLeft != state.cacheIsLeft) {
    //     state.needRef = true;
    //     state.cacheIsLeft = state.isLeft;
    //     block.putCustomConfig("isLeft", state.isLeft ? "true" : "false");
    // }
    let blockConnector = getBlockConnector();

    if (state.config.mainModel) state.mainModel = state.config.mainModel;
    if (state.config.subModel) state.subModel = state.config.subModel;
    if (state.config.isLeft != undefined) state.isLeft = state.config.isLeft;
    if (state.config.forceState != undefined) state.forceState = state.config.forceState;
    if (blockConnector.getBlockState(block).jikongState == undefined) blockConnector.setBlockStateParam(block, "jikongState", state.jikongState);
    state.jikongState = blockConnector.getBlockState(block).jikongState;
    checkCache(block, state, "jikongState");
    checkCache(block, state, "forceState");

    state.config = {};

    state.needRef = checkCache(block, state, "mainModel") || checkCache(block, state, "subModel") || checkCache(block, state, "isLeft") || state.needRef;

    if (
        state.cacheMat.rX != block.rotateX ||
        state.cacheMat.rY != block.rotateY ||
        state.cacheMat.rZ != block.rotateZ ||
        state.cacheMat.tX != block.translateX ||
        state.cacheMat.tY != block.translateY ||
        state.cacheMat.tZ != block.translateZ
    ) {
        // 如果有任一属性不同，则更新缓存并标记需要刷新
        state.cacheMat = {
            rX: block.rotateX,
            rY: block.rotateY,
            rZ: block.rotateZ,
            tX: block.translateX,
            tY: block.translateY,
            tZ: block.translateZ
        };
        state.needRefBox = true;
    }

    if (state.needRef) {
        try {
            for (let dm of state.dmh) dm.close();
        } catch (e) {}

        state.cacheMainMod = block.getCustomConfig("mainModel");
        state.cacheSubMod = block.getCustomConfig("subModel");

        let loadedJSON = JSON.parse(loadResource("str", state.cacheMainMod));
        let loaded = parseObj(loadedJSON.door[state.isLeft ? "left" : "right"]);
        if (state.cacheSubMod in loaded) state.model = loaded[state.cacheSubMod];
        else {
            state.model = JSON.parse(loadResource("str", state.cacheMainMod)).door[state.isLeft ? "left" : "right"][0];
            block.putCustomConfig("subModel", state.model.key);
            block.sendUpdateC2S();
        }

        let mainModel = loadResource("partedModel", JSON.parse(loadResource("str", state.cacheMainMod)).model);
        // print(JSON.stringify(mainModel))
        for (let i = 0; i < state.model.doors.length; i++) {
            let door = state.model.doors[i];
            // print("[DEBUG] ", door.subModel)
            let rawModel = mainModel.get(door.subModel).copy();
            rawModel.sourceLocation = null;
            if (state.model.flipV) rawModel.applyUVMirror(false, true);
            state.dmh[i] = new DynamicModelHolder();
            state.dmh[i].uploadLater(rawModel);
        }
        state.needRef = false;
        state.needRefBox = true;
    }

    //强制状态 0-集控 1-正常 2-关 3-开
    //集控状态 0-正常 1-关 2-开
    if (state.forceState) {
        if (state.forceState == 1) {
            if (block.doorTarget || block.doorValue >= 0.6) {
                state.doorVal += Timing.delta() * 0.6;
                if (state.doorVal >= 1) state.doorVal = 1;
            } else {
                state.doorVal -= Timing.delta() * 0.6;
                if (state.doorVal <= 0) state.doorVal = 0;
            }
        }
        if (state.forceState == 2) {
            state.doorVal -= Timing.delta() * 0.6;
            if (state.doorVal <= 0) state.doorVal = 0;
        }
        if (state.forceState == 3) {
            state.doorVal += Timing.delta() * 0.6;
            if (state.doorVal >= 1) state.doorVal = 1;
        }
    } else if (state.jikongState) {
        if (state.jikongState == 1) {
            state.doorVal -= Timing.delta() * 0.6;
            if (state.doorVal <= 0) state.doorVal = 0;
        }
        if (state.jikongState == 2) {
            state.doorVal += Timing.delta() * 0.6;
            if (state.doorVal >= 1) state.doorVal = 1;
        }
    } else {
        if (block.doorTarget || block.doorValue >= 0.6) {
            state.doorVal += Timing.delta() * 0.6;
            if (state.doorVal >= 1) state.doorVal = 1;
        } else {
            state.doorVal -= Timing.delta() * 0.6;
            if (state.doorVal <= 0) state.doorVal = 0;
        }
    }

    let shape = "";
    for (let i = 0; i < state.model.doors.length; i++) {
        let door = state.model.doors[i];
        if (state.dmh[i].getUploadedModel()) {
            if (shape != "" && door.shape) shape += "/";
            if (door.shape) shape += getShape(door.shape, state.doorVal, door.step);
            let mat = new Matrices();
            mat.translate(-1 * state.doorVal * parseFloat(door.step), 0, 0);
            ctx.drawModel(state.dmh[i].getUploadedModel(), mat);
        }
    }

    if (shape == "") shape = "0,0,0,16,16,16";
    if (state.cacheShape != shape || state.needRefBox == true) {
        state.cacheShape = shape;
        let finalShape = [];
        if (shape == "0,0,0,16,16,16") {
            finalShape = [[0, 0, 0, 16, 16, 16]];
        } else
            for (let subshape of collisionBoxStrToArr(shape)) {
                // print(subshape);
                // print(rotateCollisionBox(subshape, Math.PI * block.rotateX, Math.PI * block.rotateY, Math.PI * block.rotateZ));
                finalShape = finalShape.concat(rotateCollisionBox(subshape, block, block.rotateX, block.rotateY, block.rotateZ, block.translateX * 16, block.translateY * 16, block.translateZ * 16));
            }
        // print(finalShape);
        finalShape = collisionBoxArrToStr(finalShape);
        // print(finalShape);
        block.setShape(finalShape);
        block.setCollisionShape(finalShape);
        block.sendUpdateC2S();
        state.needRefBox = false;
    }

    try {
        let platform = MinecraftClient.getPlatformAt(block.getWorldPosVector3f(), 3, 5, 4);
        let dwellTime = 0;
        if (platform) dwellTime = platform.dwellTime / 2;
        let cacheDoorOpenTime = state.doorOpenTime;
        if (block.doorTarget) state.doorOpenTime += Timing.delta();
        else state.doorOpenTime = 0;
        let cacheDoorCloseTime = state.doorCloseTime;
        if (!block.doorTarget) state.doorCloseTime += Timing.delta();
        else state.doorCloseTime = 0;

        if ((state.jikongState == 0 && state.forceState == 0) || state.forceState == 1)
            if (state.model.sounds) {
                let departTime = dwellTime - state.doorOpenTime;
                let cacheDepartCloseTime = dwellTime - cacheDoorOpenTime;
                for (let sound of state.model.sounds) {
                    if (sound.type == "open" && block.doorTarget) {
                        if (cacheDoorOpenTime >= sound.delay && state.doorOpenTime <= sound.delay) {
                            setDebugInfo(`playing sound ${sound.path} doorOpenTime ${doorOpenTime} cache ${cacheDoorOpenTime} delay ${sound.delay}`);
                            ctx.playSound(Resources.id(sound.path), 70, 1);
                        }
                    }
                    if (sound.type == "depart") {
                        if (cacheDepartCloseTime <= sound.delay && departTime >= sound.delay) {
                            setDebugInfo(`playing sound ${sound.path} departTime ${departTime} cache ${cacheDepartCloseTime} delay ${sound.delay}`);
                            ctx.playSound(Resources.id(sound.path), 70, 1);
                        }
                    }
                    if (sound.type == "close" && !block.doorTarget) {
                        if (cacheDoorCloseTime <= sound.delay && state.doorCloseTime >= sound.delay) {
                            setDebugInfo(`playing sound ${sound.path} doorCloseTime ${state.doorCloseTime} cache ${cacheDoorCloseTime} delay ${sound.delay}`);
                            ctx.playSound(Resources.id(sound.path), 70, 1);
                        }
                    }
                }
            }
        ctx.setDebugInfo("dwellTime", dwellTime);
        ctx.setDebugInfo("doorOpenTime", state.doorOpenTime);
        ctx.setDebugInfo("doorCloseTime", state.doorCloseTime);
    } catch (e) {
        // setDebugInfo(e);
    }

    // ctx.setDebugInfo("mainModel", block.getCustomConfig("mainModel"));
    //
}

function dispose(ctx, state, block) {
    try {
        state.dynamicModelHolder.close();
    } catch (e) {}
}
function use(ctx, state, block, player) {
    let configs = [];
    let sc;
    configs.push(
        buildConfigItem(ComponentUtil.getString(ComponentUtil.translatable("cfg.content.mainmodel")), "mainModel", {
            type: "screendoor",
            defaultVal: block.getCustomConfig("mainModel"),
            showConditition: true
        })
    );
    configs.push(
        buildConfigItem(ComponentUtil.getString(ComponentUtil.translatable("cfg.content.submodel")), "subModel", {
            type: "screendoor",
            saveKey: "subModel",
            path: "door." + (state.isLeft ? "left" : "right"),
            showConditition: true
        })
    );
    configs.push(
        buildConfigItem(ComponentUtil.getString(ComponentUtil.translatable("cfg.screendoor.is_left")), "bool", {
            style: 2,
            type: "bool",
            savePos: "isLeft",
            default: state.isLeft
        })
    );
    configs.push(
        buildConfigItem(ComponentUtil.getString(ComponentUtil.translatable("cfg.screendoor.force_state")), "list", {
            listItems: [
                { text: ComponentUtil.getString(ComponentUtil.translatable("cfg.screendoor.force_jikong")), val: 0 },
                { text: ComponentUtil.getString(ComponentUtil.translatable("cfg.screendoor.force_normal")), val: 1 },
                { text: ComponentUtil.getString(ComponentUtil.translatable("cfg.screendoor.force_close")), val: 2 },
                { text: ComponentUtil.getString(ComponentUtil.translatable("cfg.screendoor.force_open")), val: 3 }
            ],
            type: "list",
            savePos: "forceState",
            default: state.forceState
        })
    );

    sc = createConfigSc(configs, null, { ctx, state, entity: block, block }, { title: ComponentUtil.getString(ComponentUtil.translatable("cfg.title")) });
    displayConfigSc(sc);
}

function getShape(rawShape, doorVal, step) {
    let finalShape = "";
    for (let rs of rawShape) {
        if (finalShape != "") finalShape += "/";
        for (let i = 0; i < 6; i++) {
            if (i == 0 || i == 3) {
                finalShape += (rs[i] + parseFloat(doorVal * step * 16)).toFixed(1);
            } else {
                finalShape += rs[i].toFixed(1);
            }
            if (i != 5) finalShape += ",";
        }
    }
    return finalShape;
}
