/*:
 * @target MZ
 * @plugindesc \CEN 以降を中央揃えにし、\LFT で解除（rtl安全な独立測定）[MZ]
 * @author You
 * @help
 * 【使い方】
 *  ・\CEN を一度出すと、その「文章の表示」が閉じるまで中央揃え。
 *  ・途中で左揃えに戻すには \LFT。
 * 【備考】
 *  ・行幅の測定は独立textState（rtlを明示初期化）で行い、描画はせず幅のみ算出。
 *  ・既存の _textState やフォント状態を汚しません。
 */

(() => {
  "use strict";

  // 文字列を計測用に整形：\x1b -> \ 、自前タグ除去
  function prepMeasureString(escLikeLine) {
    let raw = escLikeLine.replace(/\x1b/g, "\\");
    raw = raw.replace(/\\CEN/g, "").replace(/\\LFT/g, "");
    return raw;
  }

  // 独立 textState を自前構築して「処理だけ進めて」最終x移動量＝幅を得る
  // Window_Base の描画系を借りるが drawing=false で実描画しない
  function measureLineWidthNoDraw(win, rawText, maxWidth) {
    // フォント状態退避
    const c = win.contents;
    const prevFace   = c.fontFace;
    const prevSize   = c.fontSize;
    const prevBold   = c.fontBold;
    const prevItalic = c.fontItalic;

    // convertEscapeCharacters を通したテキスト
    const converted = win.convertEscapeCharacters(rawText);

    // 独立 textState を自前構築（rtlを明示設定）
    const state = {
      index: 0,
      x: 0,
      y: 0,
      left: 0,
      text: converted,
      height: win.lineHeight(),
      rtl: (win.baseTextDir && win.baseTextDir() === "rtl") ? true : false,
      drawing: false,           // ←描画しない
      outputWidth: 0,
      outputHeight: win.lineHeight(),
      // RPGMZの処理で参照され得る最低限のプロパティ
      startX: 0,
      maxWidth: maxWidth
    };

    // Window_Base の標準ループで1行分だけ処理する
    // 改行か終端で break
    win.resetFontSettings();
    while (state.index < state.text.length) {
      const c = state.text[state.index++];
      if (c === "\n") break;
      if (c === "\r") continue;

      if (c === "\x1b") {
        // エスケープコード
        const code = win.obtainEscapeCode(state);
        win.processEscapeCharacter(code, state); // drawing=false なので描画副作用は出ない
      } else {
        // 通常文字：文字幅だけ前進させる
        const w = win.textWidth(c);
        state.x += w;
      }
    }
    state.outputWidth = Math.max(state.outputWidth || 0, Math.abs(state.x - state.startX));

    // フォント状態復元
    c.fontFace  = prevFace;
    c.fontSize  = prevSize;
    c.fontBold  = prevBold;
    c.fontItalic= prevItalic;

    return state.outputWidth;
  }

  // メッセージ開始でモード初期化
  const _startMessage = Window_Message.prototype.startMessage;
  Window_Message.prototype.startMessage = function() {
    this._centerAlignMode = false; // \CENでON、\LFTでOFF
    _startMessage.call(this);
  };

  // 行頭Xの決定
  const _newLineX = Window_Message.prototype.newLineX;
  Window_Message.prototype.newLineX = function() {
    const baseX = _newLineX.call(this);
    const ts = this._textState;
    if (!ts) return baseX;

    if (this._centerAlignMode) {
      // 現在行（改行まで）の ESC文字列を取得
      const escLine = (ts.text.slice(ts.index).split("\n")[0] || "");
      // 計測用に \x1b->\ へ戻し、独自タグ除去
      const raw = prepMeasureString(escLine);
      // 描画せずに幅だけ安全に算出
      const w = measureLineWidthNoDraw(this, raw, this.contentsWidth());
      const cw = this.contentsWidth();
      return Math.max(0, (cw - w) / 2);
    }
    return baseX;
  };

  // 制御文字：\CEN でON、\LFT でOFF
  const _processEscapeCharacter = Window_Message.prototype.processEscapeCharacter;
  Window_Message.prototype.processEscapeCharacter = function(code, textState) {
    if (code === "CEN") { this._centerAlignMode = true;  return; }
    if (code === "LFT") { this._centerAlignMode = false; return; }
    _processEscapeCharacter.call(this, code, textState);
  };

})();
