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

//////////////////////////////
// 128x32 キャンバス確保（参考コードのフォントに統一）
//////////////////////////////
function ensureSmallCanvas(state) {
    if (state.smallW == null) state.smallW = 128;
    if (state.smallH == null) state.smallH = 32;

    if (state.text_image == null
        || state.text_image.getWidth() != state.smallW
        || state.text_image.getHeight() != state.smallH) {

        state.text_image = new BufferedImage(state.smallW, state.smallH, BufferedImage.TYPE_INT_ARGB);
        state.text_g = state.text_image.createGraphics();

        // 低解像度なので AA OFF（LEDっぽく）
        state.text_g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        state.text_g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        state.text_g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        state.text_g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
    }

    // ★参考コード寄せフォント
    if (!state.fontJP) state.fontJP = Resources.readFont(Resources.id("mtr:fonts/notosanscjkjp-medium.otf"));
    if (!state.fontEN) state.fontEN = Resources.readFont(Resources.id("mtr:fonts/morio_s.ttf"));
}

//////////////////////////////
// 文字が短いときに字間を開く（2〜3文字向け）
//////////////////////////////
function drawTrackingCentered(g2, text, baseFont, sizePx, x, yBaseline, w, color, maxExtraPerGapPx) {
    if (text == null) return;
    text = String(text);

    let font = baseFont.deriveFont(Font.PLAIN, sizePx);
    let fm = g2.getFontMetrics(font);
    let textW = fm.stringWidth(text);

    g2.setFont(font);
    g2.setColor(color);

    if (text.length <= 1) {
        g2.drawString(text, x + (w - textW) / 2, yBaseline);
        return;
    }

    let extra = w - textW;
    if (extra > 0 && text.length >= 2 && text.length <= 3) {
        let gaps = text.length - 1;
        let add = extra / gaps;
        if (maxExtraPerGapPx != null) add = Math.min(add, maxExtraPerGapPx);

        let totalW = textW + add * gaps;
        let cx = x + (w - totalW) / 2;

        for (let i = 0; i < text.length; i++) {
            let ch = text.substring(i, i + 1);
            g2.drawString(ch, cx, yBaseline);
            cx += fm.stringWidth(ch);
            if (i != text.length - 1) cx += add;
        }
        return;
    }

    g2.drawString(text, x + (w - textW) / 2, yBaseline);
}

//////////////////////////////
// 横幅に収めて中央（必要ならX方向圧縮）
//////////////////////////////
function drawFitXCentered(g2, text, baseFont, sizePx, x, yBaseline, w, color, allowTrackingShort) {
    if (text == null) return { scaleX: 1.0, startX: x, y: yBaseline, font: baseFont.deriveFont(Font.PLAIN, sizePx), scaledFont: null };
    text = String(text);

    let font = baseFont.deriveFont(Font.PLAIN, sizePx);
    let fm = g2.getFontMetrics(font);
    let tw = fm.stringWidth(text);

    // 短いときは字間を少し開ける（これはスケール無しのときだけ）
    if (allowTrackingShort && tw < w && text.length >= 2 && text.length <= 3) {
        g2.setFont(font);
        g2.setColor(color);
        drawTrackingCentered(g2, text, baseFont, sizePx, x, yBaseline, w, color, 4.0);

        // 位置情報（スケール無し想定）
        let startX = x + (w - tw) / 2;
        return { scaleX: 1.0, startX: startX, y: yBaseline, font: font, scaledFont: null, tracking: true };
    }

    // 収まるなら普通
    if (tw <= w) {
        let startX = x + (w - tw) / 2;
        g2.setFont(font);
        g2.setColor(color);
        g2.drawString(text, startX, yBaseline);
        return { scaleX: 1.0, startX: startX, y: yBaseline, font: font, scaledFont: null, tracking: false };
    }

    // X方向だけ圧縮（scaleX<1）
    let scaleX = w / tw;
    let at = new AffineTransform();
    at.scale(scaleX, 1.0);

    let scaledFont = font.deriveFont(at);
    let startX = x + (w - tw * scaleX) / 2;

    g2.setFont(scaledFont);
    g2.setColor(color);
    // scaledFont は座標もスケールされるので逆補正
    g2.drawString(text, x + (startX - x) / scaleX, yBaseline);

    return { scaleX: scaleX, startX: startX, y: yBaseline, font: font, scaledFont: scaledFont, tracking: false };
}

//////////////////////////////
// 縁取り付き（上下左右1px）→ 本体
// ★1回だけ位置決めして同じstartXで描く（内側化を防ぐ）
//////////////////////////////
function drawFitXCenteredOutline(g2, text, baseFont, sizePx, x, yBaseline, w, mainColor, outlineColor, allowTrackingShort) {
    if (text == null) return;

    text = String(text);

    let font = baseFont.deriveFont(Font.PLAIN, sizePx);
    let fm = g2.getFontMetrics(font);
    let tw = fm.stringWidth(text);

    // 短文トラッキング（ここは今のままでOK）
    if (allowTrackingShort && tw < w && text.length >= 2 && text.length <= 3) {
        let o = 1;
        drawTrackingCentered(g2, text, baseFont, sizePx, x - o, yBaseline, w, outlineColor, 4.0);
        drawTrackingCentered(g2, text, baseFont, sizePx, x + o, yBaseline, w, outlineColor, 4.0);
        drawTrackingCentered(g2, text, baseFont, sizePx, x, yBaseline - o, w, outlineColor, 4.0);
        drawTrackingCentered(g2, text, baseFont, sizePx, x, yBaseline + o, w, outlineColor, 4.0);
        drawTrackingCentered(g2, text, baseFont, sizePx, x, yBaseline, w, mainColor, 4.0);
        return;
    }

    // scaleX 計算（描画は drawAt でまとめて）
    let scaleX = 1.0;
    let scaledFont = null;
    let startX = x + (w - tw) / 2;

    if (tw > w) {
        scaleX = w / tw;
        let at = new AffineTransform();
        at.scale(scaleX, 1.0);
        scaledFont = font.deriveFont(at);
        startX = x + (w - tw * scaleX) / 2;
    }

    function drawAt(dx, dy, color) {
        g2.setColor(color);

        if (scaleX < 1.0) {
            g2.setFont(scaledFont);

            // ★重要：x を基準にして逆補正（右側がズレない）
            let logicalX = x + ((startX - x + dx) / scaleX);
            g2.drawString(text, logicalX, yBaseline + dy);

        } else {
            g2.setFont(font);
            g2.drawString(text, startX + dx, yBaseline + dy);
        }
    }

    // 縁（上下左右）
    drawAt(0, -1, outlineColor);
    drawAt(0, +1, outlineColor);
    drawAt(-1, 0, outlineColor);
    drawAt(+1, 0, outlineColor);

    // 本体
    drawAt(0, 0, mainColor);
}

//////////////////////////////
// 種別カラーDB（JSON）ロード
// 例: mtr:botapinu_lcd/route_type_colors.json
//////////////////////////////
function loadRouteTypeColorDbOnce(state) {
    if (state.routeTypeColorDb != null) return;

    // ★好きなパスに変えてOK
    let path = "mtr:botapinu_lcd/mctq_pinu_lcd/route_type_colors.json";

    try {
        let txt = Resources.readString(Resources.id(path));
        state.routeTypeColorDb = JSON.parse(String(txt));
        if (state.routeTypeColorDb == null || typeof state.routeTypeColorDb !== "object") state.routeTypeColorDb = {};
        print("route_type_colors.json loaded: " + path);
    } catch (e) {
        state.routeTypeColorDb = {};
        print("FAILED route_type_colors.json: " + e);
    }
}

// "#RRGGBB" / "#AARRGGBB" / "0xAARRGGBB" / 数値(ARGB/RGB) を Color に
function parseAnyColor(v) {
    if (v == null) return null;
    if (typeof v === "string" && v.startsWith("Color.")) {
        let name = v.substring(6);

        if (Color[name] != null) return Color[name];
    }
    // number
    if (typeof v === "number") {
        // ARGBの可能性があるので alpha=true で受ける
        return new Color((v | 0), true);
    }

    let s = String(v).trim();
    if (s.length == 0) return null;

    // 0x....
    if (s.startsWith("0x") || s.startsWith("0X")) {
        let n = (java.lang.Long.parseLong(s.substring(2), 16)) | 0;
        return new Color(n, true);
    }

    // #....
    if (s.startsWith("#")) {
        let hex = s.substring(1);
        if (hex.length === 6) {
            let n = (java.lang.Integer.parseInt(hex, 16)) | 0;
            return new Color(n); // RGB
        } else if (hex.length === 8) {
            let n = (java.lang.Long.parseLong(hex, 16)) | 0; // AARRGGBB
            return new Color(n, true);
        }
    }

    // fallback: 数字文字列
    try {
        let n2 = (java.lang.Integer.parseInt(s)) | 0;
        return new Color(n2, true);
    } catch (e) { }

    return null;
}

// routeTypeJpn に対する上書き { bg: Color, fg: Color } を返す
function getRouteTypeColorOverride(state, routeTypeJpn) {
    loadRouteTypeColorDbOnce(state);
    if (!routeTypeJpn) return null;

    let key = String(routeTypeJpn).trim();
    let obj = state.routeTypeColorDb ? state.routeTypeColorDb[key] : null;
    if (!obj || typeof obj !== "object") return null;

    let bg = parseAnyColor(obj.bg);
    let fg = parseAnyColor(obj.fg);

    if (bg == null && fg == null) return null;
    return { bg: bg, fg: fg };
}




function ikisakiMain(g, state, train) {
    ensureSmallCanvas(state);

    let text_g = state.text_g;
    let smallW = state.smallW; // 128
    let smallH = state.smallH; // 32

    // 出力側（モデルのテクスチャサイズ）
    let outW = 640;
    let outH = 160;

    // 色
    let backGround = new Color(0.188, 0.188, 0.188);

    // ▼比率変更：左48(種別) / 右80(行先)
    let typeW = 48;
    let destX = 48;
    let destW = 80;

    // ▼フォントサイズと位置（現状踏襲）
    let jpY = 21;
    let enY = 32;

    let typeJpSize = 24;
    let typeEnSize = 12;
    let destJpSize = 24;
    let destEnSize = 12;

    // 背景
    text_g.setColor(backGround);
    text_g.fillRect(0, 0, smallW, smallH);

    // platform 安全
    let platformList = train.getThisRoutePlatforms();
    let next = train.getThisRoutePlatformsNextIndex();
    let invalid = (platformList == null || platformList.length == 0 || next < 0 || next >= platformList.length);

    // デフォルト（回送）
    let routeTypeJpn = "回送";
    let routeTypeEng = "Not In Service"; // ★回送はJPだけ出したいなら空でOK
    let finalStaJpn = "";  // ★回送時は行先欄は空
    let finalStaEng = "";
    let routeColor = Color.red;

    if (!invalid) {
        let p = platformList[next];
        let finalSta = p.destinationName;
        let routeType = p.route.lightRailRouteNumber;

        finalStaJpn = TextUtil.getCjkParts(finalSta);
        finalStaEng = TextUtil.getNonCjkParts(finalSta);
        routeTypeJpn = TextUtil.getCjkParts(routeType);
        routeTypeEng = TextUtil.getNonCjkParts(routeType);
        routeColor = new Color(p.route.color);

        // 特殊表示（必要最小限）
        if (!train.isOnRoute()) {
            // ★回送扱い：行先は空にする
            routeColor = Color.red;
            routeTypeJpn = "回送";
            routeTypeEng = "Not In Service";
            finalStaJpn = "";
            finalStaEng = "";
        } else if (routeTypeJpn == "試運転" || finalStaJpn == "試運転") {
            routeColor = Color.red;
            routeTypeJpn = "試運転";
            routeTypeEng = "Test Run";
            finalStaJpn = "";
            finalStaEng = "";
        } else if (finalStaJpn == "臨時") {
            routeColor = backGround;
            routeTypeJpn = "臨時";
            routeTypeEng = "Extra";
            finalStaJpn = "";
            finalStaEng = "";
        } else if (finalStaJpn == "団体専用") {
            routeColor = Color.red;
            routeTypeJpn = "団体";
            routeTypeEng = "Group";
            finalStaJpn = "";
            finalStaEng = "";
        }
    }

    // ★ここから「描画に使う色」を決める
    // 種別背景：基本 routeColor、ただしJSON一致があれば上書き
    let typeBg = routeColor;
    let typeFg = Color.white;

    // 回送は「背景 backGround + 白文字」固定（ユーザー要望）
    let isKaisho = (String(routeTypeJpn) === "回送");
    if (invalid) isKaisho = true; // platform取れない時も回送扱い

    if (isKaisho) {
        typeBg = backGround;
        typeFg = Color.white;
        routeTypeJpn = "回送";
        routeTypeEng = "Not In Service";
        finalStaJpn = "";
        finalStaEng = "";
    } else {
        let ov = getRouteTypeColorOverride(state, routeTypeJpn);
        if (ov) {
            if (ov.bg != null) typeBg = ov.bg;
            if (ov.fg != null) typeFg = ov.fg;
        }
    }

    // 走行中は出さない（元仕様踏襲）※必要なければこのifを消す
    if (!invalid && train.isOnRoute() && train.speed() >= 1) {
        // 背景のみ
    } else {
        // 種別塗り（48px）
        text_g.setColor(typeBg);
        text_g.fillRect(0, 0, typeW, smallH);

        // 種別と行先の境界線（背景色で1px）
        text_g.setColor(backGround);
        text_g.drawLine(typeW - 1, 0, typeW - 1, smallH - 1);

        // 種別（縁取りなし）
        drawFitXCentered(
            text_g, routeTypeJpn, state.fontJP, typeJpSize,
            0, jpY, typeW, typeFg, true
        );
        drawFitXCentered(
            text_g, routeTypeEng, state.fontEN, typeEnSize,
            0, enY, typeW, typeFg, false
        );

        // 行先（80px）
        drawFitXCenteredOutline(
            text_g, finalStaJpn, state.fontJP, destJpSize,
            destX, jpY, destW, Color.white, backGround, true
        );
        drawFitXCenteredOutline(
            text_g, finalStaEng, state.fontEN, destEnSize,
            destX, enY, destW, Color.white, backGround, false
        );
    }

    // ★128x32 → 640x160（NEARESTで荒く拡大）
    if (g instanceof java.awt.Graphics2D) {
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
    }
    let ledImageSide = Resources.readBufferedImage(Resources.id("mtr:botapinu_lcd/mctq_lcd/images/led_side.png"));
    g.drawImage(state.text_image, 0, 0, outW, outH, 0, 0, smallW, smallH, null);
    g.drawImage(ledImageSide, 0, 0, outW + 1, outH + 1, null);
}