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

function getPointCoordinates(angleDeg, radius) {
    const angleRad = angleDeg * (Math.PI / 180);

    // 2. Calculate coordinates relative to the origin (0, 0)
    const pointX = radius * Math.cos(angleRad);
    const pointZ = radius * Math.sin(angleRad);

    return { x: pointX, z: pointZ };
}

function drawAutoWidthString(text, x, y, g, font, size, width, align) {
  g.setFont(font.deriveFont(Font.PLAIN, size));
  var fm = g.getFontMetrics(font.deriveFont(Font.PLAIN, size));
  var text_width = fm.stringWidth(text);

  if (text_width <= width) {
    // 横幅に収まる場合
    if (align === "center") {
      g.drawString(text, x + (width - text_width) / 2, y);
    } else if (align === "right") {
      g.drawString(text, x + (width - text_width), y);
    } else if (align === "justify") {
      if (text.length > 1) {
        var totalSpace = width - text_width;
        var extraSpace = totalSpace / (text.length - 1);
        var cx = x;
        for (var i = 0; i < text.length; i++) {
          g.drawString(text.charAt(i), cx, y);
          cx += fm.charWidth(text.charAt(i)) + extraSpace;
        }
      } else {
        // 1文字だけなら中央寄せ
        g.drawString(text, x + (width - text_width) / 2, y);
      }
    } else if (align === "justify_flex") {
      if (text.length > 1) {
        var totalSpace = width - text_width;
        var extraSpace = totalSpace / (text.length + 1);
        var cx = x + extraSpace;
        for (var i = 0; i < text.length; i++) {
          g.drawString(text.charAt(i), cx, y);
          cx += fm.charWidth(text.charAt(i)) + extraSpace;
        }
      } else {
        // 1文字だけなら中央寄せ
        g.drawString(text, x + (width - text_width) / 2, y);
      }
    } else {
      // left または未指定
      g.drawString(text, x, y);
    }
  } else {
    // 横幅を超える場合 → scaleして強制フィット（揃えは無視）
    var scale_x = width / text_width;
    var ot = g.getTransform();

    g.translate(x, y);
    g.scale(scale_x, 1.0);
    g.drawString(text, 0, 0);

    g.setTransform(ot);
  }
}

function drawVerticalText(text, x, y, g, font, size, height, align) {
  g.setFont(font.deriveFont(Font.PLAIN, size))
  var fm = g.getFontMetrics(font.deriveFont(Font.PLAIN, size));
  var text_height = size * text.length;

  if (text_height <= height) {
    if (align == "top") {
      
    } else if (align == "bottom") {
    
    } else if (align == "justify") {
      let total_space = height - text_height;
      let extra_space = total_space / (text.length - 1);

      for (i=0;i<text.length;i++) {
        let text_y = y - height + i * (size + extra_space) + size;
        g.drawString(text.split("")[i], x, text_y);
      }
    } else {
      
    }
  } else {
    var scale_y = height / text_height;
    var ot = g.getTransform();
    g.translate(x, y - height);
    g.scale(1.0, scale_y);

    for (i=0;i<text.length;i++) {
      let text_y = size * (i + 1);
      g.drawString(text.split("")[i], 0, text_y);
    }
    g.setTransform(ot);
  }
}


function ledFront(g, text_g, train, state) {
  try {
    let orange = new Color(0.941, 0.478, 0.101);

    let platformInfo = train.getThisRoutePlatforms();
    let next = train.getThisRoutePlatformsNextIndex();
    let route_number = String(platformInfo[next].route.lightRailRouteNumber).split("|");
    let dest = String(platformInfo[next].destinationName).split("|");

    text_g.setColor(Color.black);
    text_g.fillRect(0, 0, 192, 40);
    text_g.setColor(orange);
    text_g.fillRoundRect(3, 3, 50, 36, 7, 7);
    text_g.setColor(Color.black);
    drawAutoWidthString(route_number[0], 4, 36, text_g, state.font_medium, 41, 22, "center");
    drawAutoWidthString(route_number[0], 5, 36, text_g, state.font_medium, 41, 22, "center");
    drawAutoWidthString(route_number[1], 28, 36, text_g, state.oswald, 37, 23, "center");

    text_g.setColor(orange);
    drawAutoWidthString(dest[1], 56, 30, text_g, state.font_medium, 20, 132, "justify");
    drawAutoWidthString(dest[2], 56, 39, text_g, state.font_medium, 8, 132, "justify");
    drawAutoWidthString(dest[0], 56, 11, text_g, state.font_medium, 12, 132, "justify");

    g.drawImage(state.text_image, 0, 0, 768, 160, 0, 0, 192, 40, null);

    g.drawImage(Resources.readBufferedImage(Resources.id("mtr:shirataka_bus_a/images/amigake.png")), 0, 0, 769, 161, null);
  } catch(e) {
    g.setColor(Color.black);
    g.fillRect(0, 0, 769, 161);
  }
}

function ledSide(g, text_g, train, state) {
  let orange = new Color(0.941, 0.478, 0.101);


  let platformInfo = train.getThisRoutePlatforms();
  let next = train.getThisRoutePlatformsNextIndex();
  let route_number = String(platformInfo[next].route.lightRailRouteNumber).split("|");
  let dest = String(platformInfo[next].destinationName).split("|");
  let dest_index = platformInfo.length - 1;
  let stations = [];
  for (i=0;i<3;i++) {
    let index = next + i;

    if (index < dest_index) {
      stations[i] = TextUtil.getCjkParts(platformInfo.get(index).station.name);
    } else {
      stations[i] = "";
    }
  }
  stations[3] = TextUtil.getCjkParts(platformInfo.get(dest_index).station.name);
  stations.reverse();

  text_g.setColor(Color.black);
  text_g.fillRect(0, 0, 128, 96);

  text_g.setColor(orange);
  text_g.fillRect(0, 0, 28, 16);
  if (Date.now() % 15000 < 5000) {
    drawAutoWidthString(dest[0], 30, 14, text_g, state.font_medium, 16, 98, "justify_flex")
  } else if (Date.now() % 15000 < 10000) {
    drawAutoWidthString(dest[1], 30, 14, text_g, state.font_medium, 16, 98, "justify_flex")
  } else {
    drawAutoWidthString(dest[2], 30, 14, text_g, state.font, 16, 98, "center")
  }
  text_g.setColor(Color.black);
  drawAutoWidthString(route_number.join(""), 1, 15, text_g, state.oswald, 17, 26, "center");

  text_g.setColor(orange);
  for (let i=0;i<4;i++) {
    let text_x = (16 + 21) * i;
    drawVerticalText(String(stations[i]), text_x, 95, text_g, state.font_semibold, 16, 64, "justify");
  }

  g.drawImage(state.text_side_image, 0, 0, 512, 384, 0, 0, 128, 96, null);
  g.drawImage(Resources.readBufferedImage(Resources.id("mtr:shirataka_bus_a/images/amigake_side.png")), 0, 0, 513, 385, null);

}

function create(ctx,state,train){
    state.busModel = ModelManager.loadPartedRawModel(Resources.manager(), modelId, null);
    state.busModelDoorFF = state.busModel.get("door_ff");
    state.busModelDoorFB = state.busModel.get("door_fb");
    state.busModelDoorB = state.busModel.get("door_b");
    state.busModelGearB = state.busModel.get("gear_b");
    state.busModelGearF = state.busModel.get("gear_f");

    state.busDynamicDoorFF = new DynamicModelHolder();
    state.busDynamicDoorFB = new DynamicModelHolder();
    state.busDynamicDoorB = new DynamicModelHolder();
    state.busDynamicGearB = new DynamicModelHolder();
    state.busDynamicGearF = new DynamicModelHolder();

    state.busDynamicDoorFF.uploadLater(state.busModelDoorFF);
    state.busDynamicDoorFB.uploadLater(state.busModelDoorFB);
    state.busDynamicDoorB.uploadLater(state.busModelDoorB);
    state.busDynamicGearB.uploadLater(state.busModelGearB);
    state.busDynamicGearF.uploadLater(state.busModelGearF);

    state.dh = dhBase.create();

    state.text_image = new BufferedImage(192, 40, BufferedImage.TYPE_INT_ARGB);
    state.text_g = state.text_image.createGraphics();
    state.text_side_image = new BufferedImage(128, 96, BufferedImage.TYPE_INT_ARGB);
    state.text_side_g = state.text_side_image.createGraphics();

    state.rate = new RateLimit(5.0);
    state.font = Resources.readFont(Resources.id("mtr:font/notosansjp-normal.ttf"));
    state.font_medium = Resources.readFont(Resources.id("mtr:font/notosansjp-mid.ttf"));   
    state.font_semibold = Resources.readFont(Resources.id("mtr:font/notosansjp-semi.ttf"));   
    state.font_bold = Resources.readFont(Resources.id("mtr:font/notosansjp-bold.ttf"));   
    state.oswald = Resources.readFont(Resources.id("mtr:font/oswald.ttf"));   
}

function dispose(ctx,state,train){
    state.busDynamicDoorFB.close();
    state.busDynamicDoorFF.close();
    state.busDynamicDoorB.close();
    state.busDynamicGearF.close();
    state.busDynamicGearB.close();

    state.dh.close();
    state.text_g.dispose()
    state.text_side_g.dispose()
}

function render(ctx,state,train){
    let matrices = new Matrices();
    let doorValue = train.doorValue();
    let distance = train.getRailProgress(0);
    let radius = 0.91 / 2;
    
    for (i=0;i<train.trainCars();i++) {
      matrices.pushPose();
      matrices.translate(1.25, 0, 5);
      matrices.rotateY(1.5708 * doorValue);
      matrices.translate(-1.25, 0, -5)
      ctx.drawCarModel(state.busDynamicDoorFF.getUploadedModel(), i, matrices);
      matrices.popPose();

      matrices.pushPose();
      matrices.translate(
        1.25 + (-0.47 * Math.sin(1.5708 * doorValue) * 1.15),
        0,
        4.53 + (-0.47 * Math.cos(1.5708 * doorValue) * 0.7 + 0.329)
      );
      matrices.rotateY(-1.5708 * doorValue);
      matrices.translate(-1.25, 0, -4.53);
      ctx.drawCarModel(state.busDynamicDoorFB.getUploadedModel(), i, matrices);
      matrices.popPose();

      matrices.pushPose();
      matrices.translate(0, 0, 1 * doorValue);
      ctx.drawCarModel(state.busDynamicDoorB.getUploadedModel(), i, matrices);
      matrices.popPose();

      if (!train.isReversed()) {
        matrices.pushPose();
        matrices.translate(0, -0.545, 3.475);
        matrices.rotateX(distance / radius);
        matrices.translate(0, 0.545, -3.475)
        ctx.drawCarModel(state.busDynamicGearF.getUploadedModel(), i, matrices);
        matrices.popPose();

        matrices.pushPose();
        matrices.translate(0, -0.545, -1.895);
        matrices.rotateX(distance / radius);
        matrices.translate(0, 0.545, 1.895)
        ctx.drawCarModel(state.busDynamicGearB.getUploadedModel(), i, matrices);
        matrices.popPose();
      } else {
        matrices.pushPose();
        matrices.translate(0, -0.545, 3.475);
        matrices.rotateX(-(distance / radius));
        matrices.translate(0, 0.545, -3.475)
        ctx.drawCarModel(state.busDynamicGearF.getUploadedModel(), i, matrices);
        matrices.popPose();

        matrices.pushPose();
        matrices.translate(0, -0.545, -1.895);
        matrices.rotateX(-(distance / radius));
        matrices.translate(0, 0.545, 1.895)
        ctx.drawCarModel(state.busDynamicGearB.getUploadedModel(), i, matrices);
        matrices.popPose();
      }
    }   

    if (state.rate.shouldUpdate()){
        let g;
        g = state.dh.graphicsFor("led_front");
        ledFront(g, state.text_g, train, state);

        g = state.dh.graphicsFor("led_side");
        ledSide(g, state.text_side_g, train, state);
        
        state.dh.upload();
    }

    for (let i = 0; i < train.trainCars(); i++) {
        ctx.drawCarModel(state.dh.model, i, null);
    }
}