// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
//      Magicbane Emulator Project © 2013 - 2022
//                www.magicbane.com


package engine.objects;

import ch.claude_martin.enumbitset.EnumBitSet;
import engine.Enum;
import engine.Enum.*;
import engine.gameManager.BuildingManager;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.net.Dispatch;
import engine.net.DispatchMessage;
import engine.net.client.ClientConnection;
import engine.net.client.msg.*;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

public class Warehouse extends AbstractWorldObject {


    public static ItemBase goldIB = ItemBase.getItemBase(7);
    public static ItemBase stoneIB = ItemBase.getItemBase(1580000);
    public static ItemBase truesteelIB = ItemBase.getItemBase(1580001);
    public static ItemBase ironIB = ItemBase.getItemBase(1580002);
    public static ItemBase adamantIB = ItemBase.getItemBase(1580003);
    public static ItemBase lumberIB = ItemBase.getItemBase(1580004);
    public static ItemBase oakIB = ItemBase.getItemBase(1580005);
    public static ItemBase bronzewoodIB = ItemBase.getItemBase(1580006);
    public static ItemBase mandrakeIB = ItemBase.getItemBase(1580007);
    public static ItemBase coalIB = ItemBase.getItemBase(1580008);
    public static ItemBase agateIB = ItemBase.getItemBase(1580009);
    public static ItemBase diamondIB = ItemBase.getItemBase(1580010);
    public static ItemBase onyxIB = ItemBase.getItemBase(1580011);
    public static ItemBase azothIB = ItemBase.getItemBase(1580012);
    public static ItemBase orichalkIB = ItemBase.getItemBase(1580013);
    public static ItemBase antimonyIB = ItemBase.getItemBase(1580014);
    public static ItemBase sulferIB = ItemBase.getItemBase(1580015);
    public static ItemBase quicksilverIB = ItemBase.getItemBase(1580016);
    public static ItemBase galvorIB = ItemBase.getItemBase(1580017);
    public static ItemBase wormwoodIB = ItemBase.getItemBase(1580018);
    public static ItemBase obsidianIB = ItemBase.getItemBase(1580019);
    public static ItemBase bloodstoneIB = ItemBase.getItemBase(1580020);
    public static ItemBase mithrilIB = ItemBase.getItemBase(1580021);
    public static ConcurrentHashMap<Integer, Integer> maxResources = new ConcurrentHashMap<>();
    public static ConcurrentHashMap<Integer, Warehouse> warehouseByBuildingUUID = new ConcurrentHashMap<>();
    public EnumBitSet<Enum.ResourceType> lockedResourceTypes;
    private int UID;
    private int buildingUID;
    private ArrayList<Transaction> transactions = new ArrayList<>();
    private ConcurrentHashMap<ItemBase, Integer> resources = new ConcurrentHashMap<>();


    /**
     * ResultSet Constructor
     */
    public Warehouse(ResultSet rs) throws SQLException {
        super(rs);
        this.UID = rs.getInt("UID");
        this.resources.put(stoneIB, rs.getInt("warehouse_stone"));
        this.resources.put(truesteelIB, rs.getInt("warehouse_truesteel"));
        this.resources.put(ironIB, rs.getInt("warehouse_iron"));
        this.resources.put(adamantIB, rs.getInt("warehouse_adamant"));
        this.resources.put(lumberIB, rs.getInt("warehouse_lumber"));
        this.resources.put(oakIB, rs.getInt("warehouse_oak"));
        this.resources.put(bronzewoodIB, rs.getInt("warehouse_bronzewood"));
        this.resources.put(mandrakeIB, rs.getInt("warehouse_mandrake"));
        this.resources.put(coalIB, rs.getInt("warehouse_coal"));
        this.resources.put(agateIB, rs.getInt("warehouse_agate"));
        this.resources.put(diamondIB, rs.getInt("warehouse_diamond"));
        this.resources.put(onyxIB, rs.getInt("warehouse_onyx"));
        this.resources.put(azothIB, rs.getInt("warehouse_azoth"));
        this.resources.put(orichalkIB, rs.getInt("warehouse_orichalk"));
        this.resources.put(antimonyIB, rs.getInt("warehouse_antimony"));
        this.resources.put(sulferIB, rs.getInt("warehouse_sulfur"));
        this.resources.put(quicksilverIB, rs.getInt("warehouse_quicksilver"));
        this.resources.put(galvorIB, rs.getInt("warehouse_galvor"));
        this.resources.put(wormwoodIB, rs.getInt("warehouse_wormwood"));
        this.resources.put(obsidianIB, rs.getInt("warehouse_obsidian"));
        this.resources.put(bloodstoneIB, rs.getInt("warehouse_bloodstone"));
        this.resources.put(mithrilIB, rs.getInt("warehouse_mithril"));
        this.resources.put(goldIB, rs.getInt("warehouse_gold"));
        this.lockedResourceTypes = EnumBitSet.asEnumBitSet(rs.getLong("warehouse_locks"), Enum.ResourceType.class);
        this.buildingUID = rs.getInt("parent");
        Warehouse.warehouseByBuildingUUID.put(this.buildingUID, this);
    }

    public static ConcurrentHashMap<Integer, Integer> getMaxResources() {
        if (maxResources.size() != 23) {
            maxResources.put(7, 100000000);
            maxResources.put(1580000, 10000);
            maxResources.put(1580001, 2000);
            maxResources.put(1580002, 2000);
            maxResources.put(1580003, 1000);
            maxResources.put(1580004, 10000);
            maxResources.put(1580005, 3000);
            maxResources.put(1580006, 3000);
            maxResources.put(1580007, 1000);
            maxResources.put(1580008, 3000);
            maxResources.put(1580009, 2000);
            maxResources.put(1580010, 2000);
            maxResources.put(1580011, 1000);
            maxResources.put(1580012, 2000);
            maxResources.put(1580013, 3000);
            maxResources.put(1580014, 1000);
            maxResources.put(1580015, 1000);
            maxResources.put(1580016, 1000);
            maxResources.put(1580017, 500);
            maxResources.put(1580018, 500);
            maxResources.put(1580019, 500);
            maxResources.put(1580020, 500);
            maxResources.put(1580021, 500);
        }

        return maxResources;
    }

    public static void warehouseDeposit(MerchantMsg msg, PlayerCharacter player, NPC npc, ClientConnection origin) {

        Building warehouseBuilding;
        Warehouse warehouse;
        int depositAmount;
        Dispatch dispatch;

        Item resource = Item.getFromCache(msg.getItemID());

        if (resource == null)
            return;

        depositAmount = msg.getAmount();
        CharacterItemManager itemMan = player.getCharItemManager();

        if (itemMan.doesCharOwnThisItem(resource.getObjectUUID()) == false)
            return;

        warehouseBuilding = npc.getBuilding();

        if (warehouseBuilding == null)
            return;

        warehouse = warehouseByBuildingUUID.get(warehouseBuilding.getObjectUUID());

        if (warehouse == null)
            return;

        ItemBase ib = resource.getItemBase();

        if (!warehouse.deposit(player, resource, depositAmount, true, true)) {
            //            ChatManager.chatGuildError(player, "Failed to deposit " + ib.getName() +".");
            //            Logger.debug("OpenWindow", player.getName() + " Failed to deposit Item with ID " + resource.getObjectUUID() + " from Warehouse With ID = " + warehouseBuilding.getObjectUUID());
            return;
        }

        ViewResourcesMessage vrm = new ViewResourcesMessage(player);
        vrm.setGuild(player.getGuild());
        vrm.setWarehouseBuilding(warehouseBuilding);
        vrm.configure();
        dispatch = Dispatch.borrow(player, vrm);
        DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
    }

    public static void warehouseWithdraw(MerchantMsg msg, PlayerCharacter player, NPC npc, ClientConnection origin) {

        int withdrawAmount;
        Building warehouseBuilding;
        Warehouse warehouse;
        Dispatch dispatch;

        withdrawAmount = msg.getAmount();
        warehouseBuilding = npc.getBuilding();

        if (warehouseBuilding == null)
            return;

        if (player.getGuild() != warehouseBuilding.getGuild() || GuildStatusController.isInnerCouncil(player.getGuildStatus()) == false)
            return;

        warehouse = warehouseByBuildingUUID.get(warehouseBuilding.getObjectUUID());

        if (warehouse == null)
            return;

        int hashID = msg.getHashID();
        int itemBaseID = ItemBase.getItemHashIDMap().get(hashID);
        ItemBase ib = ItemBase.getItemBase(itemBaseID);

        if (ib == null) {
            Logger.debug("Failed to find Resource ItemBaseID with Hash ID = " + hashID);
            return;
        }

        if (warehouse.isResourceLocked(ib) == true) {
            ChatManager.chatSystemInfo(player, "You cannot withdrawl a locked resource.");
            return;
        }
        if (!warehouse.withdraw(player, ib, withdrawAmount, true, true)) {
            ChatManager.chatGuildError(player, "Failed to withdrawl " + ib.getName() + '.');
            Logger.debug(player.getName() + " Failed to withdrawl  =" + ib.getName() + " from Warehouse With ID = " + warehouseBuilding.getObjectUUID());
            return;
        }

        ViewResourcesMessage vrm = new ViewResourcesMessage(player);
        vrm.setGuild(player.getGuild());
        vrm.setWarehouseBuilding(warehouseBuilding);
        vrm.configure();
        dispatch = Dispatch.borrow(player, vrm);
        DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
    }

    public static void warehouseLock(MerchantMsg msg, PlayerCharacter player, NPC npc, ClientConnection origin) {
        Building warehouse;
        int hashID;
        Dispatch dispatch;

        hashID = msg.getHashID();
        warehouse = npc.getBuilding();

        if (warehouse == null)
            return;

        if (player.getGuild() != warehouse.getGuild() || GuildStatusController.isInnerCouncil(player.getGuildStatus()) == false)
            return;

        Warehouse wh = warehouseByBuildingUUID.get(warehouse.getObjectUUID());

        if (wh == null)
            return;

        int itemBaseID = ItemBase.getItemHashIDMap().get(hashID);
        ItemBase ib = ItemBase.getItemBase(itemBaseID);

        if (ib == null)
            return;

        if (wh.isResourceLocked(ib) == true) {
            boolean worked = false;
            EnumBitSet<ResourceType> bitSet = EnumBitSet.asEnumBitSet(wh.lockedResourceTypes.toLong(), ResourceType.class);

            bitSet.remove(ResourceType.resourceLookup.get(itemBaseID));

            worked = DbManager.WarehouseQueries.updateLocks(wh, bitSet.toLong());

            if (worked) {
                wh.lockedResourceTypes.remove(Enum.ResourceType.resourceLookup.get(itemBaseID));
                ViewResourcesMessage vrm = new ViewResourcesMessage(player);
                vrm.setGuild(player.getGuild());
                vrm.setWarehouseBuilding(warehouse);
                vrm.configure();
                dispatch = Dispatch.borrow(player, vrm);
                DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
            }
            return;
        }

        EnumBitSet<ResourceType> bitSet = EnumBitSet.asEnumBitSet(wh.lockedResourceTypes.toLong(), ResourceType.class);

        bitSet.add(ResourceType.resourceLookup.get(itemBaseID));

        if (DbManager.WarehouseQueries.updateLocks(wh, bitSet.toLong()) == false)
            return;

        wh.lockedResourceTypes.add(Enum.ResourceType.resourceLookup.get(itemBaseID));
        ViewResourcesMessage vrm = new ViewResourcesMessage(player);
        vrm.setGuild(player.getGuild());
        vrm.setWarehouseBuilding(warehouse);
        vrm.configure();
        dispatch = Dispatch.borrow(player, vrm);
        DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);

    }

    public static int getSellStackSize(int id){
        if(id == 1705032)
            return 10;
        else{
            ItemBase ib = ItemBase.getItemBase(id);
            if(ib != null)
                return 3000000 / ib.getBaseValue();
        }
        return 0; // something went wrong
    }

    public ConcurrentHashMap<ItemBase, Integer> getResources() {
        return resources;
    }

    public int getUID() {
        return UID;
    }

    public void setUID(int uID) {
        UID = uID;
    }

    public synchronized boolean deposit(PlayerCharacter pc, Item resource, int amount, boolean removeFromInventory, boolean transaction) {

        ClientConnection origin = pc.getClientConnection();
        if (origin == null)
            return false;

        if (amount < 0) {
            Logger.info(pc.getFirstName() + " Attempting to Dupe!!!!!!");
            return false;
        }

        ItemBase ib = resource.getItemBase();

        if (ib == null)
            return false;

        if (this.resources.get(ib) == null)
            return false;

        CharacterItemManager itemMan = pc.getCharItemManager();

        if (itemMan == null)
            return false;


        if (itemMan.getGoldTrading() > 0) {
            ErrorPopupMsg.sendErrorPopup(pc, 195);
            return false;
        }


        if (!itemMan.doesCharOwnThisItem(resource.getObjectUUID()))
            return false;

        if (!resource.validForInventory(origin, pc, itemMan))
            return false;

        if (resource.getNumOfItems() < amount)
            return false;

        int oldAmount = resources.get(ib);

        int newAmount = oldAmount + amount;

        if (newAmount > Warehouse.getMaxResources().get(ib.getUUID())) {
            //ChatManager.chatSystemInfo(pc, "The Warehouse is at it's maximum for this type of resource.");
            return false;
        }


        if (removeFromInventory) {
            if (ib.getUUID() == 7) {

                if (itemMan.getGoldInventory().getNumOfItems() - amount < 0)
                    return false;

                if (itemMan.getGoldInventory().getNumOfItems() - amount > MBServerStatics.PLAYER_GOLD_LIMIT)
                    return false;

                if (!itemMan.modifyInventoryGold(-amount)) {
                    //ChatManager.chatSystemError(pc, "You do not have this Gold.");
                    return false;
                }

                UpdateGoldMsg ugm = new UpdateGoldMsg(pc);
                ugm.configure();
                Dispatch dispatch = Dispatch.borrow(pc, ugm);
                DispatchMessage.dispatchMsgDispatch(dispatch, engine.Enum.DispatchChannel.SECONDARY);

                itemMan.updateInventory();

            } else {
                itemMan.delete(resource);
                itemMan.updateInventory();
            }
        }
        itemMan.updateInventory();
        int itemID = ib.getUUID();
        boolean worked = false;
        switch (itemID) {
            case 7:
                worked = DbManager.WarehouseQueries.updateGold(this, newAmount);
                break;
            case 1580000:
                worked = DbManager.WarehouseQueries.updateStone(this, newAmount);
                break;
            case 1580001:
                worked = DbManager.WarehouseQueries.updateTruesteel(this, newAmount);
                break;
            case 1580002:
                worked = DbManager.WarehouseQueries.updateIron(this, newAmount);
                break;
            case 1580003:
                worked = DbManager.WarehouseQueries.updateAdamant(this, newAmount);
                break;
            case 1580004:
                worked = DbManager.WarehouseQueries.updateLumber(this, newAmount);
                break;
            case 1580005:
                worked = DbManager.WarehouseQueries.updateOak(this, newAmount);
                break;
            case 1580006:
                worked = DbManager.WarehouseQueries.updateBronzewood(this, newAmount);
                break;
            case 1580007:
                worked = DbManager.WarehouseQueries.updateMandrake(this, newAmount);
                break;
            case 1580008:
                worked = DbManager.WarehouseQueries.updateCoal(this, newAmount);
                break;
            case 1580009:
                worked = DbManager.WarehouseQueries.updateAgate(this, newAmount);
                break;
            case 1580010:
                worked = DbManager.WarehouseQueries.updateDiamond(this, newAmount);
                break;
            case 1580011:
                worked = DbManager.WarehouseQueries.updateOnyx(this, newAmount);
                break;
            case 1580012:
                worked = DbManager.WarehouseQueries.updateAzoth(this, newAmount);
                break;
            case 1580013:
                worked = DbManager.WarehouseQueries.updateOrichalk(this, newAmount);
                break;
            case 1580014:
                worked = DbManager.WarehouseQueries.updateAntimony(this, newAmount);
                break;
            case 1580015:
                worked = DbManager.WarehouseQueries.updateSulfur(this, newAmount);
                break;
            case 1580016:
                worked = DbManager.WarehouseQueries.updateQuicksilver(this, newAmount);
                break;
            case 1580017:
                worked = DbManager.WarehouseQueries.updateGalvor(this, newAmount);
                break;
            case 1580018:
                worked = DbManager.WarehouseQueries.updateWormwood(this, newAmount);
                break;
            case 1580019:
                worked = DbManager.WarehouseQueries.updateObsidian(this, newAmount);
                break;
            case 1580020:
                worked = DbManager.WarehouseQueries.updateBloodstone(this, newAmount);
                break;
            case 1580021:
                worked = DbManager.WarehouseQueries.updateMithril(this, newAmount);
                break;
        }

        if (!worked)
            return false;

        resources.put(ib, newAmount);

        Resource resourceType;

        if (resource.getItemBase().getType().equals(engine.Enum.ItemType.GOLD))
            resourceType = Resource.GOLD;
        else
            resourceType = Resource.valueOf(resource.getItemBase().getName().toUpperCase());

        if (transaction)
            this.AddTransactionToWarehouse(pc.getObjectType(), pc.getObjectUUID(), TransactionType.DEPOSIT, resourceType, amount);

        return true;
    }

    //for mine deposit
    public synchronized boolean depositFromMine(Mine mine, ItemBase resource, int amount) {

        if (resource == null)
            return false;

        if (this.resources.get(resource) == null)
            return false;

        int oldAmount = resources.get(resource);
        int newAmount = oldAmount + amount;

        if (newAmount > Warehouse.getMaxResources().get(resource.getUUID()))
            return false;

        int itemID = resource.getUUID();
        boolean worked = false;

        switch (itemID) {
            case 7:
                worked = DbManager.WarehouseQueries.updateGold(this, newAmount);
                break;
            case 1580000:
                worked = DbManager.WarehouseQueries.updateStone(this, newAmount);
                break;
            case 1580001:
                worked = DbManager.WarehouseQueries.updateTruesteel(this, newAmount);
                break;
            case 1580002:
                worked = DbManager.WarehouseQueries.updateIron(this, newAmount);
                break;
            case 1580003:
                worked = DbManager.WarehouseQueries.updateAdamant(this, newAmount);
                break;
            case 1580004:
                worked = DbManager.WarehouseQueries.updateLumber(this, newAmount);
                break;
            case 1580005:
                worked = DbManager.WarehouseQueries.updateOak(this, newAmount);
                break;
            case 1580006:
                worked = DbManager.WarehouseQueries.updateBronzewood(this, newAmount);
                break;
            case 1580007:
                worked = DbManager.WarehouseQueries.updateMandrake(this, newAmount);
                break;
            case 1580008:
                worked = DbManager.WarehouseQueries.updateCoal(this, newAmount);
                break;
            case 1580009:
                worked = DbManager.WarehouseQueries.updateAgate(this, newAmount);
                break;
            case 1580010:
                worked = DbManager.WarehouseQueries.updateDiamond(this, newAmount);
                break;
            case 1580011:
                worked = DbManager.WarehouseQueries.updateOnyx(this, newAmount);
                break;
            case 1580012:
                worked = DbManager.WarehouseQueries.updateAzoth(this, newAmount);
                break;
            case 1580013:
                worked = DbManager.WarehouseQueries.updateOrichalk(this, newAmount);
                break;
            case 1580014:
                worked = DbManager.WarehouseQueries.updateAntimony(this, newAmount);
                break;
            case 1580015:
                worked = DbManager.WarehouseQueries.updateSulfur(this, newAmount);
                break;
            case 1580016:
                worked = DbManager.WarehouseQueries.updateQuicksilver(this, newAmount);
                break;
            case 1580017:
                worked = DbManager.WarehouseQueries.updateGalvor(this, newAmount);
                break;
            case 1580018:
                worked = DbManager.WarehouseQueries.updateWormwood(this, newAmount);
                break;
            case 1580019:
                worked = DbManager.WarehouseQueries.updateObsidian(this, newAmount);
                break;
            case 1580020:
                worked = DbManager.WarehouseQueries.updateBloodstone(this, newAmount);
                break;
            case 1580021:
                worked = DbManager.WarehouseQueries.updateMithril(this, newAmount);
                break;
        }
        if (!worked)
            return false;

        this.resources.put(resource, newAmount);
        Resource resourceType;

        if (resource.getUUID() == 7)
            resourceType = Resource.GOLD;
        else
            resourceType = Resource.valueOf(resource.getName().toUpperCase());

        if (mine != null)
            this.AddTransactionToWarehouse(GameObjectType.Building, mine.getBuildingID(), TransactionType.MINE, resourceType, amount);

        return true;
    }

    public synchronized boolean depositRealmTaxes(PlayerCharacter taxer, ItemBase ib, int amount) {

        if (ib == null)
            return false;

        if (this.resources.get(ib) == null)
            return false;

        int oldAmount = resources.get(ib);
        int newAmount = oldAmount + amount;

        if (newAmount > Warehouse.getMaxResources().get(ib.getUUID()))
            return false;

        int itemID = ib.getUUID();
        boolean worked = false;

        switch (itemID) {
            case 7:
                worked = DbManager.WarehouseQueries.updateGold(this, newAmount);
                break;
            case 1580000:
                worked = DbManager.WarehouseQueries.updateStone(this, newAmount);
                break;
            case 1580001:
                worked = DbManager.WarehouseQueries.updateTruesteel(this, newAmount);
                break;
            case 1580002:
                worked = DbManager.WarehouseQueries.updateIron(this, newAmount);
                break;
            case 1580003:
                worked = DbManager.WarehouseQueries.updateAdamant(this, newAmount);
                break;
            case 1580004:
                worked = DbManager.WarehouseQueries.updateLumber(this, newAmount);
                break;
            case 1580005:
                worked = DbManager.WarehouseQueries.updateOak(this, newAmount);
                break;
            case 1580006:
                worked = DbManager.WarehouseQueries.updateBronzewood(this, newAmount);
                break;
            case 1580007:
                worked = DbManager.WarehouseQueries.updateMandrake(this, newAmount);
                break;
            case 1580008:
                worked = DbManager.WarehouseQueries.updateCoal(this, newAmount);
                break;
            case 1580009:
                worked = DbManager.WarehouseQueries.updateAgate(this, newAmount);
                break;
            case 1580010:
                worked = DbManager.WarehouseQueries.updateDiamond(this, newAmount);
                break;
            case 1580011:
                worked = DbManager.WarehouseQueries.updateOnyx(this, newAmount);
                break;
            case 1580012:
                worked = DbManager.WarehouseQueries.updateAzoth(this, newAmount);
                break;
            case 1580013:
                worked = DbManager.WarehouseQueries.updateOrichalk(this, newAmount);
                break;
            case 1580014:
                worked = DbManager.WarehouseQueries.updateAntimony(this, newAmount);
                break;
            case 1580015:
                worked = DbManager.WarehouseQueries.updateSulfur(this, newAmount);
                break;
            case 1580016:
                worked = DbManager.WarehouseQueries.updateQuicksilver(this, newAmount);
                break;
            case 1580017:
                worked = DbManager.WarehouseQueries.updateGalvor(this, newAmount);
                break;
            case 1580018:
                worked = DbManager.WarehouseQueries.updateWormwood(this, newAmount);
                break;
            case 1580019:
                worked = DbManager.WarehouseQueries.updateObsidian(this, newAmount);
                break;
            case 1580020:
                worked = DbManager.WarehouseQueries.updateBloodstone(this, newAmount);
                break;
            case 1580021:
                worked = DbManager.WarehouseQueries.updateMithril(this, newAmount);
                break;
        }

        if (!worked)
            return false;

        this.resources.put(ib, newAmount);
        Resource resourceType;

        if (ib.getUUID() == 7)
            resourceType = Resource.GOLD;
        else
            resourceType = Resource.valueOf(ib.getName().toUpperCase());

        this.AddTransactionToWarehouse(taxer.getObjectType(), taxer.getObjectUUID(), TransactionType.TAXRESOURCEDEPOSIT, resourceType, amount);

        return true;
    }

    public synchronized boolean depositProfitTax(ItemBase ib, int amount, Building building) {

        if (ib == null)
            return false;

        if (this.resources.get(ib) == null)
            return false;

        int oldAmount = resources.get(ib);
        int newAmount = oldAmount + amount;

        if (newAmount > Warehouse.getMaxResources().get(ib.getUUID()))
            return false;

        int itemID = ib.getUUID();
        boolean worked = false;

        switch (itemID) {
            case 7:
                worked = DbManager.WarehouseQueries.updateGold(this, newAmount);
                break;
            case 1580000:
                worked = DbManager.WarehouseQueries.updateStone(this, newAmount);
                break;
            case 1580001:
                worked = DbManager.WarehouseQueries.updateTruesteel(this, newAmount);
                break;
            case 1580002:
                worked = DbManager.WarehouseQueries.updateIron(this, newAmount);
                break;
            case 1580003:
                worked = DbManager.WarehouseQueries.updateAdamant(this, newAmount);
                break;
            case 1580004:
                worked = DbManager.WarehouseQueries.updateLumber(this, newAmount);
                break;
            case 1580005:
                worked = DbManager.WarehouseQueries.updateOak(this, newAmount);
                break;
            case 1580006:
                worked = DbManager.WarehouseQueries.updateBronzewood(this, newAmount);
                break;
            case 1580007:
                worked = DbManager.WarehouseQueries.updateMandrake(this, newAmount);
                break;
            case 1580008:
                worked = DbManager.WarehouseQueries.updateCoal(this, newAmount);
                break;
            case 1580009:
                worked = DbManager.WarehouseQueries.updateAgate(this, newAmount);
                break;
            case 1580010:
                worked = DbManager.WarehouseQueries.updateDiamond(this, newAmount);
                break;
            case 1580011:
                worked = DbManager.WarehouseQueries.updateOnyx(this, newAmount);
                break;
            case 1580012:
                worked = DbManager.WarehouseQueries.updateAzoth(this, newAmount);
                break;
            case 1580013:
                worked = DbManager.WarehouseQueries.updateOrichalk(this, newAmount);
                break;
            case 1580014:
                worked = DbManager.WarehouseQueries.updateAntimony(this, newAmount);
                break;
            case 1580015:
                worked = DbManager.WarehouseQueries.updateSulfur(this, newAmount);
                break;
            case 1580016:
                worked = DbManager.WarehouseQueries.updateQuicksilver(this, newAmount);
                break;
            case 1580017:
                worked = DbManager.WarehouseQueries.updateGalvor(this, newAmount);
                break;
            case 1580018:
                worked = DbManager.WarehouseQueries.updateWormwood(this, newAmount);
                break;
            case 1580019:
                worked = DbManager.WarehouseQueries.updateObsidian(this, newAmount);
                break;
            case 1580020:
                worked = DbManager.WarehouseQueries.updateBloodstone(this, newAmount);
                break;
            case 1580021:
                worked = DbManager.WarehouseQueries.updateMithril(this, newAmount);
                break;
        }

        if (!worked)
            return false;

        this.resources.put(ib, newAmount);
        Resource resourceType;

        if (ib.getUUID() == 7)
            resourceType = Resource.GOLD;
        else
            resourceType = Resource.valueOf(ib.getName().toUpperCase());

        if (building != null)
            this.AddTransactionToWarehouse(GameObjectType.Building, building.getObjectUUID(), TransactionType.DEPOSIT, resourceType, amount);

        return true;
    }

    public synchronized boolean withdraw(PlayerCharacter pc, ItemBase ib, int amount, boolean addToInventory, boolean transaction) {

        if (pc == null)
            return false;

        if (ib == null)
            return false;

        if (this.resources.get(ib) == null)
            return false;

        if (amount <= 0)
            return false;

        CharacterItemManager itemMan = pc.getCharItemManager();

        if (itemMan == null)
            return false;

        if (addToInventory)
            if (!itemMan.hasRoomInventory(ib.getWeight())) {
                ChatManager.chatSystemInfo(pc, "You can not carry any more of that item.");
                return false;
            }

        if (addToInventory && ib.getUUID() == ItemBase.GOLD_BASE_ID) {
            if (pc.getCharItemManager().getGoldInventory().getNumOfItems() + amount > MBServerStatics.PLAYER_GOLD_LIMIT) {
                return false;
            }

            if (pc.getCharItemManager().getGoldInventory().getNumOfItems() + amount < 0)
                return false;
        }
        int oldAmount = this.resources.get(ib);

        if (oldAmount < amount)
            return false;

        int hashID = ib.getHashID();
        int newAmount = oldAmount - amount;

        boolean worked = false;

        switch (hashID) {
            case 2308551:
                worked = DbManager.WarehouseQueries.updateGold(this, newAmount);
                break;
            case 74856115:
                worked = DbManager.WarehouseQueries.updateStone(this, newAmount);
                break;
            case -317484979:
                worked = DbManager.WarehouseQueries.updateTruesteel(this, newAmount);
                break;
            case 2504297:
                worked = DbManager.WarehouseQueries.updateIron(this, newAmount);
                break;
            case -1741189964:
                worked = DbManager.WarehouseQueries.updateAdamant(this, newAmount);
                break;
            case -1603256692:
                worked = DbManager.WarehouseQueries.updateLumber(this, newAmount);
                break;
            case 74767:
                worked = DbManager.WarehouseQueries.updateOak(this, newAmount);
                break;
            case 1334770447:
                worked = DbManager.WarehouseQueries.updateBronzewood(this, newAmount);
                break;
            case 1191391799:
                worked = DbManager.WarehouseQueries.updateMandrake(this, newAmount);
                break;
            case 2559427:
                worked = DbManager.WarehouseQueries.updateCoal(this, newAmount);
                break;
            case 75173057:
                worked = DbManager.WarehouseQueries.updateAgate(this, newAmount);
                break;
            case -1730704107:
                worked = DbManager.WarehouseQueries.updateDiamond(this, newAmount);
                break;
            case 2977263:
                worked = DbManager.WarehouseQueries.updateOnyx(this, newAmount);
                break;
            case 78329697:
                worked = DbManager.WarehouseQueries.updateAzoth(this, newAmount);
                break;
            case -2036290524:
                worked = DbManager.WarehouseQueries.updateOrichalk(this, newAmount);
                break;
            case 452320058:
                worked = DbManager.WarehouseQueries.updateAntimony(this, newAmount);
                break;
            case -1586349421:
                worked = DbManager.WarehouseQueries.updateSulfur(this, newAmount);
                break;
            case -472884509:
                worked = DbManager.WarehouseQueries.updateQuicksilver(this, newAmount);
                break;
            case -1596311545:
                worked = DbManager.WarehouseQueries.updateGalvor(this, newAmount);
                break;
            case 1532478436:
                worked = DbManager.WarehouseQueries.updateWormwood(this, newAmount);
                break;
            case -697973233:
                worked = DbManager.WarehouseQueries.updateObsidian(this, newAmount);
                break;
            case -1569826353:
                worked = DbManager.WarehouseQueries.updateBloodstone(this, newAmount);
                break;
            case -1761257186:
                worked = DbManager.WarehouseQueries.updateMithril(this, newAmount);
                break;
        }
        if (!worked)
            return false;

        this.resources.put(ib, newAmount);

        if (addToInventory) {
            if (ib.getUUID() == 7) {

                itemMan.addGoldToInventory(amount, false);
                UpdateGoldMsg ugm = new UpdateGoldMsg(pc);
                ugm.configure();
                Dispatch dispatch = Dispatch.borrow(pc, ugm);
                DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);

                itemMan.updateInventory();
            } else {
                boolean itemWorked = false;
                Item item = new Item(ib, pc.getObjectUUID(), OwnerType.PlayerCharacter, (byte) 0, (byte) 0,
                        (short) 1, (short) 1, true, false, ItemContainerType.INVENTORY, (byte) 0,
                        new ArrayList<>(), "");
                item.setNumOfItems(amount);
                item.containerType = Enum.ItemContainerType.INVENTORY;

                try {
                    item = DbManager.ItemQueries.ADD_ITEM(item);
                    itemWorked = true;
                } catch (Exception e) {
                    Logger.error(e);
                }
                if (itemWorked) {
                    itemMan.addItemToInventory(item);
                    itemMan.updateInventory();
                }
            }
        }
        Resource resourceType;

        if (ib.getUUID() == 7)
            resourceType = Resource.GOLD;
        else
            resourceType = Resource.valueOf(ib.getName().toUpperCase());

        if (transaction)
            this.AddTransactionToWarehouse(pc.getObjectType(), pc.getObjectUUID(), TransactionType.WITHDRAWL, resourceType, amount);

        return true;
    }

    public synchronized boolean withdraw(NPC npc, ItemBase ib, int amount, boolean addToInventory, boolean transaction) {

        if (npc == null)
            return false;

        if (ib == null)
            return false;

        if (this.resources.get(ib) == null)
            return false;

        if (amount <= 0)
            return false;

        int oldAmount = this.resources.get(ib);

        if (oldAmount < amount)
            return false;

        int hashID = ib.getHashID();
        int newAmount = oldAmount - amount;
        boolean worked = false;

        switch (hashID) {
            case 2308551:
                worked = DbManager.WarehouseQueries.updateGold(this, newAmount);
                break;
            case 74856115:
                worked = DbManager.WarehouseQueries.updateStone(this, newAmount);
                break;
            case -317484979:
                worked = DbManager.WarehouseQueries.updateTruesteel(this, newAmount);
                break;
            case 2504297:
                worked = DbManager.WarehouseQueries.updateIron(this, newAmount);
                break;
            case -1741189964:
                worked = DbManager.WarehouseQueries.updateAdamant(this, newAmount);
                break;
            case -1603256692:
                worked = DbManager.WarehouseQueries.updateLumber(this, newAmount);
                break;
            case 74767:
                worked = DbManager.WarehouseQueries.updateOak(this, newAmount);
                break;
            case 1334770447:
                worked = DbManager.WarehouseQueries.updateBronzewood(this, newAmount);
                break;
            case 1191391799:
                worked = DbManager.WarehouseQueries.updateMandrake(this, newAmount);
                break;
            case 2559427:
                worked = DbManager.WarehouseQueries.updateCoal(this, newAmount);
                break;
            case 75173057:
                worked = DbManager.WarehouseQueries.updateAgate(this, newAmount);
                break;
            case -1730704107:
                worked = DbManager.WarehouseQueries.updateDiamond(this, newAmount);
                break;
            case 2977263:
                worked = DbManager.WarehouseQueries.updateOnyx(this, newAmount);
                break;
            case 78329697:
                worked = DbManager.WarehouseQueries.updateAzoth(this, newAmount);
                break;
            case -2036290524:
                worked = DbManager.WarehouseQueries.updateOrichalk(this, newAmount);
                break;
            case 452320058:
                worked = DbManager.WarehouseQueries.updateAntimony(this, newAmount);
                break;
            case -1586349421:
                worked = DbManager.WarehouseQueries.updateSulfur(this, newAmount);
                break;
            case -472884509:
                worked = DbManager.WarehouseQueries.updateQuicksilver(this, newAmount);
                break;
            case -1596311545:
                worked = DbManager.WarehouseQueries.updateGalvor(this, newAmount);
                break;
            case 1532478436:
                worked = DbManager.WarehouseQueries.updateWormwood(this, newAmount);
                break;
            case -697973233:
                worked = DbManager.WarehouseQueries.updateObsidian(this, newAmount);
                break;
            case -1569826353:
                worked = DbManager.WarehouseQueries.updateBloodstone(this, newAmount);
                break;
            case -1761257186:
                worked = DbManager.WarehouseQueries.updateMithril(this, newAmount);
                break;
        }

        if (!worked)
            return false;

        this.resources.put(ib, newAmount);
        Resource resourceType;

        if (ib.getUUID() == 7)
            resourceType = Resource.GOLD;
        else
            resourceType = Resource.valueOf(ib.getName().toUpperCase());

        if (transaction)
            this.AddTransactionToWarehouse(npc.getObjectType(), npc.getObjectUUID(), TransactionType.WITHDRAWL, resourceType, amount);

        return true;
    }

    public synchronized boolean transferResources(PlayerCharacter taxer, TaxResourcesMsg msg, ArrayList<Integer> realmResources, float taxPercent, Warehouse toWarehouse) {

        for (int ibID : realmResources) {

            ItemBase ib = ItemBase.getItemBase(ibID);

            if (ib == null)
                return false;

            if (this.resources.get(ib) == null)
                return false;

            int amount = (int) (this.resources.get(ib) * taxPercent);

            if (amount <= 0) {
                msg.getResources().put(ib.getHashID(), 0);
                continue;
            }

            int oldAmount = this.resources.get(ib);

            if (oldAmount < amount)
                amount = oldAmount;

            int hashID = ib.getHashID();
            int newAmount = oldAmount - amount;

            if (newAmount < amount)
                continue;

            boolean worked = false;

            switch (hashID) {
                case 2308551:
                    worked = DbManager.WarehouseQueries.updateGold(this, newAmount);
                    break;
                case 74856115:
                    worked = DbManager.WarehouseQueries.updateStone(this, newAmount);
                    break;
                case -317484979:
                    worked = DbManager.WarehouseQueries.updateTruesteel(this, newAmount);
                    break;
                case 2504297:
                    worked = DbManager.WarehouseQueries.updateIron(this, newAmount);
                    break;
                case -1741189964:
                    worked = DbManager.WarehouseQueries.updateAdamant(this, newAmount);
                    break;
                case -1603256692:
                    worked = DbManager.WarehouseQueries.updateLumber(this, newAmount);
                    break;
                case 74767:
                    worked = DbManager.WarehouseQueries.updateOak(this, newAmount);
                    break;
                case 1334770447:
                    worked = DbManager.WarehouseQueries.updateBronzewood(this, newAmount);
                    break;
                case 1191391799:
                    worked = DbManager.WarehouseQueries.updateMandrake(this, newAmount);
                    break;
                case 2559427:
                    worked = DbManager.WarehouseQueries.updateCoal(this, newAmount);
                    break;
                case 75173057:
                    worked = DbManager.WarehouseQueries.updateAgate(this, newAmount);
                    break;
                case -1730704107:
                    worked = DbManager.WarehouseQueries.updateDiamond(this, newAmount);
                    break;
                case 2977263:
                    worked = DbManager.WarehouseQueries.updateOnyx(this, newAmount);
                    break;
                case 78329697:
                    worked = DbManager.WarehouseQueries.updateAzoth(this, newAmount);
                    break;
                case -2036290524:
                    worked = DbManager.WarehouseQueries.updateOrichalk(this, newAmount);
                    break;
                case 452320058:
                    worked = DbManager.WarehouseQueries.updateAntimony(this, newAmount);
                    break;
                case -1586349421:
                    worked = DbManager.WarehouseQueries.updateSulfur(this, newAmount);
                    break;
                case -472884509:
                    worked = DbManager.WarehouseQueries.updateQuicksilver(this, newAmount);
                    break;
                case -1596311545:
                    worked = DbManager.WarehouseQueries.updateGalvor(this, newAmount);
                    break;
                case 1532478436:
                    worked = DbManager.WarehouseQueries.updateWormwood(this, newAmount);
                    break;
                case -697973233:
                    worked = DbManager.WarehouseQueries.updateObsidian(this, newAmount);
                    break;
                case -1569826353:
                    worked = DbManager.WarehouseQueries.updateBloodstone(this, newAmount);
                    break;
                case -1761257186:
                    worked = DbManager.WarehouseQueries.updateMithril(this, newAmount);
                    break;
            }

            if (!worked) {
                msg.getResources().put(ib.getHashID(), 0);
                continue;
            }

            msg.getResources().put(ib.getHashID(), amount);

            this.resources.put(ib, newAmount);
            toWarehouse.depositRealmTaxes(taxer, ib, amount);
            Resource resourceType;

            if (ib.getUUID() == 7)
                resourceType = Resource.GOLD;
            else
                resourceType = Resource.valueOf(ib.getName().toUpperCase());

            this.AddTransactionToWarehouse(taxer.getObjectType(), taxer.getObjectUUID(), TransactionType.TAXRESOURCE, resourceType, amount);

        }
        return true;
    }

    public synchronized boolean loot(PlayerCharacter pc, ItemBase ib, int amount, boolean addToInventory) {

        if (pc == null)
            return false;

        if (ib == null)
            return false;

        if (this.resources.get(ib) == null)
            return false;

        if (amount <= 0)
            return false;

        CharacterItemManager itemMan = pc.getCharItemManager();

        if (itemMan == null)
            return false;

        if (!itemMan.hasRoomInventory(ib.getWeight())) {
            ChatManager.chatSystemInfo(pc, "You can not carry any more of that item.");
            return false;
        }

        int oldAmount = this.resources.get(ib);

        if (oldAmount < amount)
            return false;

        int newAmount = oldAmount - amount;

        this.resources.put(ib, newAmount);

        if (addToInventory) {
            if (ib.getUUID() == 7) {

                itemMan.addGoldToInventory(amount, false);
                UpdateGoldMsg ugm = new UpdateGoldMsg(pc);
                ugm.configure();
                Dispatch dispatch = Dispatch.borrow(pc, ugm);
                DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);

                itemMan.updateInventory();
            } else {
                boolean itemWorked = false;
                Item item = new Item(ib, pc.getObjectUUID(), OwnerType.PlayerCharacter, (byte) 0, (byte) 0,
                        (short) 1, (short) 1, true, false, ItemContainerType.INVENTORY, (byte) 0,
                        new ArrayList<>(), "");
                item.setNumOfItems(amount);
                item.containerType = Enum.ItemContainerType.INVENTORY;

                try {
                    item = DbManager.ItemQueries.ADD_ITEM(item);
                    itemWorked = true;
                } catch (Exception e) {
                    Logger.error(e);
                }
                if (itemWorked) {
                    itemMan.addItemToInventory(item);
                    itemMan.updateInventory();
                }
            }
        }

        return true;
    }

    @Override
    public void updateDatabase() {
        // TODO Auto-generated method stub

    }

    @Override
    public void runAfterLoad() {

        try {
            Building warehouseBuilding = BuildingManager.getBuilding(this.buildingUID);
            Logger.info("configuring warehouse " + UID + " for city " + warehouseBuilding.getCity().getCityName() + " structure UUID " + this.buildingUID);

            //Building is gone, but Warehouse still in DB?? Should never happen, sanity check anyway.
            if (warehouseBuilding == null) {
                Logger.error("Failed to load Building for Warehouse");
                return;
            }

            Zone cityZone = warehouseBuilding.getParentZone();

            if (cityZone == null) {
                Logger.error("Failed to load Zone for Warehouse with UUID " + this.getObjectUUID());
                return;
            }

            City city = City.getCity(cityZone.getPlayerCityUUID());

            if (city == null) {
                Logger.error("Failed to load City for Warehouse with UUID " + this.getObjectUUID());
                return;
            }

            warehouseByBuildingUUID.put(this.buildingUID, this);
            city.setWarehouseBuildingID(this.buildingUID);
        } catch (Exception E) {
            Logger.info(this.getObjectUUID() + " failed");

        }
    }

    public boolean isEmpty() {
        int amount = 0;
        for (ItemBase ib : ItemBase.getResourceList()) {
            if (amount > 0)
                return false;
            amount += resources.get(ib);
        }
        return true;
    }

    public int getBuildingUID() {
        return buildingUID;
    }

    public void loadAllTransactions() {
        this.transactions = DbManager.WarehouseQueries.GET_TRANSACTIONS_FOR_WAREHOUSE(this.buildingUID);
    }

    public boolean AddTransactionToWarehouse(GameObjectType targetType, int targetUUID, TransactionType transactionType, Resource resource, int amount) {


        if (!DbManager.WarehouseQueries.CREATE_TRANSACTION(this.buildingUID, targetType, targetUUID, transactionType, resource, amount, DateTime.now()))
            return false;

        Transaction transaction = new Transaction(this.buildingUID, targetType, targetUUID, transactionType, resource, amount, DateTime.now());
        this.transactions.add(transaction);
        return true;
    }

    public ArrayList<Transaction> getTransactions() {
        return transactions;
    }

    public boolean isAboveCap(ItemBase ib, int deposit) {
        int newAmount = this.resources.get(ib) + deposit;
        return newAmount > Warehouse.getMaxResources().get(ib.getUUID());

    }

    public boolean isResourceLocked(ItemBase itemBase) {

        Enum.ResourceType resourceType;

        resourceType = Enum.ResourceType.resourceLookup.get(itemBase.getUUID());

        return resourceType.elementOf(this.lockedResourceTypes);
    }
}