importPackage(java.awt);
importPackage(java.awt.geom);
importPackage(java.awt.image);

importPackage(java.lang);
importPackage(java.util.concurrent);
include("lcd.js");
include("ikisaki.js");

let errorImage = Resources.readBufferedImage(Resources.id("mtr:new_straight_lcd/images/kr.png"));
function create(ctx, state, train) {
    state.dh = [];
    for (let i = 0; i < train.trainCars(); i++) {
        state.dh[i] = dhBase.create();
    }
    state.lcdmainRate = new RateLimit(0.1);
    state.ikisakiRate = new RateLimit(3.0);

    state.lcdSideStaticRate = new RateLimit(3.0);
    state.lcdSideDynamicRate = new RateLimit(0.5);
    state.lastPathInfo = null;
    state.lastNextIndex = -1;
    state.lastDoorOpen = false;
    state.lastStationCenters = { 'left': [], 'right': [] };


    state.modelRate = new RateLimit(0.1);
    state.font = Resources.readFont(Resources.id("mtr:font/notosansjp.ttf"));

    state.baseModel = ModelManager.loadPartedRawModel(Resources.manager(), Resources.id("mtr:new_20m_4d_straight/20m_4d_straight_new.obj"), null);
    state.masconModel = state.baseModel.get("masukon");

    state.dmhMascon = new DynamicModelHolder();
    state.dmhMascon1 = new DynamicModelHolder();

    state.dmhMascon.uploadLater(state.masconModel);
    state.dmhMascon1.uploadLater(state.masconModel);
    // ノッチの状態保存
    state.lastNotch = null;

    state.text_image = new BufferedImage(128, 32, BufferedImage.TYPE_INT_ARGB);
    state.text_g = state.text_image.createGraphics();
    state.text_front_image = new BufferedImage(128, 32, BufferedImage.TYPE_INT_ARGB);
    state.text_front_g = state.text_front_image.createGraphics();

    state.routeMapImage = new BufferedImage(600, 450, BufferedImage.TYPE_INT_ARGB);
    state.routeMapGraphics = state.routeMapImage.createGraphics();
    state.lastGeneratedNextIndex = -1;
    state.lastGeneratedDoorOpen = null;

    if (Resources.ANTE_FLAG) {
        state.LCDpool = Executors.newScheduledThreadPool(1);

        state.LCDpool.scheduleAtFixedRate(new java.lang.Runnable({
            run: () => {
                try {
                    renderLCD(ctx, state, train);
                } catch (e) {
                    print("LCD Error: " + e);
                }
            }
        }), 0, 1000 / 10, TimeUnit.MILLISECONDS);
    }
}

function renderLcdMain(ctx, state, train) {
    if (state.lcdmainRate.shouldUpdate()) {
        let g;
        for (let i = 0; i < train.trainCars(); i++) {
            let isReversed = train.isReversed();
            let leftLCD = isReversed ? "lcd_door_right" : "lcd_door_left";
            let rightLCD = isReversed ? "lcd_door_left" : "lcd_door_right";

            g = state.dh[i].graphicsFor(leftLCD);
            lcdmain(g, train, state, i + 1);
            g = state.dh[i].graphicsFor(rightLCD);
            lcdmain(g, train, state, i + 1);
            state.dh[i].upload();
        }
    }
}

function renderSideStatic(ctx, state, train) {
    if (state.lcdSideStaticRate.shouldUpdate()) {
        let g;
        for (let i = 0; i < train.trainCars(); i++) {
            let isReversed = train.isReversed();
            let leftLCD = isReversed ? "lcd_door_right" : "lcd_door_left";
            let rightLCD = isReversed ? "lcd_door_left" : "lcd_door_right";

            g = state.dh[i].graphicsFor(leftLCD);
            lcdSideStatic(g, train, state, false);
            g = state.dh[i].graphicsFor(rightLCD);
            lcdSideStatic(g, train, state, true);
            state.dh[i].upload();
        }
    }
}

function renderSideDynamic(ctx, state, train) {
    if (state.lcdSideDynamicRate.shouldUpdate()) {
        let g;
        for (let i = 0; i < train.trainCars(); i++) {
            let isReversed = train.isReversed();
            let leftLCD = isReversed ? "lcd_door_right" : "lcd_door_left";
            let rightLCD = isReversed ? "lcd_door_left" : "lcd_door_right";

            g = state.dh[i].graphicsFor(leftLCD);
            lcdSideDynamic(g, train, state, false);
            g = state.dh[i].graphicsFor(rightLCD);
            lcdSideDynamic(g, train, state, true);
            state.dh[i].upload();
        }
    }
}

function renderIkisaki(ctx, state, train) {
    if (state.ikisakiRate.shouldUpdate()) {
        let g;
        for (let i = 0; i < train.trainCars(); i++) {
            ["out_left", "out_right"].forEach(pos => {
                g = state.dh[i].graphicsFor(pos);
                ikisakiMain(g, train, state, i + 1);
            });
            state.dh[i].upload();
        }
        g = state.dh[0].graphicsFor("out_front");
        ikisakiFront(g, train, state);
        state.dh[0].upload();
        g = state.dh[train.trainCars() - 1].graphicsFor("out_back");
        ikisakiFront(g, train, state);
        state.dh[train.trainCars() - 1].upload();
    }
}

function updateDrawCalls(ctx, state, train) {
    for (let i = 0; i < train.trainCars(); i++) {
        ctx.drawCalls[i].put(i, new ClusterDrawCall(state.dh[i].model, new Matrix4f()));
    }
}

function render(ctx, state, train) {
    if (state.modelRate.shouldUpdate()) {
        let notch = ctx.train.manualNotch;
        let angle;
        switch (notch) {
            case 2:
                angle = -55;
                break;
            case 1:
                angle = -47.5;
                break;
            case 0:
                angle = -40;
                break;
            case -1:
                angle = -12.5;
                break;
            case -2:
                angle = 15;
                break;
            case -3:
                angle = 35;
                break;
            default:
                angle = -40;
        }

        if (state.lastNotch !== notch) {
            state.lastNotch = notch;

            let rotatedModel = state.masconModel.copy();

            const centerX = 1.14064;
            const centerY = 1.06607;
            const centerZ = 9.2532;//符号逆

            rotatedModel.applyTranslation(-centerX, -centerY, -centerZ);
            rotatedModel.applyRotation(new Vector3f(1, 0, 0), angle);
            rotatedModel.applyTranslation(centerX, centerY, centerZ);

            state.dmhMascon.uploadLater(rotatedModel);

            let rotatedModel1 = state.masconModel.copy();

            rotatedModel1.applyTranslation(-centerX, -centerY, -centerZ);
            rotatedModel1.applyRotation(new Vector3f(1, 0, 0), angle);
            rotatedModel1.applyTranslation(centerX, centerY, centerZ);
            rotatedModel1.applyRotation(new Vector3f(0, 1, 0), 180);

            state.dmhMascon1.uploadLater(rotatedModel1);
        }
    }

    let modelToDraw = state.dmhMascon.getUploadedModel();
    let modelToDraw1 = state.dmhMascon1.getUploadedModel();
    if (modelToDraw != null) {
        ctx.drawCarModel(modelToDraw, 0, null);
        ctx.drawCarModel(modelToDraw1, train.trainCars() - 1, null);
    }

    if (!Resources.ANTE_FLAG) {
        try {
            renderLCD(ctx, state, train);
        } catch (e) {
            print("TokikyuLCD Error: " + e);
        }
    }
}

function renderLCD(ctx, state, train) {
    renderLcdMain(ctx, state, train);
    renderSideStatic(ctx, state, train);
    renderSideDynamic(ctx, state, train);
    renderIkisaki(ctx, state, train);

    if (Resources.ANTE_FLAG) {
        for (let i = 0; i < train.trainCars(); i++) {
            ctx.drawCalls[i].put(i, new ClusterDrawCall(state.dh[i].model, new Matrix4f()));
        }
    } else {
        for (let i = 0; i < train.trainCars(); i++) {
            ctx.drawCarModel(state.dh[i].model, i, null);
        }
    }
}

function dispose(ctx, state, train) {
    if (Resources.ANTE_FLAG) {
        state.LCDpool.shutdown();
    }
    for (let i = 0; i < train.trainCars(); i++) {
        state.dh[i].close();
    }
    state.text_g.dispose();
    state.text_front_g.dispose();
    state.routeMapGraphics.dispose();
    state.dmhMascon.close();
    state.dmhMascon1.close();
}
