/*:
 * @plugindesc 複数のカスタムコマンドを持つウィンドウを追加するプラグイン（画像ベース対応版）
 * @author えむうん
 * @target MZ
 *
 * @param WindowX
 * @desc カスタムウィンドウのX座標
 * @type number
 * @default 0
 *
 * @param WindowY
 * @desc カスタムウィンドウのY座標
 * @type number
 * @default 0
 *
 * @param WindowWidth
 * @desc カスタムウィンドウの最小幅
 * @type number
 * @default 240
 *
 * @param WindowHeight
 * @desc カスタムウィンドウの最小高さ
 * @type number
 * @default 240
 *
 * @param SwitchId
 * @desc ウィンドウの表示/非表示を制御するスイッチのID
 * @type switch
 * @default 1
 *
 * @param Opacity
 * @desc ウィンドウの不透明度（0-255）
 * @type number
 * @min 0
 * @max 255
 * @default 255
 *
 * @param ColumnCount
 * @desc コマンドの列数
 * @type number
 * @min 1
 * @default 1
 *
 * @param RowCount
 * @desc コマンドの行数
 * @type number
 * @min 1
 * @default 0
 *
 * @param Layout
 * @desc コマンドの配置方法
 * @type select
 * @option 横並び
 * @value horizontal
 * @option 縦並び
 * @value vertical
 * @default vertical
 *
 * @param Commands
 * @type struct<Command>[]
 * @desc カスタムコマンドのリスト
 * @default [{"Name":"カスタムコマンド1","Image":"custom_command1","CommonEventId":"1","SwitchId":"2"},{"Name":"カスタムコマンド2","Image":"custom_command2","CommonEventId":"2","SwitchId":"3"}]
 *
 * @help
 * このプラグインは、複数の画像ベースのカスタムコマンドを持つウィンドウを追加します。
 * 指定されたスイッチがオンになると即座にウィンドウが表示されます。
 * 各コマンドは個別のスイッチで表示/非表示を制御できます。
 *
 * 使用方法：
 * 1. プラグインパラメータでウィンドウの位置、最小サイズ、制御スイッチID、
 *    不透明度を設定します。
 * 2. ColumnCount, RowCount, Layoutパラメータでコマンドの配置を設定します。
 * 3. Commands パラメータで、複数のカスタムコマンドを設定します。
 *    各コマンドにSwitchIdを設定して、個別の表示制御を行います。
 * 4. 各コマンドの画像ファイルを img/system フォルダに配置します。
 * 5. 指定したスイッチをオンにするとウィンドウが表示されます。
 * 6. 各コマンドの表示/非表示は、設定したSwitchIdで制御されます。
 * 7. ゲーム中に不透明度を変更する場合は、以下のスクリプトを使用します：
 *    $gameSystem.setCustomWindowOpacity(不透明度);
 */

/*~struct~Command:
 * @param Name
 * @desc コマンドの名前
 * @type string
 * 
 * @param Image
 * @desc コマンドの画像ファイル名（img/system/内）
 * @type file
 * @dir img/system
 * 
 * @param CommonEventId
 * @desc 呼び出すコモンイベントのID
 * @type common_event
 * 
 * @param SwitchId
 * @desc コマンドの表示/非表示を制御するスイッチのID
 * @type switch
 */

(function() {
    'use strict';

    const pluginName = "MultiCustomCommandsWindowPlugin";
    const parameters = PluginManager.parameters(pluginName);
    const windowX = Number(parameters['WindowX'] || 0);
    const windowY = Number(parameters['WindowY'] || 0);
    const windowWidth = Number(parameters['WindowWidth'] || 240);
    const windowHeight = Number(parameters['WindowHeight'] || 240);
    const switchId = Number(parameters['SwitchId'] || 1);
    const initialOpacity = Number(parameters['Opacity'] || 255);
    const columnCount = Number(parameters['ColumnCount'] || 1);
    const rowCount = Number(parameters['RowCount'] || 0);
    const layout = String(parameters['Layout'] || 'vertical');
    const commands = JSON.parse(parameters['Commands'] || '[]').map(command => {
        try {
            return JSON.parse(command);
        } catch (e) {
            console.error("Failed to parse command:", command);
            return null;
        }
    }).filter(command => command !== null);

    Game_System.prototype.customWindowOpacity = function() {
        if (this._customWindowOpacity === undefined) {
            this._customWindowOpacity = initialOpacity;
        }
        return this._customWindowOpacity;
    };

    Game_System.prototype.setCustomWindowOpacity = function(opacity) {
        this._customWindowOpacity = Math.max(0, Math.min(255, opacity));
    };

    function Window_CustomCommand() {
        this.initialize(...arguments);
    }

    Window_CustomCommand.prototype = Object.create(Window_Command.prototype);
    Window_CustomCommand.prototype.constructor = Window_CustomCommand;

    Window_CustomCommand.prototype.initialize = function(rect) {
        this._commandImages = [];
        this._customOpacity = $gameSystem.customWindowOpacity();
        this._isAdjustingSize = false;
        Window_Command.prototype.initialize.call(this, rect);
        this.updateCustomOpacity();
        this.loadCommandImages();
        this.deactivate();
    };

    Window_CustomCommand.prototype.loadCommandImages = function() {
        this._commandImages = commands.map(command => {
            if (command && command.Image) {
                const bitmap = ImageManager.loadSystem(command.Image);
                return { bitmap: bitmap, loaded: false };
            }
            return null;
        });
    };

    Window_CustomCommand.prototype.updateCommandImages = function() {
        let allLoaded = true;
        let needsRefresh = false;
        this._commandImages.forEach((img, index) => {
            if (img && !img.loaded && img.bitmap.isReady()) {
                img.loaded = true;
                needsRefresh = true;
            }
            if (img && !img.loaded) {
                allLoaded = false;
            }
        });
        if (allLoaded && !this._isAdjustingSize) {
            this._isAdjustingSize = true;
            this.adjustWindowSize();
        } else if (needsRefresh) {
            this.refresh();
        }
    };

    Window_CustomCommand.prototype.adjustWindowSize = function() {
        const maxWidth = this.calculateMaxWidth();
        const maxHeight = this.calculateMaxHeight();
        const newWidth = Math.max(windowWidth, maxWidth + this.padding * 2);
        const newHeight = Math.max(windowHeight, maxHeight + this.padding * 2);
        if (this.width !== newWidth || this.height !== newHeight) {
            this.width = newWidth;
            this.height = newHeight;
            this.createContents();
            this.refresh();
        }
        this._isAdjustingSize = false;
    };

    Window_CustomCommand.prototype.calculateMaxWidth = function() {
        const colCount = this.maxCols();
        let maxWidth = 0;
        for (let col = 0; col < colCount; col++) {
            maxWidth += this.getColumnWidth(col);
        }
        return maxWidth + (colCount - 1) * this.colSpacing();
    };

    Window_CustomCommand.prototype.calculateMaxHeight = function() {
        const rowCount = this.maxRows();
        let maxHeight = 0;
        for (let row = 0; row < rowCount; row++) {
            maxHeight += this.getRowHeight(row);
        }
        return maxHeight + (rowCount - 1) * this.rowSpacing();
    };

    Window_CustomCommand.prototype.makeCommandList = function() {
        commands.forEach((command, index) => {
            if (command && command.Name && this.isCommandVisible(command)) {
                this.addCommand(command.Name, 'custom_' + index, true);
            }
        });
    };

    Window_CustomCommand.prototype.isCommandVisible = function(command) {
        return !command.SwitchId || $gameSwitches.value(Number(command.SwitchId));
    };

    Window_CustomCommand.prototype.itemRect = function(index) {
        if (!this._commandImages || index < 0 || index >= this._commandImages.length) {
            return Window_Command.prototype.itemRect.call(this, index);
        }
        
        const img = this._commandImages[index];
        if (img && img.loaded) {
            const itemWidth = img.bitmap.width;
            const itemHeight = img.bitmap.height;
            const colSpacing = this.colSpacing();
            const rowSpacing = this.rowSpacing();
            const col = layout === 'horizontal' ? index % this.maxCols() : Math.floor(index / this.maxRows());
            const row = layout === 'horizontal' ? Math.floor(index / this.maxCols()) : index % this.maxRows();
            let x = 0;
            let y = 0;

            for (let i = 0; i < col; i++) {
                x += this.getColumnWidth(i) + colSpacing;
            }
            for (let i = 0; i < row; i++) {
                y += this.getRowHeight(i) + rowSpacing;
            }

            return new Rectangle(x, y, itemWidth, itemHeight);
        } else {
            return Window_Command.prototype.itemRect.call(this, index);
        }
    };

    Window_CustomCommand.prototype.getColumnWidth = function(col) {
        let maxWidth = 0;
        for (let row = 0; row < this.maxRows(); row++) {
            const index = row * this.maxCols() + col;
            if (index < this._commandImages.length) {
                const img = this._commandImages[index];
                if (img && img.loaded) {
                    maxWidth = Math.max(maxWidth, img.bitmap.width);
                }
            }
        }
        return maxWidth || Window_Command.prototype.itemWidth.call(this);
    };

    Window_CustomCommand.prototype.getRowHeight = function(row) {
        let maxHeight = 0;
        for (let col = 0; col < this.maxCols(); col++) {
            const index = row * this.maxCols() + col;
            if (index < this._commandImages.length) {
                const img = this._commandImages[index];
                if (img && img.loaded) {
                    maxHeight = Math.max(maxHeight, img.bitmap.height);
                }
            }
        }
        return maxHeight || Window_Command.prototype.itemHeight.call(this);
    };

    Window_CustomCommand.prototype.drawItem = function(index) {
        const img = this._commandImages[index];
        if (img && img.loaded) {
            const rect = this.itemRect(index);
            this.contents.blt(img.bitmap, 0, 0, img.bitmap.width, img.bitmap.height, rect.x, rect.y);
        } else {
            Window_Command.prototype.drawItem.call(this, index);
        }
    };

    Window_CustomCommand.prototype.updateCustomOpacity = function() {
        this.opacity = this._customOpacity;
        this.contentsOpacity = 255;  // 常に255に設定して画像を表示
    };

    Window_CustomCommand.prototype.update = function() {
        Window_Command.prototype.update.call(this);
        if (this._customOpacity !== $gameSystem.customWindowOpacity()) {
            this._customOpacity = $gameSystem.customWindowOpacity();
            this.updateCustomOpacity();
        }
        this.updateCommandImages();
        if (this._needsRefresh) {
            this.refresh();
            this._needsRefresh = false;
        }
    };

    Window_CustomCommand.prototype.maxCols = function() {
        if (this._list === undefined) return 1;
        return layout === 'horizontal' ? (columnCount || this.maxItems()) : (rowCount > 0 ? Math.ceil(this.maxItems() / rowCount) : 1);
    };

    Window_CustomCommand.prototype.maxRows = function() {
        if (this._list === undefined) return 1;
        return layout === 'vertical' ? (rowCount || this.maxItems()) : (columnCount > 0 ? Math.ceil(this.maxItems() / columnCount) : 1);
    };

    Window_CustomCommand.prototype.itemWidth = function() {
        return this.getColumnWidth(0);
    };

    Window_CustomCommand.prototype.itemHeight = function() {
        return this.getRowHeight(0);
    };

    // 背景を描画しないようにオーバーライド
    Window_CustomCommand.prototype.drawBackgroundRect = function(rect) {
        // 何もしない
    };

    const _Scene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;
    Scene_Map.prototype.createAllWindows = function() {
        _Scene_Map_createAllWindows.call(this);
        this.createCustomCommandWindow();
    };

    Scene_Map.prototype.createCustomCommandWindow = function() {
        const rect = new Rectangle(windowX, windowY, windowWidth, windowHeight);
        this._customCommandWindow = new Window_CustomCommand(rect);
        commands.forEach((command, index) => {
            if (command && command.CommonEventId) {
                this._customCommandWindow.setHandler('custom_' + index, this.onCustomCommand.bind(this, index));
            }
        });
        this.addWindow(this._customCommandWindow);
        this._customCommandWindow.hide();
    };

    const _Scene_Map_update = Scene_Map.prototype.update;
    Scene_Map.prototype.update = function() {
        _Scene_Map_update.call(this);
        this.updateCustomCommandWindow();
    };

    Scene_Map.prototype.updateCustomCommandWindow = function() {
        if ($gameSwitches.value(switchId)) {
            if (!this._customCommandWindow.visible) {
                this._customCommandWindow.show();
                this._customCommandWindow.activate();
                this._customCommandWindow.select(0);
            }
            this._customCommandWindow._needsRefresh = true;
        } else {
            if (this._customCommandWindow.visible) {
                this._customCommandWindow.hide();
                this._customCommandWindow.deactivate();
            }
        }
    };

    Scene_Map.prototype.onCustomCommand = function(index) {
        const command = commands[index];
        if (command && command.CommonEventId) {
            $gameTemp.reserveCommonEvent(Number(command.CommonEventId));
        }
        this._customCommandWindow.activate();
    };

    const _Scene_Map_processMapTouch = Scene_Map.prototype.processMapTouch;
    Scene_Map.prototype.processMapTouch = function() {
        if (this._customCommandWindow && this._customCommandWindow.visible) {
            if (TouchInput.isTriggered() && this._customCommandWindow.isTouchedInsideFrame()) {
                this._customCommandWindow.activate();
            }
        } else {
            _Scene_Map_processMapTouch.call(this);
        }
    };

    const _Game_Player_canMove = Game_Player.prototype.canMove;
    Game_Player.prototype.canMove = function() {
        if (SceneManager._scene instanceof Scene_Map) {
            const customWindow = SceneManager._scene._customCommandWindow;
            if (customWindow && customWindow.visible && customWindow.active) {
                return false;
            }
        }
        return _Game_Player_canMove.call(this);
    };

    const _Game_Switches_onChange = Game_Switches.prototype.onChange;
    Game_Switches.prototype.onChange = function() {
        _Game_Switches_onChange.call(this);
        if (SceneManager._scene instanceof Scene_Map && SceneManager._scene._customCommandWindow) {
            SceneManager._scene._customCommandWindow._needsRefresh = true;
        }
    };
})();