/*:
 * @target MZ
 * @author Aerosys
 * @plugindesc [Tier 1] [Version 1.0.1] [MV & MZ]
 * 
 * @help
 * 
 * ----------------------------------------------------------------------------
 * Rules
 * ----------------------------------------------------------------------------
 * 1. This Plugin is free of charge and can be used in any kind of game.
 * 
 * 2. You may not redistribute this Plugin or claim it as your own.
 *    
 *    a) Exception: You may redistribute this plugin as part of your game when
 *       releasing it.
 *    b) Exception: You may send this plugin to another person when you hire
 *       them for personal modifications.
 * 
 * 3. You may modify this plugin's source code for your needs but cannot
 *    redistribute your modifications.
 * 
 * 4. You may create plugins based on this (e.g. addon or extension) for your
 *    needs but you cannot redistribute them.
 * 
 * 
 * ----------------------------------------------------------------------------
 * Notetags
 * ----------------------------------------------------------------------------
 * 
 * <Cannot Store>
 * - can be applied on Items and Equipment
 * - This item cannot be stored in the warehouse
 * 
 * <Warehouse Stack Size: x>
 * - can be applied on Items and Equipment
 * - Sets the Stack Size of this Item to x in the warehouse
 * 
 * 
 * ----------------------------------------------------------------------------
 * JavaScript
 * ----------------------------------------------------------------------------
 * 
 * You can call these scripts anytime:
 * 
 * MK.Warehouse.open()
 * - Opens the Warehouse
 * 
 * 
 * MK.Warehouse.open(true)
 * - Opens the Warehouse and allows gold transfer
 * 
 * 
 * MK.Warehouse.open(false)
 * - Opens the Warehouse and doesn't allow gold transfer
 * 
 * 
 * MK.Warehouse.storeItem(item, amount)
 * - Immediately stores the given item to the Warehouse, regardless if the
 *   Warehouse is opened or not
 * 
 * Example:
 * MK.Warehouse.storeItem($dataWeapons[5], 1)
 * - stores Weapon with ID 5
 * 
 * 
 * MK.Warehouse.takeItem(item, amount)
 * - Immediately takes the given item from the Warehouse, regardless if the
 *   Warehouse is opened or not
 * 
 * Example:
 * MK.Warehouse.takeItem($dataItems[1], 5)
 * - takes 5x Items with ID 1
 * 
 * 
 * MK.Warehouse.isStorable(item)
 * - Returns true if the given Item is storable.
 * - It doesn't check whether the given Item is storable RIGHT NOW, so when
 *   your Warehouse is full, it may still return true
 * 
 * Example:
 * MK.Warehouse.isStorable($dataItems[1])
 * 
 * 
 * MK.Warehouse.isStorableRightNow(item)
 * - Returns true if the given Item is storable right now
 * - Also checks if the given Item is storable RIGHT NOW, so when your
 *   Warehouse is full, this function returns false
 * 
 * Example:
 * MK.Warehouse.isStorableRightNow($dataItems[1])
 * 
 * 
 * MK.Warehouse.numItems(item)
 * - Returns the stack size of the given Item
 * 
 * Example:
 * MK.Warehouse.numItems($dataItems[1])
 * - Returns the amount of Item with ID 1
 * 
 * 
 * MK.Warehouse.saveGold(amount)
 * - Immediately puts gold to the Warehouse
 * 
 * 
 * MK.Warehouse.takeGold(amount)
 * - Immediately takes gold from the Warehouse
 * 
 * 
 * @endofhelp
 * 
 * @command open
 * @text Open Warehouse
 * 
 * @arg enableGoldTransfer
 * @text Enable Gold Transfer?
 * @type select
 * @option Default
 * @option Yes
 * @option No
 * @default Default
 * 
 * 
 * @command storeTakeItem
 * @text Store/Take Item
 * 
 * @arg action
 * @text Action
 * @type select
 * @option Store
 * @option Take
 * @default Store
 * 
 * @arg item
 * @text Item
 * @type item
 * @default 1
 * 
 * @arg amountParent
 * @text Amount
 * 
 * @arg mode
 * @parent amountParent
 * @text Number?
 * @type select
 * @option fixed
 * @option by Variable
 * @default fixed
 * 
 * @arg amount
 * @parent amountParent
 * @text when fixed:
 * @type number
 * @default 1
 * 
 * @arg variableId
 * @parent amountParent
 * @text when by Variable:
 * @type variable
 * 
 * 
 * @command storeTakeWeapon
 * @text Store/Take Weapon
 * 
 * @arg action
 * @text Action
 * @type select
 * @option Store
 * @option Take
 * @default Store
 * 
 * @arg weapon
 * @text Weapon
 * @type weapon
 * @default 1
 * 
 * @arg amountParent
 * @text Amount
 * 
 * @arg mode
 * @parent amountParent
 * @text Number?
 * @type select
 * @option fixed
 * @option by Variable
 * @default fixed
 * 
 * @arg amount
 * @parent amountParent
 * @text when fixed:
 * @type number
 * @default 1
 * 
 * @arg variableId
 * @parent amountParent
 * @text when by Variable:
 * @type variable
 * 
 * 
 * @command storeTakeArmor
 * @text Store/Take Armor
 * 
 * @arg action
 * @text Action
 * @type select
 * @option Store
 * @option Take
 * @default Store
 * 
 * @arg armor
 * @text Armor
 * @type armor
 * @default 1
 * 
 * @arg amountParent
 * @text Amount
 * 
 * @arg mode
 * @parent amountParent
 * @text Number?
 * @type select
 * @option fixed
 * @option by Variable
 * @default fixed
 * 
 * @arg amount
 * @parent amountParent
 * @text when fixed:
 * @type number
 * @default 1
 * 
 * @arg variableId
 * @parent amountParent
 * @text when by Variable:
 * @type variable
 * 
 * 
 * @param gameplay
 * @text Gameplay
 * 
 * 
 * @param items
 * @parent gameplay
 * @text Items
 * 
 * 
 * @param canStoreItems
 * @parent items
 * @text can store Items?
 * @type boolean
 * @default true
 * 
 * @param canStoreKeyItems
 * @parent items
 * @text can store Key Items?
 * @type boolean
 * @default true
 * 
 * @param canStoreWeapons
 * @parent items
 * @text can store Weapons?
 * @type boolean
 * @default true
 * 
 * @param canStoreArmors
 * @parent items
 * @text can store Armors?
 * @type boolean
 * @default true
 * 
 * @param stackSizes
 * @parent gameplay
 * @text Stack Sizes
 * 
 * @param itemStackSize
 * @parent stackSizes
 * @text Items
 * @type number
 * @default 99
 * 
 * @param keyItemStackSize
 * @parent stackSizes
 * @text Key Items
 * @type number
 * @default 1
 * 
 * @param weaponStackSize
 * @parent stackSizes
 * @text Weapons
 * @type number
 * @default 99
 * 
 * @param armorStackSize
 * @parent stackSizes
 * @text Armors
 * @type number
 * @default 99
 * 
 * @param gold
 * @parent gameplay
 * @text Gold
 * 
 * @param enableGoldTransfer
 * @parent gold
 * @text Enable Gold Transfer?
 * @type boolean
 * @default true
 * @desc This is a default setting. You can override in anytime.
 * 
 * @param maxGold
 * @parent gold
 * @text Maximum
 * @type number
 * @default 999999
 * 
 * 
 * @param a
 * @text _
 * 
 * 
 * @param ui
 * @text UI
 * 
 * @param goldIcon
 * @parent ui
 * @text Gold Icon
 * @type icon
 * @default 314
 * @desc Used when Visustella enables Icons
 * 
 * 
 * @param b
 * @text _
 * 
 * 
 * @param audio
 * @text Audio / Sound Effects
 * 
 * @param storeItemSE
 * @parent audio
 * @text Store Item
 * @type file
 * @dir audio/se
 * @require 1
 * @default Equip2
 * 
 * @param takeItemSE
 * @parent audio
 * @text Take Item
 * @type file
 * @dir audio/se
 * @require 1
 * @default Equip1
 * 
 * @param saveGoldSE
 * @parent audio
 * @text Deposit Gold
 * @type file
 * @dir audio/se
 * @require 1
 * @default Coin
 * 
 * @param takeGoldSE
 * @parent audio
 * @text Take Gold
 * @type file
 * @dir audio/se
 * @require 1
 * @default Coin
 * 
 * 
 * @param c
 * @text _
 * 
 * 
 * @param Vocabulary
 * @text Vocabulary
 * @type struct<Vocabulary>
 * @default {"inventoryHeader":"Inventory","warehouseHeader":"Warehouse","storeItem":"Store %1","takeItem":"Take %1","gold":"Gold","goldInInventory":"%1\\G in Inventory","goldInWarehouse":"%1\\G in Warehouse","saveGold":"Deposit","takeGold":"Take","cancelGoldTransfer":"Cancel"}
 *
 */

/*~struct~Vocabulary:
 * 
 * @param inventoryHeader
 * @text Inventory Headline
 * @default Inventory
 * 
 * @param warehouseHeader
 * @text Warehouse Headline
 * @default Warehouse
 * 
 * @param storeItem
 * @text Store
 * @default Store %1
 * @desc Use %1 to display the Item Name
 * 
 * @param takeItem
 * @text Take
 * @default Take %1
 * @desc Use %1 to display the Item Name
 * 
 * @param gold
 * @text Gold (Transfer)
 * @default Gold
 * 
 * @param goldInInventory
 * @text Gold in Inventory
 * @default %1\G in Inventory
 * @desc Use %1 to display value; \G for currency unit
 * 
 * @param goldInWarehouse
 * @text Gold in Warehouse
 * @default %1\G in Warehouse
 * @desc Use %1 to display value; \G for currency unit
 * 
 * @param saveGold
 * @text Deposit Gold
 * @default Deposit
 * 
 * @param takeGold
 * @text Take Gold
 * @default Take
 * 
 * @param cancelGoldTransfer
 * @text Cancel Gold Transfer
 * @default Cancel
 * 
 */


var Imported = Imported || { };
var MK = MK || { };
MK.Warehouse = { };


(function() {

const PLUGIN_NAME = 'MK_Warehouse';
const MV_support = true;
const MZ_support = true;

const reject = (reason) => {
    const message = (
        "An Error has occurred in the Plugin %1: %2 " +
        "If the problem persists, contact the Plugin Creator."
    ).format(PLUGIN_NAME, reason);
    throw Error(message);
}

if ('MV' == Utils.RPGMAKER_NAME && !MV_support) {
    reject("This plugin supports RPG Maker MZ only.");
}
if ('MZ' == Utils.RPGMAKER_NAME && !MZ_support) {
    reject("This plugin supports RPG Maker MV only.");
}

if (!PluginManager._parameters[PLUGIN_NAME.toLowerCase()]) {
    reject((
        "Please check that this plugin's filename is \"%1.js\". " +
        "Subdirectories (e.g.: js/plugins/xy/thisPlugin.js) are not allowed."
    ).format(PLUGIN_NAME));
}

const structure = (serialized, parameterName) => {
    if (!serialized) {
        reject((
            "The Plugin Parameter \"%1\" is missing. " +
            "Please check it in the Plugin Manager. It may help to re-install this Plugin (i.e.: remove, re-add)."
        ).format(parameterName));
    }
    try {
        return JSON.parse(serialized);
    
    } catch (e) {
        reject((
            "The Plugin Parameter \"%1\" is corrupted. " +
            "Please check it in the Plugin Manager. It may help to re-install this Plugin (i.e.: remove, re-add)."
        ).format(parameterName));
    }
}

const customFunction = (body, parameterName) => {
    if (!body) {
        reject((
            "The Plugin Parameter \"%1\" is missing. " +
            "Please check it in the Plugin Manager. It may help to re-install this Plugin (i.e.: remove, re-add)."
        ).format(parameterName));
    }
    try {
        return new Function(JSON.parse(body));
    
    } catch (e) {
        reject((
            "The Plugin Parameter \"%1\" contains an error and could not be interpreted. " +
            "Please check it in the Plugin Manager. It may also help to re-install this Plugin (i.e.: remove, re-add). " +
            "Cause: %2"
        ).format(parameterName, e));
    }
}

const params = PluginManager.parameters(PLUGIN_NAME);

// gameplay
MK.Warehouse.canStoreItems          = 'true' == params.canStoreItems;
MK.Warehouse.canStoreKeyItems       = 'true' == params.canStoreKeyItems;
MK.Warehouse.canStoreWeapons        = 'true' == params.canStoreWeapons;
MK.Warehouse.canStoreArmors         = 'true' == params.canStoreArmors;

// inidividual stacks
MK.Warehouse.itemStackSize          = Number(params.itemStackSize);
MK.Warehouse.keyItemStackSize       = Number(params.keyItemStackSize);
MK.Warehouse.weaponStackSize        = Number(params.weaponStackSize);
MK.Warehouse.armorStackSize         = Number(params.armorStackSize);

// gold
MK.Warehouse.enableGoldTransfer     = 'true' == params.enableGoldTransfer;
MK.Warehouse.maxGold                = Number(params.maxGold);
MK.Warehouse.goldIcon               = Number(params.goldIcon);

// audio
MK.Warehouse.storeItemSE            = params.storeItemSE;
MK.Warehouse.takeItemSE             = params.takeItemSE;
MK.Warehouse.saveGoldSE             = params.saveGoldSE;
MK.Warehouse.takeGoldSE             = params.takeGoldSE;

// vocabulary
MK.Warehouse.Vocabulary             = structure(params.Vocabulary, 'Vocabulary');


const calcWindowHeight = (nLines) =>
    'MZ' == Utils.RPGMAKER_NAME
        ? Scene_Base.prototype.calcWindowHeight(nLines, true)
        : new Window_Base(0, 0, 0, 0).fittingHeight(nLines);

const playSE = (seName) => {
    if (seName) {
        AudioManager.playSe({
            name: seName,
            volume: 100,
            pitch: 100,
            pan: 0,
        });
    }
}


// =====================================================================================
// Window Category
// =====================================================================================

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

Window_Warehouse_Category.prototype = Object.create(Window_ItemCategory.prototype);
Window_Warehouse_Category.prototype.constructor = Window_Warehouse_Category;

Window_Warehouse_Category.prototype.makeCommandList = function() {
    Window_ItemCategory.prototype.makeCommandList.call(this);

    if (SceneManager._scene._enableGoldTransfer) {
        const goldCommand = this.goldCommandText();
        this.addCommand(goldCommand, 'gold', true, 'gold');
    }
}

Window_Warehouse_Category.prototype.goldCommandText = function() {
    return (
        Imported.VisuMZ_1_ItemsEquipsCore
            ? '\\I[%1]'.format(MK.Warehouse.goldIcon)
            : ''
    ) + MK.Warehouse.Vocabulary.gold;
}

Window_Warehouse_Category.prototype.maxCols = function() {
    return this._list ? this._list.length : 1;
}

Window_Warehouse_Category.prototype.update = function() {
    Window_ItemCategory.prototype.update.call(this);

    if (this._lastSymbol && this._lastSymbol != this.currentSymbol() && this.onSelectionChange) {
        this.onSelectionChange();
    }
    this._lastSymbol = this.currentSymbol();
}


// =====================================================================================
// Window Warehouse Inventory List
// =====================================================================================

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

Window_Inventory_List.prototype = Object.create(Window_ItemList.prototype);
Window_Inventory_List.prototype.constructor = Window_Inventory_List;

Window_Inventory_List.prototype.isEnabled = function(item) {
    return MK.Warehouse.isStorableRightNow(item);
}

Window_Inventory_List.prototype.update = function() {
    Window_ItemList.prototype.update.call(this);

    this.updateOnSelectionChange();
    this.updateLeftRightButtons();
    this.updateTouchControls();
}

Window_Inventory_List.prototype.updateOnSelectionChange = function() {
    if (this._lastItem != this.item() && this.onSelectionChange) {
        this.onSelectionChange();
    }
    this._lastItem = this.item(); 
}

Window_Inventory_List.prototype.updateLeftRightButtons = function() {
    if (this.isOpenAndActive()) {
        if (Input.isRepeated('right')) this.callHandler('right');
        if (Input.isRepeated('left')) this.callHandler('left');
    }
}

Window_Inventory_List.prototype.updateTouchControls = function() {
    if ('MZ' == Utils.RPGMAKER_NAME) {
        const hitIndex = this.hitIndex();
        if (hitIndex != this._lastHitIndex) {
            this._lastHitIndex = hitIndex;

            if (hitIndex >= 0 && this.onHover) {
                this.onHover.call(this);
            }
        }
    }
}

Window_Inventory_List.prototype.drawItemNumber = function(item, x, y, width) {
    if (this.needsNumber(item)) {
        this.drawText(":", x, y, width - this.textWidth('00'), 'right');
        this.drawText(this.number(item), x, y, width, 'right');
    }
}

Window_Inventory_List.prototype.number = function(item) {
    return $gameParty.numItems(item);
}

Window_Inventory_List.prototype.needsNumber = function(item) {
    return (
        Window_ItemList.prototype.needsNumber.apply(this, arguments) ||
        ($gameParty.numItems(item) + MK.Warehouse.numItems(item)) > 1
    );
}

// auto-refresh window on the right
Window_Inventory_List.prototype.setCategory = function(category) {
    Window_ItemList.prototype.setCategory.call(this, category);

    SceneManager._scene._warehouseWindow.setCategory(category);
}

Window_Inventory_List.prototype.maxCols = function() {
    return 1;
}

Window_Inventory_List.prototype.playOkSound = function() {
    //
}


// =====================================================================================
// Window Warehouse List
// =====================================================================================

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

Window_Warehouse_List.prototype = Object.create(Window_Inventory_List.prototype);
Window_Warehouse_List.prototype.constructor = Window_Warehouse_List;

Window_Warehouse_List.prototype.makeItemList = function() {
    this._data = MK.Warehouse.allSavedItems().filter(this.includes.bind(this));
}

Window_Warehouse_List.prototype.isEnabled = function(item) {
    return $gameParty.numItems(item) < $gameParty.maxItems(item);
}

Window_Warehouse_List.prototype.needsNumber = function(item) {
    return Window_Inventory_List.prototype.needsNumber.call(this, item);
}

Window_Warehouse_List.prototype.number = function(item) {
    return MK.Warehouse.numItems(item);
}

// auto-refresh window on the right
Window_Warehouse_List.prototype.setCategory = function(category) {
    Window_ItemList.prototype.setCategory.call(this, category);
}


// =====================================================================================
// Window Gold
// =====================================================================================

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

Window_Warehouse_Gold.prototype = Object.create(Window_Base.prototype);
Window_Warehouse_Gold.prototype.constructor = Window_Warehouse_Gold;

Window_Warehouse_Gold.prototype.createContents = function() {
    Window_Base.prototype.createContents.call(this);

    const text1 = MK.Warehouse.Vocabulary.goldInInventory
        .format($gameParty.gold())
        .replace('\\G', TextManager.currencyUnit);
    
    const text2 = MK.Warehouse.Vocabulary.goldInWarehouse
        .format($gameParty.savedGold())
        .replace('\\G', TextManager.currencyUnit);

    this.drawText(text1, 0, 1 * this.lineHeight(), this.contentsWidth(), 'center');
    this.drawText(text2, 0, 2 * this.lineHeight(), this.contentsWidth(), 'center');
}

Window_Warehouse_Gold.prototype.refresh = function() {
    this.createContents();
}


// =====================================================================================
// Window Gold Command
// =====================================================================================

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

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

Window_Warehouse_GoldCommand.prototype.makeCommandList = function() {
    this.addCommand(MK.Warehouse.Vocabulary.saveGold, 'save', $gameParty.gold() > 0);
    this.addCommand(MK.Warehouse.Vocabulary.takeGold, 'take', $gameParty.savedGold() > 0);
    this.addCommand(MK.Warehouse.Vocabulary.cancelGoldTransfer, 'cancel');
}


// =====================================================================================
// Window Transfer
// =====================================================================================

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

Window_Item_Transfer.prototype = Object.create(Window_Selectable.prototype);
Window_Item_Transfer.prototype.constructor = Window_Item_Transfer;

Window_Item_Transfer.prototype.initialize = function() {
    Window_Selectable.prototype.initialize.apply(this, arguments);
    
    this._mode = 'none';
    this._number = 1;
    this.createButtons();
    this.select(0);
}

Window_Item_Transfer.prototype.setup = function(mode, item, maxAmount) {
    this._mode = mode;
    this._item = item;
    this._maxAmount = maxAmount;
    this._maxDigits = String(MK.Warehouse.stackSize(item)).length;
    this._number = 1;
    
    this.placeButtons();
    this.updateButtonsVisiblity();
    this.refresh();
}

Window_Item_Transfer.prototype.createButtons = function() {
    Window_ShopNumber.prototype.createButtons.call(this);
}

Window_Item_Transfer.prototype.placeButtons = function() {
    Window_ShopNumber.prototype.placeButtons.call(this);
}

Window_Item_Transfer.prototype.buttonTypes = function() {
    return ['down2', 'down', 'up', 'up2', 'ok'];
}

Window_Item_Transfer.prototype.buttonSpacing = function() {
    return 8;
}

Window_Item_Transfer.prototype.buttonY = function() {
    return this.height - (2 * this.padding) - this._buttons[0].height;
}

Window_Item_Transfer.prototype.totalButtonWidth = function() {
    return Window_ShopNumber.prototype.totalButtonWidth.call(this);
}

Window_Item_Transfer.prototype.onButtonDown2 = function() {
    this.changeNumber(-10);
}

Window_Item_Transfer.prototype.onButtonDown = function() {
    this.changeNumber(-1);
}

Window_Item_Transfer.prototype.onButtonUp = function() {
    this.changeNumber(1);
}

Window_Item_Transfer.prototype.onButtonUp2 = function() {
    this.changeNumber(10);
}

Window_Item_Transfer.prototype.onButtonOk = function() {
    this.processOk();
}

Window_Item_Transfer.prototype.refresh = function() {
    Window_Selectable.prototype.refresh.call(this);

    this.drawText(this.text(), 0, 0, this.contentsWidth(), 'center');
    this.drawDigits();
}

Window_Item_Transfer.prototype.text = function() {
    return this._mode == 'store' || this._mode == 'take'
        ? MK.Warehouse.Vocabulary[this._mode + 'Item'].format(this.itemName())
        : '';
}

Window_Item_Transfer.prototype.drawDigits = function() {
    for (let i = 0; i < this.maxDigits(); i++) {
        this.drawDigit(i);
    }
}

Window_Item_Transfer.prototype.drawDigit = function(index) {
    const rectangle = this.digitRect(index);
    const c = this._number.padZero(this.maxDigits()).slice(index, index + 1);
    this.drawText(c, rectangle.x, rectangle.y, rectangle.width, 'center');
}

Window_Item_Transfer.prototype.itemRect = function(/* index */) {
    const width = this.maxDigits() * (this.digitWidth() + this.itemPadding()) + this.itemPadding();
    const height = this.lineHeight();
    const x = Math.floor((this.width / 2) - (width / 2)) - 10; // TODO ??
    const y = this.numberY();
    return new Rectangle(x, y, width, height);
}

Window_Item_Transfer.prototype.digitRect = function(index) {
    return new Rectangle(
        index * (this.digitWidth() + this.itemPadding()) + this.itemPadding() + this.itemRect().x,
        this.numberY(),
        this.digitWidth(),
        this.lineHeight(),
    );
}

Window_Item_Transfer.prototype.cursorWidth = function() {
    return (this.maxDigits() * (this.digitWidth() + this.itemPadding())) + this.itemPadding();
}

Window_Item_Transfer.prototype.numberY = function() {
    return this.height / 2 - this.lineHeight();
}

Window_Item_Transfer.prototype.digitWidth = function() {
    return this.textWidth('0');
}

Window_Item_Transfer.prototype.update = function() {
    Window_Selectable.prototype.update.call(this);
    
    if (this.isOpenAndActive()) {
        if (Input.isRepeated('right'))  this.changeNumber(1);
        if (Input.isRepeated('left'))   this.changeNumber(-1);
        if (Input.isRepeated('up'))     this.changeNumber(10);
        if (Input.isRepeated('down'))   this.changeNumber(-10);
    }
}

Window_Item_Transfer.prototype.updateButtonsVisiblity = function() {
    if (Window_ShopNumber.prototype.updateButtonsVisiblity) {
        Window_ShopNumber.prototype.updateButtonsVisiblity.call(this);
    }
}

Window_Item_Transfer.prototype.showButtons = function() {
    Window_ShopNumber.prototype.showButtons.call(this);
}

Window_Item_Transfer.prototype.hideButtons = function() {
    Window_ShopNumber.prototype.hideButtons.call(this);
}

Window_Item_Transfer.prototype.number = function() {
    return this._number;
}

Window_Item_Transfer.prototype.changeNumber = function(delta) {
    const lastNumber = this._number;
    this._number = (this._number + delta).clamp(1, this._maxAmount);
    if (this._number != lastNumber) {
        SoundManager.playCursor();
        this.refresh();
    }
}

Window_Item_Transfer.prototype.item = function() {
    return this._item;
}

Window_Item_Transfer.prototype.itemName = function() {
    return this._item ? this._item.name : undefined;
}

Window_Item_Transfer.prototype.mode = function() {
    return this._mode;
}

Window_Item_Transfer.prototype.maxDigits = function() {
    return this._maxDigits;
}

Window_Item_Transfer.prototype.itemPadding = function() {
    return Window_Base.prototype.itemPadding
        ? Window_Base.prototype.itemPadding.call(this)
        : Window_Base.prototype.textPadding.call(this);
}

Window_Item_Transfer.prototype.playOkSound = function() {
    //
}


// =====================================================================================
// Window Gold Transfer
// =====================================================================================

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

Window_Gold_Transfer.prototype = Object.create(Window_Selectable.prototype);
Window_Gold_Transfer.prototype.constructor = Window_Gold_Transfer;

Window_Gold_Transfer.prototype.initialize = function() {
    Window_Selectable.prototype.initialize.apply(this, arguments);
    this._number = 1;
    this.createButtons();
}

Window_Gold_Transfer.prototype.createButtons = function() {
    Window_NumberInput.prototype.createButtons.call(this);
}

Window_Gold_Transfer.prototype.placeButtons = function() {
    Window_NumberInput.prototype.placeButtons.call(this);
}

Window_Gold_Transfer.prototype.buttonTypes = function() {
    return ["down", "up", "ok"];
}

Window_Gold_Transfer.prototype.onButtonDown = function() {
    this.digitDown();
}

Window_Gold_Transfer.prototype.onButtonUp = function() {
    this.digitUp();
}

Window_Gold_Transfer.prototype.onButtonOk = function() {
    this.processOk();
}

Window_Gold_Transfer.prototype.buttonSpacing = function() {
    return 8;
}

Window_Gold_Transfer.prototype.buttonY = function() {
    return Window_Item_Transfer.prototype.buttonY.call(this);
}

Window_Gold_Transfer.prototype.totalButtonWidth = function() {
    return Window_Item_Transfer.prototype.totalButtonWidth.call(this);
}

Window_Gold_Transfer.prototype.setup = function(mode, maxAmount) {
    this._mode = mode;
    this._maxAmount = maxAmount;
    this._maxDigits = String(maxAmount).length;
    this._number = 1;
    this.select(this._maxDigits - 1);
    this.placeButtons();
    this.updateButtonsVisiblity();
    this.refresh();
}

Window_Gold_Transfer.prototype.refresh = function() {
    Window_Selectable.prototype.refresh.call(this);

    for (let index = 0; index < this.maxDigits(); index++) {
        const digit = this.number().padZero(this.maxDigits()).charAt(index);
        const rect = this.itemRect(index);
        this.drawText(
            digit,
            rect.x,
            rect.y,
            rect.width,
            'center',
        );
    }
}

Window_Gold_Transfer.prototype.update = function() {
    Window_Selectable.prototype.update.call(this);

    if (this.isOpenAndActive()) {
        if (Input.isRepeated('up')) this.digitUp();
        if (Input.isRepeated('down')) this.digitDown();
    }
}

Window_Gold_Transfer.prototype.digitUp = function() {
    Window_NumberInput.prototype.changeDigit.call(this, true);
}

Window_Gold_Transfer.prototype.digitDown = function() {
    Window_NumberInput.prototype.changeDigit.call(this, false);
}

Window_Gold_Transfer.prototype.number = function() {
    return this._number;
}

Window_Gold_Transfer.prototype.setNumber = function(number) {
    this._number = number;
    this.refresh();
}

Window_Gold_Transfer.prototype.mode = function() {
    return this._mode;
}

Window_Gold_Transfer.prototype.maxDigits = function() {
    return this._maxDigits;
}

Window_Gold_Transfer.prototype.maxItems = function() {
    return this.maxDigits();
}

Window_Gold_Transfer.prototype.maxCols = function() {
    return this.maxDigits();
}

Window_Gold_Transfer.prototype.isHorizontal = function() {
    return true;
}

Window_Gold_Transfer.prototype.playOkSound = function() {
    //
}

Window_Gold_Transfer.prototype.isTouchOkEnabled = function() {
    return false;
}

Window_Gold_Transfer.prototype.updateButtonsVisiblity = function() {
    if (Window_NumberInput.prototype.updateButtonsVisiblity) {
        Window_NumberInput.prototype.updateButtonsVisiblity.call(this);
    }
}

Window_Gold_Transfer.prototype.showButtons = function() {
    Window_NumberInput.prototype.showButtons.call(this);
}

Window_Gold_Transfer.prototype.hideButtons = function() {
    Window_NumberInput.prototype.hideButtons.call(this);
}


// =====================================================================================
// Window Inventory Header
// =====================================================================================

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

Window_Inventory_Header.prototype = Object.create(Window_Base.prototype);
Window_Inventory_Header.prototype.constructor = Window_Inventory_Header;

Window_Inventory_Header.prototype.initialize = function() {
    Window_Base.prototype.initialize.apply(this, arguments);

    const systemColor = 'MZ' == Utils.RPGMAKER_NAME
        ? ColorManager.systemColor()
        : this.systemColor();
    
    this.changeTextColor(systemColor);
    this.drawText(this.title(), 0, 4, this.contentsWidth(), 'center');
    this.resetTextColor();
}

Window_Inventory_Header.prototype.title = function() {
    return MK.Warehouse.Vocabulary.inventoryHeader;
}


// =====================================================================================
// Window Warehouse Header
// =====================================================================================

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

Window_Warehouse_Header.prototype = Object.create(Window_Inventory_Header.prototype);
Window_Warehouse_Header.prototype.constructor = Window_Warehouse_Header;

Window_Warehouse_Header.prototype.initialize = function() {
    Window_Inventory_Header.prototype.initialize.apply(this, arguments);
}

Window_Warehouse_Header.prototype.title = function() {
    return MK.Warehouse.Vocabulary.warehouseHeader;
}


// =====================================================================================
// Scene Warehouse
// =====================================================================================

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

Scene_Warehouse.prototype = Object.create(Scene_MenuBase.prototype);
Scene_Warehouse.prototype.constructor = Scene_Warehouse;

Scene_Warehouse.prototype.prepare = function(enableGoldTransfer) {
    this._enableGoldTransfer = enableGoldTransfer;
}

Scene_Warehouse.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);

    this.createHelpWindow();
    this.createCategoryWindow();
    this.createHeaderWindows();
    this.createItemListWindow();
    this.createWarehouseListWindow();
    this.createGoldWindow();
    this.createGoldCommandWindow();
    this.createTransferItemWindow();
    this.createTransferGoldWindow();

    this._categoryWindow.setItemWindow(this._itemListWindow);
    this._itemListWindow.createContents();
}

Scene_Warehouse.prototype.createCategoryWindow = function() {
    const rectangle = this.categoryWindowRectangle();
    if ('MZ' == Utils.RPGMAKER_NAME) {
        this._categoryWindow = new Window_Warehouse_Category(rectangle);
    } else {
        this._categoryWindow = new Window_Warehouse_Category();
        this._categoryWindow.x = rectangle.x;
        this._categoryWindow.y = rectangle.y;
        this._categoryWindow.width = rectangle.width;
        this._categoryWindow.height = rectangle.height;
    }
    this._categoryWindow.setHandler('ok', this.onCategoryOkay.bind(this));
    this._categoryWindow.setHandler('cancel', this.popScene.bind(this));
    this._categoryWindow.onSelectionChange = this.onCategoryChange.bind(this);
    this.addWindow(this._categoryWindow);
}

Scene_Warehouse.prototype.createHeaderWindows = function() {
    const rectangle1 = this.header1Rectangle();
    const rectangle2 = this.header2Rectangle();

    if ('MZ' == Utils.RPGMAKER_NAME) {
        this._itemListHeaderWindow = new Window_Inventory_Header(rectangle1);
        this._warehouseHeaderWindow = new Window_Warehouse_Header(rectangle2);
    } else {
        this._itemListHeaderWindow = new Window_Inventory_Header(
            rectangle1.x,
            rectangle1.y,
            rectangle1.width,
            rectangle1.height,
        );
        this._warehouseHeaderWindow = new Window_Warehouse_Header(
            rectangle2.x,
            rectangle2.y,
            rectangle2.width,
            rectangle2.height,
        );
    }
    this.addWindow(this._itemListHeaderWindow);
    this.addWindow(this._warehouseHeaderWindow);
}

Scene_Warehouse.prototype.createItemListWindow = function() {
    const rectangle = this.inventoryListRectangle();
    if ('MZ' == Utils.RPGMAKER_NAME) {
        this._itemListWindow = new Window_Inventory_List(rectangle);
    } else {
        this._itemListWindow = new Window_Inventory_List(
            rectangle.x,
            rectangle.y,
            rectangle.width,
            rectangle.height,
        );
    }
    this._itemListWindow.setHelpWindow(this._helpWindow);
    this._itemListWindow.setHandler('ok', this.onInventoryItemOkay.bind(this));
    this._itemListWindow.setHandler('cancel', this.onItemCancel.bind(this));
    this._itemListWindow.setHandler('right', this.onItemRight.bind(this));
    this._itemListWindow.onHover = this.onWarehouseItemLeft.bind(this);
    this._itemListWindow.onSelectionChange = this.onSelectionChange.bind(this);
    this._itemListWindow.refresh();
    this.addWindow(this._itemListWindow);
}

Scene_Warehouse.prototype.createWarehouseListWindow = function() {
    const rectangle = this.warehouseWindowRectangle();
    if ('MZ' == Utils.RPGMAKER_NAME) {
        this._warehouseWindow = new Window_Warehouse_List(rectangle);
    } else {
        this._warehouseWindow = new Window_Warehouse_List(
            rectangle.x,
            rectangle.y,
            rectangle.width,
            rectangle.height,
        );
    }
    this._warehouseWindow.setHelpWindow(this._helpWindow);
    this._warehouseWindow.setHandler('ok', this.onWarehouseItemOkay.bind(this));
    this._warehouseWindow.setHandler('cancel', this.onWarehouseItemCancel.bind(this));
    this._warehouseWindow.setHandler('left', this.onWarehouseItemLeft.bind(this));
    this._warehouseWindow.onHover = this.onItemRight.bind(this);
    this._warehouseWindow.onSelectionChange = this.onSelectionChange.bind(this);
    this._warehouseWindow.refresh();
    this.addWindow(this._warehouseWindow);
}

Scene_Warehouse.prototype.createGoldWindow = function() {
    const rectangle = this.goldWindowRectangle();
    if ('MZ' == Utils.RPGMAKER_NAME) {
        this._goldWindow = new Window_Warehouse_Gold(rectangle);
    } else {
        this._goldWindow = new Window_Warehouse_Gold(
            rectangle.x,
            rectangle.y,
            rectangle.width,
            rectangle.height,
        );
    }
    this._goldWindow.hide();
    this.addWindow(this._goldWindow);
}

Scene_Warehouse.prototype.createGoldCommandWindow = function() {
    const rectangle = this.goldCommandWindowRectangle();
    if ('MZ' == Utils.RPGMAKER_NAME) {
        this._goldCommandWindow = new Window_Warehouse_GoldCommand(rectangle);
    } else {
        this._goldCommandWindow = new Window_Warehouse_GoldCommand(
            rectangle.x,
            rectangle.y,
            rectangle.width,
            rectangle.height,
        );
    }
    this._goldCommandWindow.setHandler('save', this.onSaveGold.bind(this));
    this._goldCommandWindow.setHandler('take', this.onTakeGold.bind(this));
    this._goldCommandWindow.setHandler('cancel', this.onGoldCancel.bind(this));
    this._goldCommandWindow.hide();
    this.addWindow(this._goldCommandWindow);
}

Scene_Warehouse.prototype.createTransferItemWindow = function() {
    const rectangle = this.transferWindowRectangle();
    if ('MZ' == Utils.RPGMAKER_NAME) {
        this._transferItemWindow = new Window_Item_Transfer(rectangle);
    } else {
        this._transferItemWindow = new Window_Item_Transfer(
            rectangle.x,
            rectangle.y,
            rectangle.width,
            rectangle.height,
        );
    }
    this._transferItemWindow.setHandler('ok', this.onTransferOkay.bind(this));
    this._transferItemWindow.setHandler('cancel', this.onTransferCancel.bind(this));
    this._transferItemWindow.hide();
    this.addWindow(this._transferItemWindow);
}

Scene_Warehouse.prototype.createTransferGoldWindow = function() {
    const rectangle = this.transferWindowRectangle();
    if ('MZ' == Utils.RPGMAKER_NAME) {
        this._transferGoldWindow = new Window_Gold_Transfer(rectangle);
    } else {
        this._transferGoldWindow = new Window_Gold_Transfer(
            rectangle.x,
            rectangle.y,
            rectangle.width,
            rectangle.height,
        );
    }
    this._transferGoldWindow.setHandler('ok', this.onTransferGoldOkay.bind(this));
    this._transferGoldWindow.setHandler('cancel', this.onTransferGoldCancel.bind(this));
    this._transferGoldWindow.hide();
    this.addWindow(this._transferGoldWindow);
}

Scene_Warehouse.prototype.onCategoryOkay = function() {
    this._categoryWindow.deactivate();

    if ('gold' == this._categoryWindow.currentSymbol()) {
        this._goldCommandWindow.show();
        this._goldCommandWindow.activate();
        this._goldCommandWindow.select(0);
    } else {
        this._itemListWindow.activate();
        this._itemListWindow.selectLast();
    }
}

Scene_Warehouse.prototype.onCategoryChange = function() {
    if ('gold' == this._categoryWindow.currentSymbol()) {
        this._itemListWindow.hide();
        this._warehouseWindow.hide();
        this._goldWindow.show();
        this._goldCommandWindow.show();
        this._goldCommandWindow.deactivate();
        this._goldCommandWindow.deselect();
    } else {
        this._itemListWindow.show();
        this._warehouseWindow.show();
        this._goldWindow.hide();
        this._goldCommandWindow.hide();
    }
}

Scene_Warehouse.prototype.onSelectionChange = function() {
    // nothing to do
}

Scene_Warehouse.prototype.onInventoryItemOkay = function() {
    const item = this._itemListWindow.item();
    const maxAmount = this.currentlySelectedMaxAmount('store', item);

    if (item && maxAmount) {
        if (this._itemListWindow.needsNumber()) {
            SoundManager.playOk();

            this._itemListWindow.deactivate();
            this._warehouseWindow.deactivate();
            this._transferItemWindow.setup('store', item, maxAmount);
            this._transferItemWindow.show();
            this._transferItemWindow.activate();
        }
        else {
            playSE(MK.Warehouse.storeItemSE);
            MK.Warehouse.storeItem(item, 1);
            
            this._itemListWindow.refresh();
            this._warehouseWindow.refresh();
            this._itemListWindow.activate();
        }
    } else {
        // not supposed to happen
        this._itemListWindow.activate();
        this._itemListWindow.selectLast();
    }
}

Scene_Warehouse.prototype.onWarehouseItemOkay = function() {
    const item = this._warehouseWindow.item();
    const maxAmount = this.currentlySelectedMaxAmount('take', item);
    
    if (item && maxAmount) {
        if (this._warehouseWindow.needsNumber()) {
            SoundManager.playOk();
            
            this._itemListWindow.deactivate();
            this._warehouseWindow.deactivate();
            this._transferItemWindow.show();
            this._transferItemWindow.setup('take', item, maxAmount);
            this._transferItemWindow.activate();
        }
        else {
            playSE(MK.Warehouse.takeItemSE);
            MK.Warehouse.takeItem(item, 1);
            this._itemListWindow.refresh();
            this._warehouseWindow.refresh();
            this._warehouseWindow.activate();
        }
    } else {
        // not supposed to happen
        this._warehouseWindow.activate();
        this._warehouseWindow.selectLast();
    }
}

Scene_Warehouse.prototype.currentlySelectedMaxAmount = function(mode, item) {
    if (!item) return 0;

    if ('store' == mode) {
        return Math.min(
            $gameParty.numItems(item),
            MK.Warehouse.stackSize(item) - MK.Warehouse.numItems(item),
        );
    }
    if ('take' == mode) {
        return Math.min(
            MK.Warehouse.numItems(item),
            $gameParty.maxItems(item) - $gameParty.numItems(item),
        );
    }
}

Scene_Warehouse.prototype.onItemCancel = function() {
    this._itemListWindow.deactivate();
    this._itemListWindow.deselect();
    this._warehouseWindow.deactivate();
    this._warehouseWindow.deselect();
    this._categoryWindow.activate();
    this._helpWindow.clear();
}

Scene_Warehouse.prototype.onItemRight = function() {
    if (this._itemListWindow.isOpenAndActive()) {
        this._itemListWindow.deactivate();
        this._itemListWindow.deselect();
        this._warehouseWindow.activate();
        this._warehouseWindow.selectLast();
    }
}

Scene_Warehouse.prototype.onWarehouseItemCancel = function() {
    this.onItemCancel();
}

Scene_Warehouse.prototype.onWarehouseItemLeft = function() {
    if (this._warehouseWindow.isOpenAndActive()) {
        this._itemListWindow.activate();
        this._itemListWindow.selectLast();
        this._warehouseWindow.deactivate();
        this._warehouseWindow.deselect();
    }
}

Scene_Warehouse.prototype.onTransferOkay = function() {
    if ('store' == this._transferItemWindow.mode()) this.storeItem();
    if ('take' == this._transferItemWindow.mode()) this.takeItem();
}

Scene_Warehouse.prototype.storeItem = function() {
    const item = this._itemListWindow.item();
    const amount = this._transferItemWindow.number();

    if (item && amount) {
        playSE(MK.Warehouse.storeItemSE);
        MK.Warehouse.storeItem(item, amount);
    }
    this._transferItemWindow.deactivate();
    this._transferItemWindow.hide();
    this._itemListWindow.refresh();
    this._itemListWindow.activate();
    this._warehouseWindow.refresh();
}

Scene_Warehouse.prototype.takeItem = function() {
    const item = this._warehouseWindow.item();
    const amount = this._transferItemWindow.number();

    if (item && amount) {
        playSE(MK.Warehouse.takeItemSE);
        MK.Warehouse.takeItem(item, amount);
    }
    this._transferItemWindow.deactivate();
    this._transferItemWindow.hide();
    this._itemListWindow.refresh();
    this._warehouseWindow.refresh();
    this._warehouseWindow.activate();
}

Scene_Warehouse.prototype.onTransferGoldOkay = function() {
    if ('save' == this._transferGoldWindow.mode()) this.saveGold();
    if ('take' == this._transferGoldWindow.mode()) this.takeGold();
}

Scene_Warehouse.prototype.saveGold = function() {
    const amount = this._transferGoldWindow.number();

    if (amount) {
        playSE(MK.Warehouse.saveGoldSE);
        MK.Warehouse.saveGold(amount);
    }
    this._transferGoldWindow.deactivate();
    this._transferGoldWindow.hide();
    this._goldWindow.refresh();
    this._goldCommandWindow.hide();
    this._goldCommandWindow.refresh();
    this._categoryWindow.activate();
}

Scene_Warehouse.prototype.takeGold = function() {
    const amount = this._transferGoldWindow.number();

    if (amount) {
        playSE(MK.Warehouse.takeGoldSE);
        MK.Warehouse.takeGold(amount);
    }
    this._transferGoldWindow.deactivate();
    this._transferGoldWindow.hide();
    this._goldWindow.refresh();
    this._goldCommandWindow.hide();
    this._goldCommandWindow.refresh();
    this._categoryWindow.activate();
}

Scene_Warehouse.prototype.onTransferCancel = function() {
    this._transferItemWindow.deactivate();
    this._transferItemWindow.hide();

    if ('store' == this._transferItemWindow.mode()) {
        this._itemListWindow.activate();
    } else {
        this._warehouseWindow.activate();
    }
}

Scene_Warehouse.prototype.onTransferGoldCancel = function() {
    this._transferGoldWindow.deactivate();
    this._transferGoldWindow.hide();
    this._goldCommandWindow.show();
    this._goldCommandWindow.activate();
}

Scene_Warehouse.prototype.onGoldCancel = function() {
    this._goldCommandWindow.deactivate();
    this._goldCommandWindow.hide();
    this._categoryWindow.activate();
}

Scene_Warehouse.prototype.onSaveGold = function() {
    this._goldCommandWindow.hide();
    this._transferGoldWindow.setup('save', $gameParty.gold());
    this._transferGoldWindow.show();
    this._transferGoldWindow.activate();
}

Scene_Warehouse.prototype.onTakeGold = function() {
    this._goldCommandWindow.hide();
    this._transferGoldWindow.setup('take', $gameParty.savedGold());
    this._transferGoldWindow.show();
    this._transferGoldWindow.activate();
}

Scene_Warehouse.prototype.categoryWindowRectangle = function() {
    const y = this.mainAreaTop
        ? this.mainAreaTop()
        : this._helpWindow.y + this._helpWindow.height;
    return new Rectangle(
        0,
        y,
        Graphics.boxWidth,
        calcWindowHeight(1),
    );
}

Scene_Warehouse.prototype.header1Rectangle = function() {
    return new Rectangle(
        0,
        this._categoryWindow.y + this._categoryWindow.height,
        Graphics.boxWidth / 2,
        calcWindowHeight(1),
    );
}

Scene_Warehouse.prototype.header2Rectangle = function() {
    return new Rectangle(
        Graphics.boxWidth / 2,
        this._categoryWindow.y + this._categoryWindow.height,
        Graphics.boxWidth / 2,
        calcWindowHeight(1),
    );
}

Scene_Warehouse.prototype.inventoryListRectangle = function() {
    const x = this._categoryWindow.x;
    const y = this._itemListHeaderWindow.y + this._itemListHeaderWindow.height;
    const width = Graphics.boxWidth / 2;
    const height = 'MZ' == Utils.RPGMAKER_NAME
        ? this.mainAreaBottom() - y
        : Graphics.boxHeight - y;
    return new Rectangle(x, y, width, height);
}

Scene_Warehouse.prototype.warehouseWindowRectangle = function() {
    const x = this._warehouseHeaderWindow.x;
    const y = this._itemListWindow.y;
    const width = this._warehouseHeaderWindow.width;
    const height = this._itemListWindow.height;
    return new Rectangle(x, y, width, height);
}

Scene_Warehouse.prototype.goldWindowRectangle = function() {
    return new Rectangle(
        0,
        this._itemListHeaderWindow.y,
        Graphics.boxWidth,
        this._itemListHeaderWindow.height + this._itemListWindow.height,
    );
}

Scene_Warehouse.prototype.goldCommandWindowRectangle = function() {
    const width = Graphics.boxWidth / 3;
    const height = calcWindowHeight(3);
    const x = Graphics.boxWidth - width;
    const y = this._goldWindow.y + this._goldWindow.height - height;
    return new Rectangle(x, y, width, height);
}

Scene_Warehouse.prototype.transferWindowRectangle = function() {
    const width = Graphics.boxWidth / 2;
    const height = Graphics.boxHeight / 3;
    const x = (Graphics.boxWidth / 2) - (width / 2);
    const y = (Graphics.boxHeight / 2) - (height / 2);
    return new Rectangle(x, y, width, height);
}


// =====================================================================================
// MK
// =====================================================================================

MK.Warehouse.open = function(enableGoldTransfer) {
    SceneManager.push(Scene_Warehouse);

    SceneManager.prepareNextScene(
        typeof enableGoldTransfer === 'boolean'
            ? enableGoldTransfer
            : MK.Warehouse.enableGoldTransfer
    );
}

MK.Warehouse.storeItem = function(item, amount) {
    if (!item || !item.id || !amount) return;
    if (!MK.Warehouse.isStorable(item)) return;

    const actualAmount = Math.min(amount, $gameParty.numItems(item));
    if (!actualAmount) return;
    
    const container = MK.Warehouse.getContainer(item);
    if (container) {
        $gameParty.loseItem(item, actualAmount, false);
        container[item.id] = (container[item.id] || 0) + actualAmount;
    }
}

MK.Warehouse.takeItem = function(item, amount) {
    if (!item || !item.id || !amount) return;

    const actualAmount = Math.min(amount, MK.Warehouse.numItems(item));
    if (!actualAmount) return;
    
    const container = MK.Warehouse.getContainer(item); 
    if (container) {
        $gameParty.gainItem(item, amount);
        container[item.id] = container[item.id] - amount;
    }
}

MK.Warehouse.isStorable = function(item) {
    return (
        item &&
        item.meta &&
        !('Cannot Store' in item.meta) && (
            (item.itypeId == 1 && MK.Warehouse.canStoreItems) ||
            (item.itypeId == 2 && MK.Warehouse.canStoreKeyItems) ||
            (DataManager.isWeapon(item) && MK.Warehouse.canStoreWeapons) ||
            (DataManager.isArmor(item) && MK.Warehouse.canStoreArmors) ||
            (item.meta['Can Store'])
    ));
}

MK.Warehouse.isStorableRightNow = function(item) {
    return (
        MK.Warehouse.isStorable(item) &&
        (MK.Warehouse.stackSize(item) > MK.Warehouse.numItems(item))
    );
}

MK.Warehouse.numItems = function(item) {
    const container = MK.Warehouse.getContainer(item);
    return item && item.id && container && container[item.id]
        ? container[item.id]
        : 0;
}

MK.Warehouse.getContainer = function(item) {
    if (DataManager.isItem(item))   return $gameParty._savedItems;
    if (DataManager.isWeapon(item)) return $gameParty._savedWeapons;
    if (DataManager.isArmor(item))  return $gameParty._savedArmors;
}

MK.Warehouse.allSavedItems = function() {
    $gameParty._savedItems = $gameParty._savedItems || [ ];
    $gameParty._savedWeapons = $gameParty._savedWeapons || [ ];
    $gameParty._savedArmors = $gameParty._savedArmors || [ ];

    const toReturn = [ ];

    for (let i = 0; i < $gameParty._savedItems.length; i++) {
        if ($gameParty._savedItems[i]) {
            toReturn.push($dataItems[i]);
        }
    }
    for (let i = 0; i < $gameParty._savedWeapons.length; i++) {
        if ($gameParty._savedWeapons[i]) {
            toReturn.push($dataWeapons[i]);
        }
    }
    for (let i = 0; i < $gameParty._savedArmors.length; i++) {
        if ($gameParty._savedArmors[i]) {
            toReturn.push($dataArmors[i]);
        }
    }
    return toReturn;
}

MK.Warehouse.stackSize = function(item) {
    if (item && item.meta && 'Warehouse Stack Size' in item.meta) {
        return Number(item.meta['Warehouse Stack Size']);
    }
    if (DataManager.isItem(item) && item.itypeId == 2) return MK.Warehouse.keyItemStackSize;
    if (DataManager.isItem(item)) return MK.Warehouse.itemStackSize;
    if (DataManager.isWeapon(item)) return MK.Warehouse.weaponStackSize;
    if (DataManager.isArmor(item)) return MK.Warehouse.armorStackSize;
    return 0;
}

MK.Warehouse.saveGold = function(amount) {
    const actualAmount = Math.min(
        amount,
        $gameParty.gold(),
        MK.Warehouse.maxGold - $gameParty.savedGold(),
    );
    if (actualAmount) {
        $gameParty.loseGold(actualAmount);
        $gameParty._savedGold = $gameParty.savedGold() + actualAmount;
    }
}

MK.Warehouse.takeGold = function(amount) {
    const actualAmount = Math.min(
        amount,
        $gameParty.savedGold(),
        $gameParty.maxGold() - $gameParty.gold(),
    );
    if (actualAmount) {
        $gameParty._savedGold = $gameParty.savedGold() - actualAmount;
        $gameParty.gainGold(actualAmount);
    }
}

Game_Party.prototype.savedGold = function() {
    return this._savedGold || 0;
}

if (PluginManager.registerCommand) {

    PluginManager.registerCommand(PLUGIN_NAME, 'open', args => {
        const enableGoldTransfer = (
            ('Yes' == args.enableGoldTransfer) ||
            ('Default' == args.enableGoldTransfer && MK.Warehouse.enableGoldTransfer)
        );
        MK.Warehouse.open(enableGoldTransfer);
    });

    const storeTakeAnyItem = (item, args) => {
        let amount = 0;
        
        if ('fixed' == args.mode) amount = Number(args.amount);
        if ('by Variables' == args.mode) amount = $gameVariables.value(Number(args.variableId));
        
        if ('Store' == args.action) {
            MK.Warehouse.storeItem(item, amount);
        }
        if ('Take' == args.action) {
            MK.Warehouse.takeItem(item, amount);
        }
    }

    PluginManager.registerCommand(PLUGIN_NAME, 'storeTakeItem', args => {
        const item = $dataItems[Number(args.item)];
        storeTakeAnyItem(item, args);
    });

    PluginManager.registerCommand(PLUGIN_NAME, 'storeTakeWeapon', args => {
        const item = $dataweapons[Number(args.weapon)];
        storeTakeAnyItem(item, args);
    });

    PluginManager.registerCommand(PLUGIN_NAME, 'storeTakeArmor', args => {
        const item = $dataArmors[Number(args.armor)];
        storeTakeAnyItem(item, args);
    });
}


})();
