include(Resources.id("mtrsteamloco:scripts/display_helper.js"));
importPackage(java.awt);
importPackage(java.awt.geom);

function assyukuDraw(g, text, textSize, drawPos, targetWidth, font, textColor, offsetX) {
    let fm = g.getFontMetrics(font.deriveFont(Font.PLAIN, textSize));

    if (fm.stringWidth(text) > targetWidth) {
        let nextStaScale = targetWidth / fm.stringWidth(text);
        // ★スケール適用フォント
        g.setFont(font.deriveFont(AffineTransform.getScaleInstance(nextStaScale, 1.0)).deriveFont(Font.PLAIN, textSize));
        // ★スケール後の実際の幅で中央揃え！
        let scaledWidth = fm.stringWidth(text) * nextStaScale;
        let startX = offsetX + ((targetWidth - scaledWidth) / 2);
        g.setColor(textColor);
        g.drawString(text, startX, drawPos);
    } else {
        // ★スケール不要時も中央揃え
        g.setFont(font.deriveFont(Font.PLAIN, textSize));
        g.setColor(textColor);
        let currentWidth = fm.stringWidth(text);
        let startX = offsetX + ((targetWidth - currentWidth) / 2);
        g.drawString(text, startX, drawPos);
    }
}

function assyukuDrawNotCenter(g, text, textSize, drawPos, targetWidth, font, textColor, offsetX) {
    let originalFont = font.deriveFont(Font.PLAIN, textSize);
    let fm = g.getFontMetrics(originalFont);

    if (fm.stringWidth(text) > targetWidth) {
        let scale = targetWidth / fm.stringWidth(text);
        let scaledFont = font.deriveFont(AffineTransform.getScaleInstance(scale, 1.0))
            .deriveFont(Font.PLAIN, textSize);
        g.setFont(scaledFont);
        g.setFont(scaledFont);  // ★2回セット
        g.setColor(textColor);
        g.drawString(text, offsetX, drawPos);
    } else {
        g.setFont(originalFont);
        g.setColor(textColor);
        g.drawString(text, offsetX, drawPos);
    }
}

function assyukuDrawFade(g, text, textSize, drawPos, targetWidth, font, textColor, offsetX, scaleY, isFadeIn) {
    let baseFont = font.deriveFont(Font.PLAIN, textSize);
    let fm = g.getFontMetrics(baseFont);
    let ot = g.getTransform();

    scaleY = Math.max(0.001, scaleY);

    let translateY, drawY;
    if (isFadeIn) {
        translateY = drawPos - textSize;
        drawY = textSize;
    } else {
        translateY = drawPos;
        drawY = 0;
    }

    g.translate(offsetX + targetWidth / 2, translateY);
    g.scale(1.0, scaleY);

    let originalWidth = fm.stringWidth(text);
    if (originalWidth > targetWidth) {
        let textScale = targetWidth / originalWidth;
        g.setFont(font.deriveFont(AffineTransform.getScaleInstance(textScale, 1.0)).deriveFont(Font.PLAIN, textSize));
        let scaledWidth = originalWidth * textScale;
        g.setColor(textColor);
        g.drawString(text, -(scaledWidth / 2), drawY);
    } else {
        g.setFont(baseFont);
        g.setColor(textColor);
        g.drawString(text, -(originalWidth / 2), drawY);
    }
    g.setTransform(ot);
}


function getRouteTypeColor(routeTypeJpn) {
    if (routeTypeJpn == "普通" || routeTypeJpn == "各停") {
        return Color.lightGray;
    } else if (routeTypeJpn == "各駅停車") {
        return Color.cyan;
    } else if (routeTypeJpn == "快速" || routeTypeJpn == "特急") {
        return Color.red;
    } else if (routeTypeJpn == "急行") {
        return Color.red;
    } else if (routeTypeJpn == "準急") {
        return Color.green;
    } else if (routeTypeJpn == "通勤快速") {
        return Color.orange;
    } else if (routeTypeJpn == "区間快速") {
        return new Color(0.082, 0.678, 1.0);
    } else if (routeTypeJpn == "通勤急行") {
        return Color.yellow;
    } else if (routeTypeJpn == "快速急行") {
        return new Color(0.5, 0.0, 1.0);
    } else {
        return Color.lightGray;
    }
}

function lcdmain(g, train, state, carNumber) {
    let next = train.getThisRoutePlatformsNextIndex();
    let platformList = train.getThisRoutePlatforms();
    let nextSta = platformList.get(next).station.name;
    let nextStaDistance = platformList[next].distance;
    let railProgress = train.getRailProgress(0);
    let nextStaJpn = TextUtil.getCjkParts(nextSta);
    let nextStaEng = TextUtil.getNonCjkParts(nextSta);
    let finalSta = platformList[next].destinationName;
    let finalStaJpn = TextUtil.getCjkParts(finalSta);
    let finalStaEng = TextUtil.getNonCjkParts(finalSta);
    let route = platformList[next].route.name;
    let routeExtra = TextUtil.getExtraParts(route);
    let routeType = platformList[next].route.lightRailRouteNumber;
    let routeTypeJpn = TextUtil.getCjkParts(routeType);
    let routeTypeEng = TextUtil.getNonCjkParts(routeType);
    let routeColor = new Color(platformList[next].route.color);
    let nextStaExtra = TextUtil.getExtraParts(nextSta);
    let lcdWhite = new Color(0.902, 0.902, 0.902);
    let routeTypeColor = getRouteTypeColor(routeTypeJpn);

    if (train.isOnRoute()) {
        g.setPaint(new LinearGradientPaint(
            0, //始点x座標
            0, //始点y座標
            0, //終点x座標
            50, //終点y座標
            [0, 0.4, 1], //適用色の座標割合
            [lcdWhite, Color.lightGray, lcdWhite] //色配列
        ));
        //上の背景、路線色の帯
        g.fillRect(0, 0, 600, 62.5);
        g.setColor(lcdWhite);
        g.fillRect(0, 50, 600, 100);
        g.setColor(routeColor);
        g.fillRect(0, 142.5, 600, 7.5);

        //種別背景
        g.setPaint(new LinearGradientPaint(
            10, //始点x座標
            5, //始点y座標
            10, //終点x座標
            45, //終点y座標
            [0, 0.5, 1], //適用色の座標割合
            [routeTypeColor, routeTypeColor.darker(), routeTypeColor] //色配列
        ));
        g.fillRoundRect(10, 5, 100, 40, 10, 10);


        //号車表示
        g.setPaint(new LinearGradientPaint(
            525, //始点x座標
            5, //始点y座標
            525, //終点x座標
            45, //終点y座標
            [0, 0.5, 1], //適用色の座標割合
            [Color.darkGray, Color.darkGray.darker(), Color.darkGray] //色配列
        ));
        g.fillRoundRect(525, 5, 40, 40, 10, 10);
        assyukuDraw(g, carNumber, 40, 40, 40, state.font, Color.white, 525);

        //ナンバリング表示
        if (nextStaExtra != "") {
            let parts = splitTrainCodeUpper(nextStaExtra);
            if (parts.prefix.length == 1) {
                g.setColor(routeColor);
                g.fillOval(120, 70, 60, 60);
                g.setColor(lcdWhite);
                g.fillOval(125, 75, 50, 50);
            } else {
                g.setColor(routeColor);
                g.fillRoundRect(120, 70, 60, 60, 10, 10);
                g.setColor(lcdWhite);
                g.fillRoundRect(125, 75, 50, 50, 10, 10);
            }

            assyukuDraw(g, parts.prefix, 25, 97.5, 50, state.font, Color.black, 125);
            assyukuDraw(g, parts.number, 25, 122.5, 50, state.font, Color.black, 125);
        }

        if (Date.now() % 10000 < 5000) {
            //*日本語
            //種別
            assyukuDraw(g, routeTypeJpn, 30, 37.5, 100, state.font, Color.white, 10);
            //(~線直通)行き先
            let destText;
            if (routeExtra.includes("直通")) {
                // "直通"部分 + finalStaJpn + "ゆき"
                destText = (routeExtra.split(" ").find(part => part.includes("直通")) || "") + " " + finalStaJpn + " ゆき";
            } else {
                destText = finalStaJpn + " ゆき";
            }
            assyukuDrawNotCenter(g, destText, 30, 35, 362.5, state.font, Color.darkGray, 112.5);


            //次はorまもなく
            if (train.doorValue() == 0) {
                if (platformList.size() - 1 != next || routeExtra.includes("直通")) {
                    if (nextStaDistance - railProgress < 750) {
                        assyukuDraw(g, "まもなく", 25, 125, 100, state.font, Color.black, 10);
                    } else {
                        assyukuDraw(g, "つぎは", 25, 125, 100, state.font, Color.black, 10);
                    }
                } else {
                    if (nextStaDistance - railProgress < 750) {
                        assyukuDraw(g, "まもなく終点", 25, 125, 100, state.font, Color.black, 10);
                    } else {
                        assyukuDraw(g, "つぎは終点", 25, 125, 100, state.font, Color.black, 10);
                    }
                }
            }


            if (Date.now() % 10000 < 4750 && Date.now() % 10000 > 250) {
                //次駅
                assyukuDraw(g, nextStaJpn, 62.5, 125, 400, state.font, Color.black, 200);
            }
            //"~号車"
            assyukuDraw(g, "号車", 20, 40, 35, state.font, Color.darkGray, 565);
        } else {
            //*英語
            //種別
            assyukuDraw(g, routeTypeEng, 30, 37.5, 100, state.font, Color.white, 10);
            //行き先
            let destText = "For " + finalStaEng;
            assyukuDrawNotCenter(g, destText, 30, 35, 362.5, state.font, Color.darkGray, 112.5);


            //次はorまもなく
            if (train.doorValue() == 0) {
                if (platformList.size() - 1 != next || routeExtra.includes("直通")) {
                    if (nextStaDistance - railProgress < 750) {
                        assyukuDraw(g, "Arriving at", 25, 125, 100, state.font, Color.black, 10);
                    } else {
                        assyukuDraw(g, "Next", 25, 125, 100, state.font, Color.black, 10);
                    }
                } else {
                    if (nextStaDistance - railProgress < 750) {
                        assyukuDraw(g, "Arriving at Final stop", 25, 125, 100, state.font, Color.black, 10);
                    } else {
                        assyukuDraw(g, "Next Final stop", 25, 125, 100, state.font, Color.black, 10);
                    }
                }
            }
            if (Date.now() % 10000 < 9750 && Date.now() % 10000 > 5250) {
                //次駅
                assyukuDraw(g, nextStaEng, 62.5, 125, 400, state.font, Color.black, 200);
            }
            //"Car No."
            assyukuDraw(g, "Car No.", 20, 20, 50, state.font, Color.darkGray, 475);
        }

        //次駅切り替え(三菱セサミクロ)
        let t = Date.now() % 10000;
        let fadeDuration = 500; // フェードアニメーションの時間 (ms)

        // 定位置Y座標
        let BASE_Y = 125;
        let TEXT_SIZE = 62.5;
        let TARGET_WIDTH = 400;
        let OFFSET_X = 200;

        if (t >= 4750 && t <= 4750 + fadeDuration * 2) { // 4750〜5750ms
            let progress = Math.min((t - 4750) / fadeDuration, 2.0);

            if (progress <= 1.0) {
                let fadeProgress = progress;
                assyukuDrawFade(g, nextStaJpn, TEXT_SIZE, BASE_Y, TARGET_WIDTH, state.font, Color.black, OFFSET_X, 1.0 - fadeProgress, false);
                assyukuDrawFade(g, nextStaEng, TEXT_SIZE, BASE_Y, TARGET_WIDTH, state.font, Color.black, OFFSET_X, fadeProgress, true);
            } else {
                assyukuDrawFade(g, nextStaEng, TEXT_SIZE, BASE_Y, TARGET_WIDTH, state.font, Color.black, OFFSET_X, 1.0, false);
            }
        }
        else if (t >= 9750 || t <= fadeDuration) { // 9750ms〜500ms
            let progress;
            if (t >= 9750) {
                progress = (t - 9750) / fadeDuration;
            } else {
                progress = 0.5 + t / fadeDuration;
            }
            progress = Math.min(progress, 2.0);

            if (progress <= 1.0) {
                let fadeProgress = progress;
                assyukuDrawFade(g, nextStaEng, TEXT_SIZE, BASE_Y, TARGET_WIDTH, state.font, Color.black, OFFSET_X, 1.0 - fadeProgress, false);
                assyukuDrawFade(g, nextStaJpn, TEXT_SIZE, BASE_Y, TARGET_WIDTH, state.font, Color.black, OFFSET_X, fadeProgress, true);
            } else {
                assyukuDrawFade(g, nextStaJpn, TEXT_SIZE, BASE_Y, TARGET_WIDTH, state.font, Color.black, OFFSET_X, 1.0, false);
            }
        }
    } else {
        g.setColor(lcdWhite);
        g.fillRect(0, 0, 600, 150);
    }
}

function splitTrainCodeUpper(code) {
    let match = code.match(/^([a-zA-Z]+)([0-9]+)$/);
    if (match) {
        return {
            prefix: match[1].toUpperCase(),  // TT01 → "TT"
            number: match[2]                 // "01"
        };
    }
    return { prefix: code.toUpperCase(), number: "" };
}

function lcdSideStatic(g, train, state, isRightSide) {
    let platformList = train.getAllPlatforms();
    let next = train.getAllPlatformsNextIndex();
    let doorOpen = train.doorValue() > 0;

    if (state.lastGeneratedNextIndex != next || state.lastGeneratedDoorOpen != doorOpen || !state.lastGeneratedPathInfo) {
        let gBuf = state.routeMapGraphics;

        gBuf.setColor(new Color(0.902, 0.902, 0.902));
        gBuf.fillRect(0, 150, 600, 300);

        if (platformList.size() == 0 || !train.isOnRoute()) {
            state.lastGeneratedNextIndex = next;
            state.lastGeneratedDoorOpen = doorOpen;
            g.drawImage(state.routeMapImage, 0, 0, null);
            return;
        }

        let path = train.path();
        let nextPlatform = platformList.get(next);
        let plat = nextPlatform.platform;
        let railProgress = train.getRailProgress(0);
        let nextStaDistance = platformList[next].distance;
        let showRouteMap = true;

        let allStations = [];
        for (let i = 0; i < path.size(); i++) {
            let pd = path[i];
            let rail = pd.rail;
            if (rail.railType == Packages.mtr.data.RailType.PLATFORM) {
                let p0 = new Vector3f(rail.getPosition(0));
                allStations.push(MinecraftClient.getStationAt(p0));
            }
        }

        let restStations = [];
        for (let i = train.getRailIndex(railProgress, true); i < path.size(); i++) {
            let pd = path[i];
            let rail = pd.rail;
            if (rail.railType == Packages.mtr.data.RailType.PLATFORM) {
                let p0 = new Vector3f(rail.getPosition(0));
                restStations.push(MinecraftClient.getStationAt(p0));
            }
        }

        let pathInfo = calcOperationPath(train, platformList, next, doorOpen, allStations, restStations);

        if (pathInfo) {
            let [displayPathStations, segmentStartIndex, segmentEndIndex, currentRestIdxAbsolute, nextIndex, isPassArray] = pathInfo;

            function tx(x) { return isRightSide ? 600 - x : x; }

            if (doorOpen) {
                for (let i = train.getRailIndex(railProgress, true); i < path.size(); i++) {
                    let pd = path[i];
                    let rail = pd.rail;
                    let p0 = new Vector3f(rail.getPosition(0));
                    let p1 = new Vector3f(rail.getPosition(rail.getLength() + 1));

                    if (plat.containsPos(p0.toBlockPos()) && plat.containsPos(p1.toBlockPos())) {
                        let [doorLeftOpen, doorRightOpen] = MinecraftClient.canOpenDoorsAt(p0, p1);
                        let thisSideOpen = isRightSide ? doorLeftOpen : doorRightOpen;
                        showRouteMap = !thisSideOpen;
                        break;
                    }
                }
            } else if (nextStaDistance - railProgress < 750) {
                showRouteMap = false;
            }

            if (showRouteMap) {
                gBuf.setColor(new Color(0.902, 0.902, 0.902));
                gBuf.fillRect(0, 150, 600, 300);

                let stationCenters = drawSegmentsBand(gBuf, platformList, displayPathStations, segmentStartIndex, segmentEndIndex, currentRestIdxAbsolute, nextIndex, doorOpen, isRightSide, tx, isPassArray);
                drawStationBoxes(gBuf, platformList, next, segmentStartIndex, segmentEndIndex, currentRestIdxAbsolute, stationCenters, state.font, isRightSide, isPassArray, doorOpen, displayPathStations);  // ★doorOpen追加
                drawTerminalTriangle(gBuf, platformList, displayPathStations, segmentStartIndex, segmentEndIndex, isRightSide, tx);
                drawStationNames(gBuf, displayPathStations, segmentStartIndex, segmentEndIndex, stationCenters, state.font, isRightSide, isPassArray);
                state.lastStationCenters[isRightSide ? 'right' : 'left'] = stationCenters;
            } else {
                state.lastStationCenters[isRightSide ? 'right' : 'left'] = [];
            }
        } else {
            gBuf.setColor(new Color(0.902, 0.902, 0.902));
            gBuf.fillRect(0, 150, 600, 300);
        }

        state.lastPathInfo = pathInfo;
        state.lastGeneratedNextIndex = next;
        state.lastGeneratedDoorOpen = doorOpen;
    }
    g.drawImage(state.routeMapImage, 0, 0, null);
}

function lcdSideDynamic(g, train, state, isRightSide) {
    let stationCenters = state.lastStationCenters[isRightSide ? 'right' : 'left'];
    if (!state.lastPathInfo || !stationCenters || stationCenters.length == 0) return;

    let segmentStartIndex = state.lastPathInfo[1];
    let nextIndex = state.lastPathInfo[4];
    let doorOpen = train.doorValue() > 0;

    let railProgress = train.getRailProgress(0);
    let platformList = train.getAllPlatforms();
    let next = train.getAllPlatformsNextIndex();
    let nextStaDistance = platformList.get(next).distance;

    if (doorOpen) {
        let path = train.path();
        let nextPlatform = platformList.get(train.getAllPlatformsNextIndex());
        let plat = nextPlatform.platform;
        for (let i = train.getRailIndex(railProgress, true); i < path.size(); i++) {
            let pd = path[i];
            let rail = pd.rail;

            let p0 = new Vector3f(rail.getPosition(0)), p1 = new Vector3f(rail.getPosition(rail.getLength() + 1));

            if (plat.containsPos(p0.toBlockPos()) && plat.containsPos(p1.toBlockPos())) {
                let [doorLeftOpen, doorRightOpen] = MinecraftClient.canOpenDoorsAt(p0, p1);

                let thisSideOpen = isRightSide ? doorLeftOpen : doorRightOpen;
                if (!thisSideOpen) {
                    drawDirectionArrow(g, stationCenters, segmentStartIndex, nextIndex, doorOpen, isRightSide);
                }
                break;
            }
        }
    } else {
        if (nextStaDistance - railProgress < 750) {
            let path = train.path();
            let nextPlatform = platformList.get(train.getAllPlatformsNextIndex());
            if (nextPlatform) {
                let plat = nextPlatform.platform;
                for (let i = train.getRailIndex(railProgress, true); i < path.size(); i++) {
                    let pd = path[i];
                    let rail = pd.rail;
                    let p0 = new Vector3f(rail.getPosition(0));
                    let p1 = new Vector3f(rail.getPosition(rail.getLength() + 1));

                    if (plat.containsPos(p0.toBlockPos()) && plat.containsPos(p1.toBlockPos())) {
                        let [doorLeftOpen, doorRightOpen] = MinecraftClient.canOpenDoorsAt(p0, p1);
                        let thisSideOpen = isRightSide ? doorLeftOpen : doorRightOpen;

                        let message = thisSideOpen
                            ? "こちら側のドアが開きます / Doors on this side will open."
                            : "反対側のドアが開きます / Doors on the opposite side will open.";

                        g.setColor(new Color(0.902, 0.902, 0.902));
                        g.fillRect(0, 150, 600, 300);
                        assyukuDraw(g, message, 25, 175, 600, state.font, Color.blue, 0);
                        g.setColor(Color.darkGray);
                        g.fillRect(0, 180, 600, 2.5);
                        break;
                    }
                }
            }
            return;
        } else {
            drawDirectionArrow(g, stationCenters, segmentStartIndex, nextIndex, doorOpen, isRightSide);
        }
    }
}

function calcOperationPath(train, platformList, next, doorOpen, allStations, restStations) {
    let totalStations = platformList.size();

    // 1. 現在位置特定（全経路内絶対位置）
    let railProgress = train.getRailProgress(0);
    let path = train.path();
    let currentRestIdxAbsolute = 0;
    let currentRailIdx = train.getRailIndex(railProgress, true);
    for (let i = currentRailIdx; i < path.size(); i++) {
        let pd = path[i];
        if (pd.rail.railType == Packages.mtr.data.RailType.PLATFORM) {
            let station = MinecraftClient.getStationAt(new Vector3f(pd.rail.getPosition(0)));
            for (let j = 0; j < restStations.length; j++) {
                if (TextUtil.getCjkParts(restStations[j].name) == TextUtil.getCjkParts(station.name)) {
                    currentRestIdxAbsolute = j + allStations.length - restStations.length;  // ★完璧！
                    //print("現在位置特定: 駅[" + restStations[j].name + "] index=" + currentRestIdxAbsolute);
                    break;
                }
            }
            break;
        }
    }

    // 2. 終点特定：現在位置から前方のみ探索
    let destinationName = TextUtil.getCjkParts(platformList.get(next).destinationName);
    let destinationIdxAbsolute = -1;
    for (let i = currentRestIdxAbsolute; i < allStations.length; i++) {
        if (TextUtil.getCjkParts(allStations[i].name) == destinationName) {
            destinationIdxAbsolute = i;
            //print("終点特定: [" + destinationName + "] index=" + i);
            break;
        }
    }
    if (destinationIdxAbsolute == -1) {
        destinationIdxAbsolute = allStations.length - 1;
        //print("⚠️終点[" + destinationName + "]前方未検出→経路終端使用");
    }

    let routeStartIdx = 0;
    for (let i = next; i > 0; i--) {
        let destName = TextUtil.getCjkParts(platformList.get(i).destinationName);  // ★i番目の終点！
        //print("比較: platform[" + i + "] dest=[" + destName + "]" + " vs prev dest=[" + TextUtil.getCjkParts(platformList.get(i - 1).destinationName) + "]");
        if (destName != TextUtil.getCjkParts(platformList.get(i - 1).destinationName)) {  // ★前駅と比較
            routeStartIdx = i - 1;  // ★platformList index（後でallStations変換）
            //print("🔍区間始点: platform[" + (i - 1) + "] dest=[" + destName + "]");
            break;
        }
    }

    // ★platform→allStations変換
    for (let j = currentRestIdxAbsolute; j >= 0; j--) {
        if (TextUtil.getCjkParts(allStations[j].name) == TextUtil.getCjkParts(platformList.get(routeStartIdx).station.name)) {
            routeStartIdx = j;
            //print("🎯路線始点: allStations[" + routeStartIdx + "]");
            break;
        }
    }

    let totalRouteStations = destinationIdxAbsolute - routeStartIdx + 1;
    let totalVisibleStations = 8;

    let segmentStartIdx, segmentEndIdx;

    if (totalRouteStations <= totalVisibleStations) {
        segmentStartIdx = routeStartIdx;  // ★復路始点から！
        segmentEndIdx = destinationIdxAbsolute;
        //print("【短距離全表示】[" + segmentStartIdx + "～" + segmentEndIdx + "]");
    } else {
        if (doorOpen) {
            let pastStations = 1;
            segmentStartIdx = Math.max(routeStartIdx, currentRestIdxAbsolute - pastStations);
            segmentEndIdx = Math.min(destinationIdxAbsolute, currentRestIdxAbsolute + totalVisibleStations - 1 - pastStations);
            //print("【ドア開】[" + segmentStartIdx + "～" + segmentEndIdx + "]");
        } else {
            // 走行中：現在駅中心（過去1＋現在＋先6）
            let pastStations = 1;
            segmentStartIdx = Math.max(0, currentRestIdxAbsolute - pastStations);
            segmentEndIdx = Math.min(destinationIdxAbsolute, segmentStartIdx + totalVisibleStations - 1);

            // 終点接近：終点固定
            let stationsToEnd = destinationIdxAbsolute - currentRestIdxAbsolute;
            if (stationsToEnd <= totalVisibleStations - 1) {
                segmentStartIdx = Math.max(0, destinationIdxAbsolute - totalVisibleStations + 1);
                segmentEndIdx = destinationIdxAbsolute;
                //print("【終点固定】[" + segmentStartIdx + "～" + segmentEndIdx + "]");
            } else {
                //print("【走行スライド】[" + segmentStartIdx + "～" + segmentEndIdx + "]");
            }
        }
    }

    // 4. 表示駅リスト作成
    let displayPathStations = allStations.slice(segmentStartIdx, segmentEndIdx + 1);

    // 5. stopStationNames
    let stopStationNames = {};
    for (let i = 0; i < totalStations; i++) {
        stopStationNames[TextUtil.getCjkParts(platformList.get(i).station.name)] = true;
    }

    // 6. isPassArray
    let isPassArray = [];
    for (let i = 0; i < displayPathStations.length; i++) {
        let stationName = TextUtil.getCjkParts(displayPathStations[i].name);
        isPassArray.push(!stopStationNames[stationName]);
    }

    // 7. 相対位置計算
    let currentRestIdxRelative = currentRestIdxAbsolute - segmentStartIdx;
    let nextRestIdx = 0;
    let nextStationName = TextUtil.getCjkParts(platformList.get(next).station.name);
    for (let i = 0; i < displayPathStations.length; i++) {
        if (TextUtil.getCjkParts(displayPathStations[i].name) == nextStationName) {
            nextRestIdx = i;
            break;
        }
    }

    //print("全長=" + totalRouteStations + ", 表示=[" + segmentStartIdx + "～" + segmentEndIdx + "], 現在相対=" + currentRestIdxRelative);
    return [displayPathStations, 0, displayPathStations.length - 1, currentRestIdxRelative, nextRestIdx, isPassArray];
}

function drawSegmentsBand(g, platformList, displayPathStations, segmentStartIndex, segmentEndIndex, currentRestIdxAbsolute, nextIndex, doorOpen, isRightSide, tx, isPassArray) {
    let stationPerSegment = 2;
    let segmentWidth = 35;
    let rightEnd = 560;

    let actualMaxStations = segmentEndIndex - segmentStartIndex + 1;
    let totalSegmentsToDraw = actualMaxStations * stationPerSegment;
    let firstSegmentXLogical = isRightSide
        ? rightEnd - (totalSegmentsToDraw * segmentWidth) + 35
        : rightEnd - (totalSegmentsToDraw * segmentWidth);

    let stationCenters = [];

    for (let i = 0; i < actualMaxStations; i++) {
        let stationIdx = segmentStartIndex + i;
        let isPassed = stationIdx < currentRestIdxAbsolute;
        //print("駅[" + stationIdx + "]: isPassed=" + isPassed + ", doorOpen=" + doorOpen);

        // 駅固有色（現路線色）
        let currentStationColor = isPassed ? Color.gray :
            getNearestRouteColor(platformList, displayPathStations, stationIdx, isPassArray, i, segmentStartIndex);

        // ★次停車駅色取得
        let nextStopColor = currentStationColor;
        for (let k = i + 1; k < actualMaxStations; k++) {
            if (!isPassArray[k]) {
                nextStopColor = getNearestRouteColor(platformList, displayPathStations, segmentStartIndex + k, isPassArray, k, segmentStartIndex);
                //print("→次停車駅[" + displayPathStations[k].name + "]色取得");
                break;
            }
        }

        for (let j = 0; j < stationPerSegment; j++) {
            let seg = i * stationPerSegment + j;
            let logicalX = firstSegmentXLogical + seg * segmentWidth;
            let x = tx(logicalX);

            let segmentRouteColor;

            if (isPassed) {
                segmentRouteColor = Color.gray;
            }
            // ★ドア開現在駅セグ0灰色（最優先）
            else if (doorOpen && stationIdx == currentRestIdxAbsolute && j == 0) {
                segmentRouteColor = Color.gray;
                //print("駅[" + stationIdx + "][セグ0]ドア開灰色");
            }
            // ★セグ0：現駅路線色（境界点）
            else if (j == 0) {
                segmentRouteColor = currentStationColor;
                //print("駅[" + stationIdx + "][セグ0]現路線色");
            }
            // ★セグ1：次停車駅色（境界移行）
            else {
                segmentRouteColor = nextStopColor;
                //print("駅[" + stationIdx + "][セグ1]次停車駅色[" + nextStopColor + "]");
            }

            // 描画
            g.setColor(segmentRouteColor);
            g.fillRect(x, 300, segmentWidth, 20);
            g.setPaint(new LinearGradientPaint(x, 320, x, 340, [0, 1], [segmentRouteColor.darker(), segmentRouteColor]));
            g.fillRect(x, 320, segmentWidth, 20);

            if (j == 0) {
                stationCenters[i] = isRightSide ? x : x + segmentWidth;
            }
        }
    }
    return stationCenters;
}

function getNearestRouteColor(platformList, displayPathStations, stationIdx, isPassArray, stationOffset, segmentStartIndex) {
    // ★新実装：この駅の次停車駅を直接取得
    let nextStopStationIdx = -1;
    for (let i = stationOffset; i < isPassArray.length; i++) {
        if (!isPassArray[i]) {
            nextStopStationIdx = segmentStartIndex + i;
            break;
        }
    }

    if (nextStopStationIdx != -1) {
        let nextStopStationName = TextUtil.getCjkParts(displayPathStations[nextStopStationIdx - segmentStartIndex].name);
        //print("→次停車駅発見！[" + nextStopStationName + "]色先取り");

        // 次停車駅の路線色取得
        for (let k = 0; k < platformList.size(); k++) {
            if (TextUtil.getCjkParts(platformList.get(k).station.name) == nextStopStationName) {
                return new Color(platformList.get(k).route.color);
            }
        }
    }

    // フォールバック：従来の前方→後方探索
    //print("通過駅→直近停車駅探索開始(stationIdx=" + stationIdx + ")");
    for (let searchIdx = stationIdx; searchIdx < displayPathStations.length; searchIdx++) {
        let searchStationName = TextUtil.getCjkParts(displayPathStations[searchIdx].name);
        for (let k = 0; k < platformList.size(); k++) {
            if (TextUtil.getCjkParts(platformList.get(k).station.name) == searchStationName) {
                //print("→前方停車駅発見！駅[" + searchIdx + "][" + searchStationName + "]");
                return new Color(platformList.get(k).route.color);
            }
        }
    }
    for (let searchIdx = stationIdx - 1; searchIdx >= 0; searchIdx--) {
        let searchStationName = TextUtil.getCjkParts(displayPathStations[searchIdx].name);
        for (let k = 0; k < platformList.size(); k++) {
            if (TextUtil.getCjkParts(platformList.get(k).station.name) == searchStationName) {
                //print("→後方停車駅発見！駅[" + searchIdx + "][" + searchStationName + "]");
                return new Color(platformList.get(k).route.color);
            }
        }
    }

    let fallbackColor = platformList.size() > 0 ? new Color(platformList.get(0).route.color) : new Color(0.5, 0.5, 0.5);
    //print("→最終フォールバック");
    return fallbackColor;
}

function drawStationBoxes(g, platformList, nextIndex, segmentStartIndex, segmentEndIndex, currentRestIdxAbsolute, stationCenters, font, isRightSide, isPassArray, doorOpen, displayPathStations) {  // ★doorOpen追加
    let actualMaxStations = stationCenters.length;

    for (let i = 0; i < actualMaxStations; i++) {
        let stationIdx = segmentStartIndex + i;
        if (stationIdx > segmentEndIndex || stationCenters[i] == undefined) break;

        let pathOffset = i;
        let isPass = isPassArray[pathOffset];
        let cx = stationCenters[i];

        // ★状態分岐（変数定義修正）
        let isPassed, boxColor;
        if (doorOpen) {
            // ドア開：現在駅のみ薄灰色、それ以外白
            isPassed = stationIdx <= currentRestIdxAbsolute;
            boxColor = isPassed ? Color.lightGray : Color.white;
        } else {
            // 走行中：現在位置より前が薄灰色
            isPassed = stationIdx < currentRestIdxAbsolute;
            boxColor = isPassed ? Color.lightGray : Color.white;
        }

        if (isPass) {
            // 通過駅：斜めボックス（既存コードそのまま）
            let topY = 305;
            let bottomY = 335;
            if (isRightSide) {
                g.setColor(boxColor);
                g.fillPolygon([cx + 10, cx + 2.5, cx - 10, cx - 2.5], [topY, topY, topY + 15, topY + 15], 4);
                g.setPaint(new LinearGradientPaint(cx - 17.5, 320, cx - 17.5, 340, [0, 1], [boxColor.darker(), boxColor]));
                g.fillPolygon([cx - 10, cx + 2.5, cx + 10, cx - 2.5], [topY + 15, bottomY, bottomY, topY + 15], 4);
            } else {
                g.setColor(boxColor);
                g.fillPolygon([cx - 10, cx - 2.5, cx + 10, cx + 2.5], [topY, topY, topY + 15, topY + 15], 4);
                g.setPaint(new LinearGradientPaint(cx - 17.5, 320, cx - 17.5, 340, [0, 1], [boxColor.darker(), boxColor]));
                g.fillPolygon([cx + 10, cx - 2.5, cx - 10, cx + 2.5], [topY + 15, bottomY, bottomY, topY + 15], 4);
            }
        } else {
            // 停車駅：四角ボックス
            g.setColor(boxColor);
            g.fillRect(cx - 17.5, 305, 35, 15);
            g.setPaint(new LinearGradientPaint(cx - 17.5, 320, cx - 17.5, 340, [0, 1], [boxColor.darker(), boxColor]));
            g.fillRect(cx - 17.5, 320, 35, 15);
        }

        // 所要時間（現在位置より後ろの停車駅のみ）
        if (!isPassed && !isPass) {
            // ★platformListで正しいインデックス特定
            let platformIdx = -1;
            let stationName = TextUtil.getCjkParts(displayPathStations[i].name);
            for (let k = 0; k < platformList.size(); k++) {
                if (TextUtil.getCjkParts(platformList.get(k).station.name) == stationName) {
                    platformIdx = k;
                    break;
                }
            }

            if (platformIdx != -1) {
                let nextStaDistance = platformList[platformIdx].distance;
                let prevPlatformIdx = doorOpen ? nextIndex : nextIndex - 1;
                let prevStaDistance = platformList[prevPlatformIdx].distance;
                let nextStaMeter = nextStaDistance - prevStaDistance;
                let timeText = Math.floor(nextStaMeter / 1000).toString();
                if (timeText == "0") timeText = "1";
                assyukuDraw(g, timeText, 25, 332.5, 35, font, Color.black, cx - 17.5);
            }
        }
    }
}

function drawDirectionArrow(g, stationCenters, segmentStartIndex, nextIndex, doorOpen, isRightSide) {
    if (stationCenters.length == 0) return;

    let nextOffset = Math.max(0, nextIndex - segmentStartIndex);
    let safeNext = Math.min(nextOffset, stationCenters.length - 1);

    let arrowX;
    if (doorOpen) {
        // ドア開：次駅中心
        arrowX = stationCenters[safeNext];
    } else {
        // ★走行中：現在駅と次駅の中間（進捗率考慮）
        let currentOffset = Math.max(0, Math.min(nextOffset - 1, stationCenters.length - 1));
        let progress = 0.5;  // 簡易：後で実装可能
        arrowX = stationCenters[currentOffset] * (1 - progress) + stationCenters[safeNext] * progress;
    }

    let arrowY = 320;
    let w = 20, h = 20;

    let lcdWhite = new Color(0.902, 0.902, 0.902);

    if (isRightSide) {
        g.setColor(lcdWhite);
        g.fillPolygon(
            [arrowX + w * 0.85, arrowX - w * 0.1, arrowX - w * 0.85,
            arrowX - w * 0.1, arrowX + w * 0.85, arrowX + w * 0.1],
            [arrowY - h, arrowY - h, arrowY,
            arrowY + h, arrowY + h, arrowY],
            6
        );

        g.setColor((Date.now() % 2000 < 1000) ? Color.red : Color.blue);
        g.fillPolygon(
            [arrowX + w * 0.75, arrowX, arrowX - w * 0.75,
                arrowX, arrowX + w * 0.75, arrowX],
            [arrowY - h, arrowY - h, arrowY,
            arrowY + h, arrowY + h, arrowY],
            6
        );
    } else {
        g.setColor(lcdWhite);
        g.fillPolygon(
            [arrowX - w * 0.85, arrowX + w * 0.1, arrowX + w * 0.85,
            arrowX + w * 0.1, arrowX - w * 0.85, arrowX - w * 0.1],
            [arrowY - h, arrowY - h, arrowY,
            arrowY + h, arrowY + h, arrowY],
            6
        );

        g.setColor((Date.now() % 2000 < 1000) ? Color.red : Color.blue);
        g.fillPolygon(
            [arrowX - w * 0.75, arrowX, arrowX + w * 0.75,
                arrowX, arrowX - w * 0.75, arrowX],
            [arrowY - h, arrowY - h, arrowY,
            arrowY + h, arrowY + h, arrowY],
            6
        );
    }
}

function drawTerminalTriangle(g, platformList, displayPathStations, segmentStartIndex, segmentEndIndex, isRightSide, tx) {
    // ★表示範囲内で最もindex大きい停車駅を探す
    let maxStopStationIdx = -1;
    let maxStopStationColor = new Color(0.5, 0.5, 0.5);

    //print("終端三角形：表示範囲[" + segmentStartIndex + "～" + segmentEndIndex + "]探索開始");

    // 後方から前方へ（最大index優先）
    for (let i = segmentEndIndex; i >= segmentStartIndex; i--) {
        let stationName = TextUtil.getCjkParts(displayPathStations[i].name);

        // platformListで停車駅確認
        for (let k = 0; k < platformList.size(); k++) {
            if (TextUtil.getCjkParts(platformList.get(k).station.name) == stationName) {
                maxStopStationIdx = i;
                maxStopStationColor = new Color(platformList.get(k).route.color);
                //print("→最大停車駅発見！駅[" + i + "][" + stationName + "] route.color使用");
                break;
            }
        }
        if (maxStopStationIdx != -1) break;
    }

    let baseLogicalX = 560;
    let tipLogicalX = 577.5;
    let baseX = tx(baseLogicalX);
    let tipX = tx(tipLogicalX);

    g.setColor(maxStopStationColor);
    g.fillPolygon([baseX, tipX, baseX], [300, 320, 320], 3);
    g.setPaint(new LinearGradientPaint(0, 320, 0, 340, [0, 1], [maxStopStationColor.darker(), maxStopStationColor]));
    g.fillPolygon([baseX, tipX, baseX], [320, 320, 340], 3);
}

function drawStationNames(g, displayPathStations, segmentStartIndex, segmentEndIndex, stationCenters, baseFont, isRightSide, isPassArray) {
    let actualMaxStations = stationCenters.length;

    for (let i = 0; i < actualMaxStations; i++) {
        let stationIdx = segmentStartIndex + i;
        if (stationIdx > segmentEndIndex || stationCenters[i] == undefined) break;

        let pathOffset = i;
        let isPass = isPassArray[pathOffset];
        let textColor = isPass ? Color.gray : Color.black;

        let stationName = displayPathStations[stationIdx].name;
        let stationNameJpn = TextUtil.getCjkParts(stationName);
        let stationNameEng = TextUtil.getNonCjkParts(stationName);
        let staXPosition = stationCenters[i];
        let staYPosition = 287.5;

        let originalTransform = g.getTransform();
        if (Date.now() % 20000 < 10000) {
            drawVerticalString(g, stationNameJpn, staXPosition, staYPosition,
                baseFont.deriveFont(Font.PLAIN, 25), textColor);
        } else {
            g.rotate(Math.PI / 180 * -60, staXPosition, staYPosition);
            let base = baseFont.deriveFont(Font.PLAIN, 25);
            g.setFont(base);
            let engWidth = g.getFontMetrics().stringWidth(stationNameEng);
            let targetWidth = 150;
            //右側表示の右端の駅名は見切れないように
            if (isRightSide && i == 0) targetWidth = 75;
            if (engWidth > targetWidth) {
                let scaleX = targetWidth / engWidth;
                let scaledFont = base.deriveFont(
                    AffineTransform.getScaleInstance(scaleX, 1)
                );
                g.setFont(scaledFont);
                g.setColor(textColor);
                g.drawString(stationNameEng, staXPosition, staYPosition);
            } else {
                g.setColor(textColor);
                g.drawString(stationNameEng, staXPosition, staYPosition);
            }
        }
        g.setTransform(originalTransform);
    }

    let x;
    if (Date.now() % 20000 < 10000) {
        x = 600 - g.getFontMetrics(baseFont.deriveFont(Font.PLAIN, 15)).stringWidth("多少時間は異なります。");
        g.setFont(baseFont.deriveFont(Font.PLAIN, 15));
        g.setColor(Color.black);
        g.drawString("運転状況により、", x, 432.5);
        g.drawString("多少時間は異なります。", x, 447.5);
    } else {
        x = 600 - g.getFontMetrics(baseFont.deriveFont(Font.PLAIN, 15)).stringWidth("Estimated time required.");
        g.setFont(baseFont.deriveFont(Font.PLAIN, 15));
        g.setColor(Color.black);
        g.drawString("Estimated time required.", x, 447.5);
    }

    if (isRightSide) {
        if (Date.now() % 20000 < 10000) {
            assyukuDraw(g, "(分)", 10, 340, 17.5, baseFont, Color.white, 40);
        } else {
            assyukuDraw(g, "(min)", 10, 340, 17.5, baseFont, Color.white, 40);
        }
    } else {
        if (Date.now() % 20000 < 10000) {
            assyukuDraw(g, "(分)", 10, 340, 17.5, baseFont, Color.white, 560 - 17.5);
        } else {
            assyukuDraw(g, "(min)", 10, 340, 17.5, baseFont, Color.white, 560 - 17.5);
        }
    }
}

function drawVerticalString(g, text, x, baseY, baseFont, textColor) {
    text = String(text);
    if (text.length == 2) {
        text = text.charAt(0) + "　" + text.charAt(1);
    }
    let baseSizeFont = baseFont.deriveFont(Font.PLAIN, 25);
    g.setFont(baseSizeFont);
    let fm = g.getFontMetrics(baseSizeFont);
    let lineHeight = fm.getAscent() * 1.1;
    let maxHeight = 137.5;
    let totalHeight = lineHeight * text.length;

    let scale = 1.0;
    if (totalHeight > maxHeight) {
        scale = maxHeight / totalHeight;
    }
    let scaledFont;
    if (scale < 1.0) {
        scaledFont = baseSizeFont.deriveFont(
            AffineTransform.getScaleInstance(1.0, scale)
        );
    } else {
        scaledFont = baseSizeFont;
    }
    g.setFont(scaledFont);
    let scaledFM = g.getFontMetrics(scaledFont);
    let scaledLineHeight = scaledFM.getAscent() * 1.1;
    let drawY = baseY + (scaledFM.getDescent() * 0.5);
    for (let i = text.length - 1; i >= 0; i--) {
        let ch = text.charAt(i);
        let drawCh = ch;
        if (ch == "ー" || ch == "-") {
            drawCh = "｜";
        }
        if (ch == "　") {
        } else {
            let charWidth = scaledFM.stringWidth(drawCh);
            g.setColor(textColor);
            g.drawString(drawCh, x - (charWidth / 2), drawY);
        }
        drawY -= scaledLineHeight;
    }
}
