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

// ============================================================
// ★ ikisaki用キャッシュ初期化（初回のみ）
// state.fontCache は lcd.js と共有（同じstateオブジェクト）
// ============================================================
function initIkisakiCache(state) {
    if (state.ikisakiCache) return;

    if (!state.fontCache) state.fontCache = {};
    let fc = state.fontCache;
    let f = state.font;
    // ikisaki で使う固定サイズをあらかじめ全部生成
    [7, 10, 12, 19, 20, 25, 32].forEach(function(s) {
        fc[s] = f.deriveFont(Font.PLAIN, s);
    });

    state.ikisakiCache = {
        // ★ 最重要: readBufferedImageを毎回呼ぶのをやめてキャッシュ
        ledImage:   Resources.readBufferedImage(Resources.id("mtr:scripts/images/led_5_1.png")),
        backGround: new Color(0.2, 0.2, 0.2),
        purple:     new Color(0.537, 0.0, 1.0),
    };
}

// ============================================================
// assyukuDraw（小さいバッファ対応）
// FC不要版：font.deriveFont()は毎回実行
// ============================================================
function assyukuDraw(g, text, textSize, drawPos, targetWidth, font, textColor, offsetX) {
    let f = font.deriveFont(Font.PLAIN, textSize);
    let fm = g.getFontMetrics(f);
    let tw = fm.stringWidth(text);
    if (tw > targetWidth) {
        let scale = targetWidth / tw;
        g.setFont(font.deriveFont(AffineTransform.getScaleInstance(scale, 1.0)).deriveFont(Font.PLAIN, textSize));
        g.setColor(textColor);
        g.drawString(text, offsetX + (targetWidth - tw * scale) / 2, drawPos);
    } else {
        g.setFont(f);
        g.setColor(textColor);
        g.drawString(text, offsetX + (targetWidth - tw) / 2, drawPos);
    }
}

// ============================================================
// assyukuDrawOutline（FC不要版）
// ============================================================
function assyukuDrawOutline(g, text, textSize, drawPos, targetWidth, font, textColor, offsetX, outlineColor) {
    let f = font.deriveFont(Font.PLAIN, textSize);
    let fm = g.getFontMetrics(f);
    let textW = fm.stringWidth(text);
    let drawFont = f;
    if (textW > targetWidth) {
        let scale = targetWidth / textW;
        drawFont = font.deriveFont(AffineTransform.getScaleInstance(scale, 1.0)).deriveFont(Font.PLAIN, textSize);
        textW = textW * scale;
    }
    g.setFont(drawFont);
    let startX = offsetX + (targetWidth - textW) / 2;
    if (outlineColor != null) {
        g.setColor(outlineColor);
        for (let ox = -1; ox <= 1; ox++) {
            for (let oy = -1; oy <= 1; oy++) {
                if (ox == 0 && oy == 0) continue;
                g.drawString(text, startX + ox, drawPos + oy);
            }
        }
    }
    g.setColor(textColor);
    g.drawString(text, startX, drawPos);
}

// ============================================================
// pickNumbering / splitTrainCodeUpper
// ============================================================
function pickNumbering(finalStaExtra, prevStaExtra) {
    if (!finalStaExtra.includes("_")) return finalStaExtra;
    let candidates = finalStaExtra.split("_");
    let currentPrefixes = candidates.map(c => splitTrainCodeUpper(c).prefix);
    let prev = prevStaExtra;
    while (prev != null && prev != "") {
        let prevCandidates = prev.includes("_") ? prev.split("_") : [prev];
        for (let i = 0; i < prevCandidates.length; i++) {
            let prevPrefix = splitTrainCodeUpper(prevCandidates[i]).prefix;
            for (let j = 0; j < currentPrefixes.length; j++) {
                if (currentPrefixes[j] == prevPrefix) return candidates[j];
            }
        }
        break;
    }
    return candidates[0];
}

function splitTrainCodeUpper(text) {
    let match = text.match(/([A-Za-z]+)(\d+)/);
    if (match) return { prefix: match[1].toUpperCase(), number: match[2] };
    return { prefix: text, number: "" };
}

// ============================================================
// drawRouteType（newシグネチャ：FCなし版）
// ============================================================
function drawRouteType(g, routeTypeJpn, routeExtra, finalStaJpn, finalStaEng, routeColor, width, height, font, finalStaExtra, numberingColor, prevStaExtra, cache) {
    let rectW = width / 10 * 3;
    let backGround = cache.backGround;
    let purple = cache.purple;

    if (routeTypeJpn == "快速") {
        let c = routeExtra.includes("ぴぬ鉄道") ? Color.blue : Color.red;
        g.setColor(c); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "快 速", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Rapid", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "快速急行") {
        g.setColor(purple); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "快速急行", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Rapid Exp.", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "急行") {
        g.setColor(Color.red); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "急 行", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Express", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "S急行") {
        g.setColor(Color.red); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "急行", 19, 18, rectW / 2, font, Color.white, rectW / 2, backGround);
        assyukuDrawOutline(g, "Express", 7, 29, rectW / 3 * 2, font, Color.white, rectW / 3, backGround);
        g.drawImage(s_liner_img, 1, 10.5, 20, 15, null);
    } else if (routeTypeJpn == "準急") {
        let c = routeExtra.includes("京阪") ? Color.blue : Color.green;
        g.setColor(c); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "準 急", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Semi Exp.", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "各駅停車") {
        g.setColor(Color.cyan); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "各駅停車", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Local", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "普通") {
        g.setColor(Color.lightGray); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "普 通", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Local", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "各停") {
        g.setColor(Color.lightGray); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "各 停", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Local", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "通勤急行") {
        g.setColor(Color.MAGENTA); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "通勤急行", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Commuter Exp.", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "通勤準急") {
        g.setColor(Color.blue); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "通勤準急", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Com. Semi Exp.", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "区間快速") {
        g.setColor(Color.blue); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "区 快", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Semi Rapid", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "新快速") {
        g.setColor(Color.green); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "新 快", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "New Rapid", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "通勤快速") {
        g.setColor(Color.orange); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "通 快", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Com. Rapid", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "通勤特急") {
        g.setColor(Color.orange); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "通勤特急", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Com. Exp.", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "特急") {
        g.setColor(Color.orange); g.fillRect(0, 0, rectW, height);
        assyukuDrawOutline(g, "特 急", 19, 18, rectW, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "Limited Exp.", 7, 29, rectW, font, Color.white, 0, backGround);
    } else if (routeTypeJpn == "団体専用") {
        if (finalStaJpn == "たびじ") {
            assyukuDrawOutline(g, "たびじ", 20, 20, rectW, font, Color.white, 0, backGround);
        } else {
            assyukuDrawOutline(g, "たびじ", 19, 18, rectW, font, Color.white, 0, backGround);
            assyukuDrawOutline(g, "Group", 7, 29, rectW, font, Color.white, 0, backGround);
        }
    } else if (routeTypeJpn == "快速特急洛楽") {
        g.setColor(Color.magenta); g.fillRect(0, 0, rectW, height);
        g.setColor(Color.white); g.fillRect(30, 1, 18, height - 2);
        assyukuDrawOutline(g, "快速特急", 19, 18, 30, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "洛楽", 19, 18, 18, font, Color.magenta, 30, backGround);
        assyukuDrawOutline(g, "Rapid Limited Exp.", 7, 29, 30, font, Color.white, 0, backGround);
        assyukuDrawOutline(g, "RAKURAKU", 7, 29, 18, font, Color.magenta, 30, backGround);
    } else {
        g.setColor(routeColor);
        g.fillRect(0, 0, rectW, height);
    }

    // ナンバリング
    if (finalStaExtra != "") {
        let selectedExtra = pickNumbering(finalStaExtra, prevStaExtra != null ? prevStaExtra : "");
        let parts = splitTrainCodeUpper(selectedExtra);
        if (parts.prefix.length == 1) {
            g.setColor(numberingColor); g.fillOval(50, 2, 28, 28);
            g.setColor(backGround);     g.fillOval(52, 4, 24, 24);
        } else {
            g.setColor(numberingColor); g.fillRoundRect(50, 2, 28, 28, 6, 6);
            g.setColor(backGround);     g.fillRoundRect(52, 4, 24, 24, 6, 6);
        }
        assyukuDrawOutline(g, parts.prefix, 12, 16, 24, font, Color.white, 52, backGround);
        assyukuDrawOutline(g, parts.number, 12, 28, 24, font, Color.white, 52, backGround);
    }
}

// ============================================================
// ★ 共通: 種別・行先情報取得
// ============================================================
function getIkisakiInfo(train) {
    let next = train.getThisRoutePlatformsNextIndex();
    let platformList = train.getThisRoutePlatforms();
    let finalSta = platformList[next].destinationName;
    let finalStaJpn = TextUtil.getCjkParts(finalSta);
    let finalStaEng = TextUtil.getNonCjkParts(finalSta);
    let finalStaExtra = TextUtil.getExtraParts(finalSta);
    let route = platformList[next].route.name;
    let routeExtra = TextUtil.getExtraParts(route);
    let routeType = platformList[next].route.lightRailRouteNumber;
    let routeTypeJpn = TextUtil.getCjkParts(routeType);
    let routeColor = new Color(platformList[next].route.color);
    let finalStaJpnString = String(finalStaJpn);
    let displayFinalStaJpn = (finalStaJpnString.length == 2)
        ? finalStaJpnString.charAt(0) + "　" + finalStaJpnString.charAt(1)
        : finalStaJpn;

    let nextAll = train.getAllPlatformsNextIndex();
    let platformListAll = train.getAllPlatforms();
    let numberingColor = Color.white;
    let finalStaIndex = 0;
    for (let i = nextAll; i < platformListAll.size(); i++) {
        if (TextUtil.getCjkParts(platformListAll[i].station.name) == finalStaJpn) {
            numberingColor = new Color(platformListAll[i].route.color);
            finalStaIndex = i;
            break;
        }
    }
    let prevStaExtra = "";
    if (next > 0 && finalStaIndex > 0) {
        prevStaExtra = TextUtil.getExtraParts(platformListAll[finalStaIndex - 1].station.name);
    }

    return {
        next, platformList,
        finalStaJpn, finalStaEng, finalStaExtra, displayFinalStaJpn,
        routeExtra, routeTypeJpn, routeColor,
        numberingColor, prevStaExtra
    };
}

// ============================================================
// ★ 共通: 特殊種別（回送・試運転等）描画
// true = 描画済み、false = 通常描画へ
// ============================================================
function drawSpecialRouteType(text_g, routeTypeJpn, finalStaJpn, small_width, font) {
    if (routeTypeJpn == "回送" || finalStaJpn == "回送") {
        assyukuDraw(text_g, "回　 送", 20, 20, small_width, font, Color.white, 0);
        assyukuDraw(text_g, "Not In Service", 12, 31, small_width, font, Color.yellow, 0);
        return true;
    }
    if (routeTypeJpn == "試運転" || finalStaJpn == "試運転") {
        assyukuDraw(text_g, "試　運　転", 20, 20, small_width, font, Color.white, 0);
        assyukuDraw(text_g, "Trial Run", 12, 31, small_width, font, Color.yellow, 0);
        return true;
    }
    if (routeTypeJpn == "臨時" || finalStaJpn == "臨時") {
        assyukuDraw(text_g, "臨　 時", 20, 20, small_width, font, Color.white, 0);
        assyukuDraw(text_g, "Extra Train", 12, 31, small_width, font, Color.yellow, 0);
        return true;
    }
    if (routeTypeJpn == "団体" || finalStaJpn == "団体") {
        assyukuDraw(text_g, "団　 体", 20, 20, small_width, font, Color.white, 0);
        assyukuDraw(text_g, "Reserved", 12, 31, small_width, font, Color.yellow, 0);
        return true;
    }
    if (routeTypeJpn == "修学旅行" || finalStaJpn == "修学旅行") {
        assyukuDraw(text_g, "修 学 旅 行", 20, 20, small_width, font, Color.white, 0);
        assyukuDraw(text_g, "School Tour", 12, 31, small_width, font, Color.yellow, 0);
        return true;
    }
    return false;
}

// ============================================================
// ikisakiMain（側面行先）
// ============================================================
function ikisakiMain(g, train, state, cars) {
    initIkisakiCache(state);
    let cache = state.ikisakiCache;
    let text_g = state.text_g;
    let small_width = 160, small_height = 32;
    let display_width = 480, display_height = 96;

    text_g.setColor(cache.backGround);
    text_g.fillRect(0, 0, small_width, small_height);

    if (!train.isOnRoute()) {
        assyukuDraw(text_g, "回　 送", 20, 20, small_width, state.font, Color.white, 0);
        assyukuDraw(text_g, "Not In Service", 12, 31, small_width, state.font, Color.yellow, 0);
    } else {
        let info = getIkisakiInfo(train);

        if (!drawSpecialRouteType(text_g, info.routeTypeJpn, info.finalStaJpn, small_width, state.font)) {
            drawRouteType(text_g, info.routeTypeJpn, info.routeExtra, info.finalStaJpn, info.finalStaEng,
                info.routeColor, small_width, small_height, state.font,
                info.finalStaExtra, info.numberingColor, info.prevStaExtra, cache);

            let next = info.next;
            let platformList = info.platformList;
            if ((train.speed() < 0.27777) && (next + 1 != platformList.size())) {
                let nextSta = platformList[next + 1].station.name;
                let nextStaJpn = TextUtil.getCjkParts(nextSta);
                let nextStaEng = TextUtil.getNonCjkParts(nextSta);
                let phase = Date.now() % 9000;

                if (phase < 3000) {
                    assyukuDraw(text_g, info.displayFinalStaJpn + " 行", 20, 20, small_width / 2, state.font, Color.white, small_width / 2);
                    assyukuDraw(text_g, "次は " + nextStaJpn,             12, 31, small_width / 2, state.font, Color.yellow, small_width / 2);
                } else if (phase < 6000) {
                    assyukuDraw(text_g, "For " + info.finalStaEng,  20, 20, small_width / 2, state.font, Color.white, small_width / 2);
                    assyukuDraw(text_g, "Next " + nextStaEng,       12, 31, small_width / 2, state.font, Color.yellow, small_width / 2);
                } else {
                    // 号車表示: font.deriveFont()を1回だけ
                    text_g.setColor(cache.backGround);
                    text_g.fillRect(0, 0, small_width, small_height);
                    let carFont = state.font.deriveFont(Font.PLAIN, 32);
                    let carText = cars + "  号  車";
                    let carW = text_g.getFontMetrics(carFont).stringWidth(carText);
                    text_g.setFont(carFont);
                    text_g.setColor(Color.white);
                    text_g.drawString(carText, (small_width - carW) / 2, 30);
                }
            } else {
                assyukuDraw(text_g, info.displayFinalStaJpn, 20, 20, small_width / 2, state.font, Color.white, small_width / 2);
                assyukuDraw(text_g, info.finalStaEng,        12, 31, small_width / 2, state.font, Color.white, small_width / 2);
            }
        }
    }

    // ★ キャッシュ済みledImageを使う
    g.drawImage(state.text_image, 0, 0, display_width, display_height, 0, 0, small_width, small_height, null);
    g.drawImage(cache.ledImage, 0, 0, display_width + 1, display_height + 1, null);
}

// ============================================================
// ikisakiFront（前面・後面行先）
// ============================================================
function ikisakiFront(g, train, state) {
    initIkisakiCache(state);
    let cache = state.ikisakiCache;
    let text_g = state.text_front_g;
    let small_width = 160, small_height = 32;
    let display_width = 480, display_height = 96;

    text_g.setColor(cache.backGround);
    text_g.fillRect(0, 0, small_width, small_height);

    if (!train.isOnRoute()) {
        assyukuDraw(text_g, "回　 送", 20, 20, small_width, state.font, Color.white, 0);
        assyukuDraw(text_g, "Not In Service", 12, 31, small_width, state.font, Color.yellow, 0);
    } else {
        let info = getIkisakiInfo(train);

        if (!drawSpecialRouteType(text_g, info.routeTypeJpn, info.finalStaJpn, small_width, state.font)) {
            drawRouteType(text_g, info.routeTypeJpn, info.routeExtra, info.finalStaJpn, info.finalStaEng,
                info.routeColor, small_width, small_height, state.font,
                info.finalStaExtra, info.numberingColor, info.prevStaExtra, cache);
            assyukuDraw(text_g, info.displayFinalStaJpn, 20, 20, small_width / 2, state.font, Color.white, small_width / 2);
            assyukuDraw(text_g, info.finalStaEng,        12, 31, small_width / 2, state.font, Color.white, small_width / 2);
        }
    }

    // ★ キャッシュ済みledImageを使う
    g.drawImage(state.text_front_image, 0, 0, display_width, display_height, 0, 0, small_width, small_height, null);
    g.drawImage(cache.ledImage, 0, 0, display_width + 1, display_height + 1, null);
}