include(Resources.id("mtrsteamloco:scripts/display_helper.js"));
importPackage(java.awt);
importPackage(java.awt.geom);
importPackage(java.io);
importPackage(java.net);
importPackage(java.util);
importPackage(java.lang);
importPackage(java.util.concurrent);

const car_num = new ConfigResponder.TextField("car_num", ComponentUtil.translatable("_号車"), "1");
const is_right = new ConfigResponder.CycleToggle("is_right", ComponentUtil.translatable("_番ドア"), 0, ["右から", "左から"]);

let slotCfg = {
  "version": 1,
  "texSize": [240, 30],
  "slots": [{
    "name": "1",
    "texArea": [0, 0, 60, 30],
    "pos": [[[-8.7, 1.15, 0.1], [-8.7, 1.0, 0.1], [-8.4, 1.0, 0.1], [-8.4, 1.15, 0.1]]],
    "offsets": [[-0.75, 0, 0.01], [3.35, 0, 0.01]]
  },
  {
    "name": "2",
    "texArea": [60, 0, 60, 30],
    "pos": [[[-3.85, 1.15, 0.1], [-3.85, 1.0, 0.1], [-3.55, 1.0, 0.1], [-3.55, 1.15, 0.1]]],
    "offsets": [[-0.75, 0, 0.01], [3.35, 0, 0.01]]
  },
  {
    "name": "3",
    "texArea": [120, 0, 60, 30],
    "pos": [[[1.0, 1.15, 0.1], [1.0, 1.0, 0.1], [1.3, 1.0, 0.1], [1.3, 1.15, 0.1]]],
    "offsets": [[-0.75, 0, 0.01], [3.35, 0, 0.01]]
  },
  {
    "name": "4",
    "texArea": [180, 0, 60, 30],
    "pos": [[[5.85, 1.15, 0.1], [5.85, 1.0, 0.1], [6.15, 1.0, 0.1], [6.15, 1.15, 0.1]]],
    "offsets": [[-0.75, 0, 0.01], [3.35, 0, 0.01]]
  }]
};
let dhBase = new DisplayHelper(slotCfg);
let activeLCDs = [];
let asyncPool = null;

function create(ctx, state, entity) {
  state.dh = dhBase.create();
  state.rate = new RateLimit(0.1);
  state.displayRate = new RateLimit(2.0);
  state.font = Resources.readFont(Resources.id("mtrsteamloco:eyecandies/font/notosansjp/notosansjp.ttf"));

  state.doorModel = ModelManager.loadPartedRawModel(Resources.manager(), Resources.id("mtrsteamloco:eyecandies/pd/tm_tozai_pd/tm_tozai_pd_d.obj"), null);
  state.doorR = state.doorModel.get("doorR");
  state.doorL = state.doorModel.get("doorL");
  state.doorR_long = state.doorModel.get("doorR_long");
  state.doorL_long = state.doorModel.get("doorL_long");
  state.dmhdoorR = new DynamicModelHolder();
  state.dmhdoorL = new DynamicModelHolder();
  state.dmhdoorR_long = new DynamicModelHolder();
  state.dmhdoorL_long = new DynamicModelHolder();


  state.dmhdoorR.uploadLater(state.doorR);
  state.dmhdoorL.uploadLater(state.doorL);
  state.dmhdoorR_long.uploadLater(state.doorR_long);
  state.dmhdoorL_long.uploadLater(state.doorL_long);

  state.soundTime = -1;
  state.doorTargetLast = entity.doorTarget;

  activeLCDs.push({ ctx: ctx, state: state, entity: entity });

  if (Resources.ANTE_FLAG && asyncPool === null) {
    asyncPool = Executors.newScheduledThreadPool(1);
    asyncPool.scheduleAtFixedRate(new java.lang.Runnable({
      run: () => {
        for (let i = 0; i < activeLCDs.length; i++) {
          let entry = activeLCDs[i];
          if (!entry.state.dh || entry.state.dh.closed) continue;

          try {
            tick(entry.ctx, entry.state, entry.entity);
            entry.ctx.drawCalls.put(
              i,
              new ClusterDrawCall(entry.state.dh.model, new Matrix4f())
            );
          } catch (e) {
          }
        }
      }
    }), 0, 1000 / 0.5, TimeUnit.MILLISECONDS);
  }
}

function dispose(ctx, state, entity) {
  state.dmhdoorR.close();
  state.dmhdoorL.close();
  state.dmhdoorR_long.close();
  state.dmhdoorL_long.close();

  for (let i = activeLCDs.length - 1; i >= 0; i--) {
    if (activeLCDs[i].entity.equals(entity)) {
      activeLCDs.splice(i, 1);
      break;
    }
  }

  if (activeLCDs.length === 0 && asyncPool !== null) {
    asyncPool.shutdown();
    asyncPool = null;
  }
  state.dh.close();
}

function render(ctx, state, entity) {
  entity.registerCustomConfig(car_num);
  entity.registerCustomConfig(is_right);
  if (state.rate.shouldUpdate()) {
    if (entity.doorTarget != state.doorTargetLast) {
      if (Date.now() > state.soundTime + 1000) {
        let soundId = Resources.id("mtrsteamloco:tm_g_pd")
        let k = new TickableSound(soundId);
        k.setData(1, 1, entity.getWorldPosVector3f());
        let delay = entity.doorTarget ? 0 : 20;
        SoundHelper.play(k, delay);
        state.soundTime = Date.now();
      }
    }
    state.doorTargetLast = entity.doorTarget;
  }
  //ドア動作
  let doorValue = entity.doorValue * 1.0666;
  if (entity.doorValue > 0.75) {
    doorValue = 0.8;
  }

  let matR = new Matrices();
  matR.pushPose();
  matR.translate(doorValue, 0, 0);
  ctx.drawModel(state.dmhdoorR.getUploadedModel(), matR);
  matR.popPose();

  let matL = new Matrices();
  matL.pushPose();
  matL.translate(-doorValue, 0, 0);
  ctx.drawModel(state.dmhdoorL.getUploadedModel(), matL);
  matL.popPose();

  let doorValue_long = entity.doorValue * 2.4;
  if (entity.doorValue > 0.75) {
    doorValue_long = 1.8;
  }

  let matR_long = new Matrices();
  matR_long.pushPose();
  matR_long.translate(doorValue_long, 0, 0);
  ctx.drawModel(state.dmhdoorR_long.getUploadedModel(), matR_long);
  matR_long.popPose();

  let matL_long = new Matrices();
  matL_long.pushPose();
  matL_long.translate(-doorValue_long, 0, 0);
  ctx.drawModel(state.dmhdoorL_long.getUploadedModel(), matL_long);
  matL_long.popPose();

  if (!Resources.ANTE_FLAG) {
    tick(ctx, state, entity);
    ctx.drawModel(state.dh.model, null);
  }
}

function tick(ctx, state, entity) {
  let isRight = (entity.getCustomConfig("is_right") == 0);
  let carNum = entity.getCustomConfig("car_num");
  let navy = new Color(0.125, 0.184, 0.333);

  let text_1 = isRight ? "4" : "1";
  let text_2 = isRight ? "3" : "2";
  let text_3 = isRight ? "2" : "3";
  let text_4 = isRight ? "1" : "4";

  let g;
  g = state.dh.graphicsFor("1");
  g.setColor(navy);
  g.fillRect(0, 0, 60, 30);
  assyukuDrawNotCenter(g, carNum, 20, 27.5, 15, state.font, Color.white, 0);
  assyukuDrawNotCenter(g, text_1, 20, 27.5, 15, state.font, Color.white, 30);
  assyukuDrawNotCenter(g, "号車", 10, 27.5, 15, state.font, Color.white, 15);
  assyukuDrawNotCenter(g, "番ドア", 10, 27.5, 15, state.font, Color.white, 45);

  g = state.dh.graphicsFor("2");
  g.setColor(navy);
  g.fillRect(0, 0, 60, 30);
  assyukuDrawNotCenter(g, carNum, 20, 27.5, 15, state.font, Color.white, 0);
  assyukuDrawNotCenter(g, text_2, 20, 27.5, 15, state.font, Color.white, 30);
  assyukuDrawNotCenter(g, "号車", 10, 27.5, 15, state.font, Color.white, 15);
  assyukuDrawNotCenter(g, "番ドア", 10, 27.5, 15, state.font, Color.white, 45);

  g = state.dh.graphicsFor("3");
  g.setColor(navy);
  g.fillRect(0, 0, 60, 30);
  assyukuDrawNotCenter(g, carNum, 20, 27.5, 15, state.font, Color.white, 0);
  assyukuDrawNotCenter(g, text_3, 20, 27.5, 15, state.font, Color.white, 30);
  assyukuDrawNotCenter(g, "号車", 10, 27.5, 15, state.font, Color.white, 15);
  assyukuDrawNotCenter(g, "番ドア", 10, 27.5, 15, state.font, Color.white, 45);

  g = state.dh.graphicsFor("4");
  g.setColor(navy);
  g.fillRect(0, 0, 60, 30);
  assyukuDrawNotCenter(g, carNum, 20, 27.5, 15, state.font, Color.white, 0);
  assyukuDrawNotCenter(g, text_4, 20, 27.5, 15, state.font, Color.white, 30);
  assyukuDrawNotCenter(g, "号車", 10, 27.5, 15, state.font, Color.white, 15);
  assyukuDrawNotCenter(g, "番ドア", 10, 27.5, 15, state.font, Color.white, 45);

  state.dh.upload();
}

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 use(ctx, state, entity, player) {

}