function drawLCD(g, drawableRoute, texArea, state, train, trainConfig, doorInfo) {
    const originalClip = g.getClip();

    const cjkFont = loadResource("font", trainConfig.cjkFont);
    const nonCjkFont = loadResource("font", trainConfig.nonCjkFont);

    const imgLogo = loadResource("img", "mtrsteamloco:lcds/bj_new/logo.png");
    const imgDoor = loadResource("img", "mtrsteamloco:lcds/bj_new/door.png");

    let [x, y, w, h] = texArea;
    let trainStatus = drawableRoute.trainStatus;
    let { routeName, routeColor } = drawableRoute;

    if (!drawableRoute.finalFullRouteStations) return;

    let stations = drawableRoute.finalFullRouteStations;
    let index = drawableRoute.fullRouteIndex;

    if (index > stations.length - 1 || drawableRoute.trainStatus == STATUS_MAP.NO_ROUTE || trainStatus == STATUS_MAP.CHANGING || drawableRoute.trainStatus == STATUS_MAP.WAITING) {
        g.setColor(Color.BLACK);
        g.fillRect(x, y, w, h);
        return;
    }

    g.setColor(Color.WHITE);
    g.fillRect(x, y, w, h);

    drawGradientLine(g, widthPercent(0.1), heightPercent(0.22), widthPercent(0.5), heightPercent(0.22), Color.GRAY, h * 0.01);
    drawGradientLine(g, widthPercent(0.9), heightPercent(0.22), widthPercent(0.5), heightPercent(0.22), Color.GRAY, h * 0.01);
    drawGradientLine(g, x + h * 0.3, heightPercent(0.3), x + h * 0.3, heightPercent(0.6), Color.GRAY, h * 0.01);
    drawGradientLine(g, x + h * 0.3, heightPercent(0.9), x + h * 0.3, heightPercent(0.6), Color.GRAY, h * 0.01);

    //top
    g.drawImage(imgLogo, x + h * 0.03, heightPercent(0.03), h * 0.14, h * 0.14, null);
    let currentX = widthPercent(0) + h * 0.2;
    g.setColor(rgbToColor(1, 39, 118));
    currentX += drawStrDoubleLang(g, cjkFont, nonCjkFont, trainConfig.title, currentX, heightPercent(0.17), h * 0.14, 0, 1);
    currentX += h * 0.05;
    currentX += drawLineBox(g, drawableRoute, currentX, heightPercent(0.02), h * 0.15, 0);
    currentX += h * 0.05;

    drawGradientLine(g, currentX, heightPercent(0.01), currentX, heightPercent(0.1), Color.GRAY, h * 0.01);
    drawGradientLine(g, currentX, heightPercent(0.19), currentX, heightPercent(0.1), Color.GRAY, h * 0.01);

    let leftWidth = currentX - x;
    currentX = widthPercent(1) - h * 0.1;

    drawGradientLine(g, currentX, heightPercent(0.01), currentX, heightPercent(0.1), Color.GRAY, h * 0.01);
    drawGradientLine(g, currentX, heightPercent(0.19), currentX, heightPercent(0.1), Color.GRAY, h * 0.01);

    g.setColor(rgbToColor(1, 39, 118));
    currentX -= h * 0.05;
    currentX -= drawStrUnified(g, nonCjkFont, getWorldTime().h + ":" + getWorldTime().m, currentX, heightPercent(0.16), h * 0.12, 2);
    currentX -= h * 0.025;
    var date = new Date();
    let timeText1 = padZero(date.getMonth() + 1) + "月" + padZero(date.getDate()) + "日";
    let timeText2 = "星期" + ["日", "一", "二", "三", "四", "五", "六"][date.getDay()];
    let timeTextWidth = Math.max(getUnifiedStringWidth(g, cjkFont, timeText1, h * 0.05), getUnifiedStringWidth(g, cjkFont, timeText2, h * 0.05));
    drawStrUnified(g, cjkFont, timeText1, currentX - timeTextWidth * 0.5, heightPercent(0.08), h * 0.05, 1);
    drawStrUnified(g, cjkFont, timeText2, currentX - timeTextWidth * 0.5, heightPercent(0.14), h * 0.05, 1);
    currentX -= timeTextWidth;
    currentX -= h * 0.025;

    drawGradientLine(g, currentX, heightPercent(0.01), currentX, heightPercent(0.1), Color.GRAY, h * 0.01);
    drawGradientLine(g, currentX, heightPercent(0.19), currentX, heightPercent(0.1), Color.GRAY, h * 0.01);

    g.setColor(rgbToColor(1, 39, 118));

    currentX -= h * 0.1;
    currentX -= drawStrDoubleLang(g, cjkFont, nonCjkFont, addPrefix(stations[stations.length - 1].stationName, "开往: |Destination: ", true), currentX, heightPercent(0.17), h * 0.14, 2, 1);
    currentX -= h * 0.1;

    drawGradientLine(g, currentX, heightPercent(0.01), currentX, heightPercent(0.1), Color.GRAY, h * 0.01);
    drawGradientLine(g, currentX, heightPercent(0.19), currentX, heightPercent(0.1), Color.GRAY, h * 0.01);

    let rightWdith = x + w - currentX;
    let centralWidth = w - leftWidth - rightWdith;

    let centralTextWidth1 = getDLStringWidth(
        g,
        cjkFont,
        nonCjkFont,
        trainStatus == STATUS_MAP.RUNNING || trainStatus == STATUS_MAP.CHANGING || trainStatus == STATUS_MAP.DEPARTING ? "下一站|Next Station" : "本站|This Station",
        h * 0.14
    );
    let centralTextWidth2 = getUnifiedStringWidth(g, cjkFont, `${getMatching(stations[index].stationName, true)} · ${getMatching(stations[index].stationName, false)}`, h * 0.08);

    currentX = x + (w - leftWidth - rightWdith) * 0.5 + leftWidth - (centralTextWidth1 + centralTextWidth2 + h * 0.2) * 0.5;
    currentX += drawStrDoubleLang(
        g,
        cjkFont,
        nonCjkFont,
        trainStatus == STATUS_MAP.RUNNING || trainStatus == STATUS_MAP.CHANGING || trainStatus == STATUS_MAP.DEPARTING ? "下一站|Next Station" : "本站|This Station",
        currentX,
        heightPercent(0.17),
        h * 0.14,
        0,
        1
    );
    currentX += h * 0.1;
    currentX += drawStrUnified(g, cjkFont, `${getMatching(stations[index].stationName, true)} · ${getMatching(stations[index].stationName, false)}`, currentX, heightPercent(0.15), h * 0.08, 0);

    g.setStroke(new BasicStroke(h * 0.001));

    //cyber doorlight
    let isOpen = false;
    if (doorInfo.isLeft) isOpen = train.doorLeftOpen[doorInfo.cart - 1];
    else isOpen = train.doorRightOpen[doorInfo.cart - 1];
    g.setColor(Color.GRAY);
    g.fillOval(x + h * 0.05, heightPercent(0.3), h * 0.2, h * 0.2);
    g.fillOval(x + h * 0.05, heightPercent(0.6), h * 0.2, h * 0.2);
    g.setColor(
        isOpen && ((train.doorValue() > 0 && train.doorValue() < 0.2) || (train.doorValue() > 0.4 && train.doorValue() < 0.6) || train.doorValue() >= 0.8) ? Color.YELLOW : rgbToColor(154, 169, 173)
    );
    g.fillOval(x + h * 0.065, heightPercent(0.315), h * 0.17, h * 0.17);
    g.setColor(rgbToColor(156, 162, 191));
    g.fillOval(x + h * 0.065, heightPercent(0.615), h * 0.17, h * 0.17);
    g.setColor(Color.BLACK);
    drawStrUnified(g, cjkFont, "开关门", x + h * 0.15, heightPercent(0.575), h * 0.06, 1);
    drawStrUnified(g, cjkFont, "门隔离", x + h * 0.15, heightPercent(0.875), h * 0.06, 1);

    if (trainStatus == STATUS_MAP.RUNNING || trainStatus == STATUS_MAP.DEPARTING || (trainStatus == STATUS_MAP.ARRIVED && train.speed() > 0)) {
        // if (true) {
        var circleSize = h * 0.075;
        var distances = (w * 0.7) / (stations.length - 1);
        let basicY = heightPercent(0.6);
        for (let i = 0; i < stations.length; i++) {
            let thisStation = stations[i];
            let stationState = thisStation.flag;
            let nextStationState = i < stations.length - 1 ? stations[i + 1].flag : 0;
            let thisX = widthPercent(0.2) + distances * i;
            let nameOnTop = i % 2 == 0;

            let rectColor = rgbToColor(167, 168, 168);
            switch (nextStationState) {
                case 0:
                    rectColor = routeColor;
                    break;
                case 1:
                    rectColor = routeColor;
                    break;
                default:
                    rectColor = rgbToColor(167, 168, 168);
            }
            g.setColor(rectColor);
            if (i < stations.length - 1) {
                let arrowPos = nextStationState == 1 ? (Timing.elapsed() % 1.5) / 1.5 : 0.5;
                g.setClip(new Rectangle(thisX, basicY - h * 0.01, distances, h * 0.03));
                g.fillPolygon(
                    [thisX, thisX + distances * arrowPos - h * 0.0375, thisX + distances * arrowPos - h * 0.025, thisX + distances * arrowPos - h * 0.0375, thisX],
                    [basicY - h * 0.05, basicY - h * 0.05, basicY, basicY + h * 0.05, basicY + h * 0.05],
                    5
                );
                g.fillPolygon(
                    [
                        thisX + distances * arrowPos - h * 0.025,
                        thisX + distances * arrowPos - h * 0.0125,
                        thisX + distances * arrowPos - h * 0.025,
                        thisX + distances * arrowPos - h * 0.0125,
                        thisX + distances * arrowPos,
                        thisX + distances * arrowPos - h * 0.0125
                    ],
                    [basicY - h * 0.05, basicY, basicY + h * 0.05, basicY + h * 0.05, basicY, basicY - h * 0.05],
                    6
                );
                g.fillPolygon(
                    [
                        thisX + distances * arrowPos + h * 0.0,
                        thisX + distances * arrowPos + h * 0.0125,
                        thisX + distances * arrowPos + h * 0.0,
                        thisX + distances * arrowPos + h * 0.0125,
                        thisX + distances * arrowPos + h * 0.025,
                        thisX + distances * arrowPos + h * 0.0125
                    ],
                    [basicY - h * 0.05, basicY, basicY + h * 0.05, basicY + h * 0.05, basicY, basicY - h * 0.05],
                    6
                );
                g.fillPolygon(
                    [thisX + distances, thisX + distances * arrowPos + h * 0.025, thisX + distances * arrowPos + h * 0.0375, thisX + distances * arrowPos + h * 0.025, thisX + distances],
                    [basicY - h * 0.05, basicY - h * 0.05, basicY, basicY + h * 0.05, basicY + h * 0.05],
                    5
                );
                g.setClip(originalClip);
            }
            if (thisStation.transInfo) {
                let finalTransName = "";
                g.setClip(
                    new Polygon(
                        [thisX - circleSize * 0.35, thisX - circleSize * 0.35, thisX, thisX + circleSize * 0.35, thisX + circleSize * 0.35],
                        [basicY, basicY + h * 0.06 * (nameOnTop ? 1 : -1), basicY + h * 0.09 * (nameOnTop ? 1 : -1), basicY + h * 0.06 * (nameOnTop ? 1 : -1), basicY],
                        5
                    )
                );
                let currentY = basicY + (nameOnTop ? h * 0.1 : h * -0.2);
                for (let i = 0; i < thisStation.transInfo.length; i++) {
                    let thisTrans = thisStation.transInfo[i];
                    g.setColor(stationState <= 1 ? thisTrans.routeColor : rgbToColor(167, 168, 168));
                    g.fillRect(thisX - circleSize * 0.35 + (i * circleSize * 0.7) / thisStation.transInfo.length, heightPercent(0.1), (circleSize * 0.7) / thisStation.transInfo.length + 1, h * 0.8);
                }
                g.setClip(originalClip);
                for (let i = 0; i < thisStation.transInfo.length; i++) {
                    let thisTrans = thisStation.transInfo[i];
                    drawLineBox(g, thisTrans, thisX, currentY, h * 0.08, 1);
                    currentY += h * 0.09 * (nameOnTop ? 1 : -1);
                }
            }
            g.setColor(rectColor);
            if (stationState == 2) g.setColor(rgbToColor(167, 168, 168));
            g.fillOval(thisX - circleSize * 0.5, basicY - circleSize * 0.5, circleSize, circleSize);
            g.setColor(g.getColor().brighter());
            g.fillOval(thisX - circleSize * 0.4, basicY - circleSize * 0.4, circleSize * 0.8, circleSize * 0.8);
            if (stationState == 2) {
                g.setColor(rgbToColor(167, 168, 168));
                g.fillPolygon(
                    [thisX - circleSize * 0.2, thisX, thisX + circleSize * 0.2, thisX, thisX - circleSize * 0.2, thisX],
                    [basicY - circleSize * 0.3, basicY - circleSize * 0.3, basicY, basicY + circleSize * 0.3, basicY + circleSize * 0.3, basicY],
                    6
                );
            }
            if (stationState == 1) {
                g.setColor(rectColor);
                g.fillOval(
                    thisX - circleSize * 0.4 * (Timing.elapsed() % 1),
                    basicY - circleSize * 0.4 * (Timing.elapsed() % 1),
                    circleSize * 0.8 * (Timing.elapsed() % 1),
                    circleSize * 0.8 * (Timing.elapsed() % 1)
                );
                g.setColor(g.getColor().brighter());
                g.fillOval(
                    thisX - circleSize * 0.3 * (Timing.elapsed() % 1),
                    basicY - circleSize * 0.3 * (Timing.elapsed() % 1),
                    circleSize * 0.6 * (Timing.elapsed() % 1),
                    circleSize * 0.6 * (Timing.elapsed() % 1)
                );
            }

            g.setColor(stationState == 1 ? rgbToColor(1, 39, 118) : stationState == 0 ? Color.BLACK : rgbToColor(167, 168, 168));
            drawStrDoubleLang(
                g,
                cjkFont,
                nonCjkFont,
                thisStation.stationName,
                thisX,
                basicY + (nameOnTop ? h * -0.1 : h * 0.225),
                h * 0.125 + (stationState == 1 ? h * -0.025 * Math.abs(Math.sin(Timing.elapsed())) : 0),
                1,
                1
            );
        }
    } else if (trainStatus == STATUS_MAP.ARRIVED) {
        //if (screenState) {
        g.setColor(rgbToColor(59, 82, 139));
        // let sideW = 0.5 * (w - drawStrDL(g, routeInfo.stationDetails[nextStationIndex].stationName, widthPercent(0.5), heightPercent(0.35), h * 0.3, 1, 1));
        g.setColor(Color.BLACK);
        drawStrDL(g, cjkFont, nonCjkFont, stations[index].stationName, widthPercent(0.5), heightPercent(0.35), h * 0.35, 1, 1);

        if (isOpen) {
            g.drawImage(imgDoor, widthPercent(0.8) - w * 0.025 * state.doorVal, heightPercent(0.35), w * 0.05, h * 0.35, null);
            g.drawImage(imgDoor, widthPercent(0.85) + w * 0.025 * state.doorVal, heightPercent(0.35), w * 0.05, h * 0.35, null);
            drawStrDL(g, cjkFont, nonCjkFont, "本侧开门|The door of this side is open", widthPercent(0.85), heightPercent(0.675), h * 0.1, 1, 1);
        } else {
            g.drawImage(imgDoor, widthPercent(0.8), heightPercent(0.35), w * 0.05, h * 0.35, null);
            g.drawImage(imgDoor, widthPercent(0.85), heightPercent(0.35), w * 0.05, h * 0.35, null);
            drawStrDL(g, cjkFont, nonCjkFont, "对侧开门|The door of opposite side is open", widthPercent(0.85), heightPercent(0.675), h * 0.1, 1, 1);
        }
    }
    function widthPercent(p) {
        return x + w * p;
    }
    function heightPercent(p) {
        return y + h * p;
    }
    function drawLineBox(g, routeInfo, x, y, h, d) {
        let routeName = routeInfo.routeName;
        let routeColor = routeInfo.routeColor;
        let textWidth = 0;
        if (isNumLine(routeName)) {
            textWidth += getUnifiedStringWidth(g, nonCjkFont, getCJKLineName(getMatching(routeName, true)), h * 0.9);
            textWidth += getDLStringWidth(g, cjkFont, nonCjkFont, "号线|" + getMatching(routeName, false), h * 0.85);
        } else {
            textWidth = getDLStringWidth(g, cjkFont, nonCjkFont, routeName, h * 0.85);
        }
        let finalWdith = textWidth + h * 0.5;
        let currentX = x + (d == 2 ? -finalWdith : d == 1 ? finalWdith * -0.5 : 0);
        g.setColor(routeColor);
        g.fillRoundRect(currentX, y, finalWdith, h, h * 0.25, h * 0.25);
        currentX += h * 0.25;
        g.setColor(isLightColor(routeColor) ? Color.BLACK : Color.WHITE);
        if (isNumLine(routeName)) {
            currentX += drawStrUnified(g, nonCjkFont, getCJKLineName(getMatching(routeName, true)), currentX, y + h * 0.9, h * 0.8, 0);
            currentX += drawStrDoubleLang(g, cjkFont, nonCjkFont, "号线|" + getMatching(routeName, false), currentX, y + h * 0.9, h * 0.75, 0, 0);
        } else {
            currentX = drawStrDoubleLang(g, cjkFont, nonCjkFont, routeName, currentX, y + h * 0.9, h * 0.75, 0, 1);
        }
        return finalWdith;
    }
}

function drawGradientLine(g2, x1, y1, x2, y2, color, lineWidth) {
    var transparentColor = new rgbaToColor(color.getRed(), color.getGreen(), color.getBlue(), 0);

    // 创建线性渐变
    var gradient = new LinearGradientPaint(
        x1,
        y1, // 渐变起点
        x2,
        y2, // 渐变终点
        [0.0, 1.0], // 渐变位置
        [transparentColor, color] // 颜色数组
    );

    // 保存原始画笔状态
    var originalPaint = g2.getPaint();
    var originalStroke = g2.getStroke();

    // 设置渐变画笔并绘制
    g2.setPaint(gradient);
    g2.setStroke(new BasicStroke(lineWidth));
    g2.drawLine(x1, y1, x2, y2);

    // 恢复原始画笔状态（可选）
    g2.setPaint(originalPaint);
    g2.setStroke(originalStroke);
}
function padZero(num) {
    return num < 10 ? "0" + num : num;
}
function getWorldTime() {
    var totalTicks = MinecraftClient.worldDayTime();
    var hours = (parseInt(totalTicks / 1000) + 6) % 24;
    var minutes = parseInt((totalTicks % 1000) / 16.67);

    return {
        h: hours < 10 ? "0" + hours : String(hours),
        m: minutes < 10 ? "0" + minutes : String(minutes)
    };
}
