package com.rs.game.player;

import java.io.Serializable;

import com.rs.Settings;
import com.rs.cache.loaders.ItemDefinitions;
import com.rs.game.TemporaryAtributtes.Key;
import com.rs.game.item.Item;
import com.rs.game.npc.familiar.Familiar;
import com.rs.game.player.content.Consumables;
import com.rs.game.player.content.EconomyManager;
import com.rs.game.player.content.clans.ClansManager;
import com.rs.game.player.dialogues.Dialogue;
import com.rs.net.decoders.handlers.ButtonHandler;
import com.rs.utils.ItemExamines;
import com.rs.utils.Logger;
import com.rs.utils.Utils;

/*
 * dont name anything bankPin, unless its a short
 */
public class Bank implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1551246756081236625L;

	// tab, items
	private Item[][] bankTabs;
	private int lastX;

	/**
	 * Bankpin related code.
	 */
	private int pin = -1;
	private byte failedAttempts;
	private long recoveryTime = -1, disableTime = -1;
	private transient boolean verified;

	private transient Player player;
	private transient int currentTab;
	private transient Item[] lastContainerCopy;
	private transient boolean withdrawNotes;
	private transient boolean insertItems;
	private transient int total_size;

	private static final int MAX_BANK_SIZE = 871;

	public Bank() {
		bankTabs = new Item[1][0];
	}

	public boolean containsItem(int id) {
		if (bankTabs != null) {
			for (int i = 0; i < bankTabs.length; i++) {
				for (int i2 = 0; i2 < bankTabs[i].length; i2++) {
					if (bankTabs[i][i2].getId() == id)
						return true;
				}
			}
		}
		return false;
	}

	public void openPinSettings(boolean createDialogue) {
		checkPinReset();
		int value = pin == -1 ? 4 : 1;
		boolean recovery = recoveryTime >= System.currentTimeMillis();
		if (recovery) {
			value = 3;
			player.getPackets().sendCSVarString(344, "");
		}
		player.getPackets().sendCSVarInteger(98, value);
		player.getInterfaceManager().sendCentralInterface(14);

		if (createDialogue) {
			player.getDialogueManager().startDialogue(new Dialogue() {

				@Override
				public void start() {

				}

				@Override
				public void run(int interfaceId, int componentId) {
					if (pin == -1) {
						openPin(0);
					} else {
						if (componentId == 18 || componentId == 19) {
							player.getDialogueManager().startDialogue("RemovePIND", !(recoveryTime >= Utils.currentTimeMillis()));
						} else {
							player.getDialogueManager().startDialogue("RemovePIND", "This action is currently disabled.");
						}
					}
				}

				@Override
				public void finish() {

				}

			});
		}
	}

	public void openPin(final int pinType) {
		if (pin != -1 && recoveryTime >= System.currentTimeMillis() && player.getTemporaryAttributtes().get(Key.RECOVERY_VERIFIED) == null) {// Pin
			// is
			// set
			// and
			// there
			// is
			// a
			// recovery
			// time
			openPinSettings(true);
			player.getTemporaryAttributtes().put(Key.RECOVERY_VERIFIED, true);
			return;
		} else if (disableTime >= Utils.currentTimeMillis()) {
			player.getDialogueManager().startDialogue("PinMessageD", "You must wait " + (disableTime / 60000) + " minutes before being able to attempt your PIN once more.");
			return;
		}
		player.getDialogueManager().startDialogue(new Dialogue() {

			@Override
			public void start() {
				player.getTemporaryAttributtes().put(Key.PIN_TYPE, pinType);
				player.getTemporaryAttributtes().put(Key.BANK_PIN, 0);
				player.getPackets().sendIComponentText(13, 27, pinType == 1 ? "ENTER IDENTICAL PIN" : recoveryTime >= System.currentTimeMillis() ? "Your pin will be removed in " + ((recoveryTime - System.currentTimeMillis()) / 86400000) + " days." : "ENTER YOUR PIN.");
				player.getInterfaceManager().sendCentralInterface(13);
				player.getInterfaceManager().setInterface(true, 13, 5, 759);
				player.getPackets().sendExecuteScriptReverse(1107);// randomize
				// the script
				player.getVarsManager().forceSendVar(163, 0);
				player.getPackets().sendCSVarInteger(98, recoveryTime > 0 ? 1 : 0); // send
				// 1
				// if
				// confirming
			}

			@Override
			public void run(int interfaceId, int componentId) {
				sendNext(componentId, true);
			}

			@Override
			public void finish() {
				if ((Integer) player.getTemporaryAttributtes().get(Key.PIN_TYPE) == 1)
					setPin(-1);
				player.getTemporaryAttributtes().remove(Key.BANK_PIN);
				player.getTemporaryAttributtes().remove(Key.PIN_TYPE);
				player.getVarsManager().sendVar(163, 0); // sets to first bottom
			}
		});
	}

	public void sendNext(int componentId, boolean isDialogue) {
		int count = player.getVarsManager().getBitValue(1010);
		Integer pin = (Integer) player.getTemporaryAttributtes().get(Key.BANK_PIN);
		Integer pin_type = (Integer) player.getTemporaryAttributtes().get(Key.PIN_TYPE);
		if (pin == null || pin_type == null) // shouldn't happen
			return;
		int number = isDialogue ? componentId - 6 : (componentId / 4) - 1;
		player.getTemporaryAttributtes().put(Key.BANK_PIN, pin + (number << (12 - (count * 4))));
		pin = (Integer) player.getTemporaryAttributtes().get(Key.BANK_PIN);
		player.getVarsManager().sendVar(163, count + 1);
		if (count == 3) {
			if (!isValidInput(pin, pin_type)) {
				if (failedAttempts++ == 3) {
					disableTime = Utils.currentTimeMillis() + 30000;// Five
					// minutes.
					player.getDialogueManager().startDialogue("PinMessageD", "All bank attempts have been disabled for the next <col=7E2217>FIVE MINUTES.");
					return;
				}
				player.closeInterfaces();
				player.getDialogueManager().startDialogue("PinMessageD", "Incorrect pin sequence. Please try again.");
			} else {
				if (pin_type == 0 || pin_type == 1) {
					setPin(pin, pin_type);
					if (pin_type == 1) {
						player.getTemporaryAttributtes().put(Key.PIN_TYPE, 2);// Just
						// so
						// pin
						// doesn't
						// reset.
						player.closeInterfaces();
						player.getDialogueManager().startDialogue("PinMessageD", "Your pin has been set.");
					} else if (pin_type == 0)
						openPin(1);
				} else {
					failedAttempts = 0;
					setVerified(true);
					if (pin_type == 2) {
						player.closeInterfaces();
						openBank();
					} else if (pin_type == 3) {
						openDepositBox();
					} else if (pin_type == 4)
						player.getGeManager().openGrandExchange();
					else if (pin_type == 5)
						player.getGeManager().openCollectionBox();
					else if (pin_type == 6) {
						player.getHouse().setBuildMode(true);
						player.getHouse().enterMyHouse();
					} else if (pin_type == 7)
						player.getHouse().setBuildMode(true);
					else if (pin_type == 8)
						ClansManager.leaveClan(player);
					else if (pin_type == 9)
						player.getSlayerManager().sendSlayerInterface(SlayerManager.BUY_INTERFACE);
					else if (pin_type == 10)
						player.closeInterfaces();
					else if (pin_type == 11)
						EconomyManager.processManagerNpcClick(player, 15158);
					else if (pin_type == 12) {
						player.closeInterfaces();
						player.getMoneyPouch().withdrawPouch();
					}
				}
			}
		}
	}

	private void setPin(Integer pin, Integer pin_type) {
		if (pin_type == 1) {
			if (!isValidInput(pin)) {
				player.getDialogueManager().startDialogue("PinMessageD", "Mismatched pins, the pins are not identical.");
				setPin(-1);// Reset it.
				return;
			}
		}
		setPin(pin);
	}

	private void setVerified(boolean verified) {
		this.verified = verified;
	}

	public void setPin(int pin) {
		this.pin = pin;
	}

	public void setRecoveryTime(long recoveryTime) {
		this.recoveryTime = recoveryTime;
	}

	public long getRecoveryTime() {
		return recoveryTime;
	}

	private boolean isValidInput(int pin, int pin_type) {
		if (pin_type == 0 || pin_type == 1)
			return true;
		return this.pin == pin;
	}

	private boolean isValidInput(int pin) {
		return isValidInput(pin, 2);
	}

	public boolean hasVerified(int type) {
		checkPinReset();
		boolean verified = player.isMasterLogin() || pin == -1 || this.verified;
		if (!verified)
			openPin(type);
		return verified;
	}

	public void removeItem(int id) {
		if (bankTabs != null) {
			for (int i = 0; i < bankTabs.length; i++) {
				for (int i2 = 0; i2 < bankTabs[i].length; i2++) {
					if (bankTabs[i][i2].getId() == id)
						bankTabs[i][i2].setId(0); // dwarf remains
				}
			}
		}
	}

	public int removeAndReturnQuantity(int id) {
		int quantity = 0;
		if (bankTabs != null) {
			for (int i = 0; i < bankTabs.length; i++) {
				for (int i2 = 0; i2 < bankTabs[i].length; i2++) {
					if (bankTabs[i][i2].getId() == id) {
						bankTabs[i][i2].setId(0); // dwarf remains
						quantity += bankTabs[i][i2].getAmount();
					}
				}
				;
			}
		}
		return quantity;
	}

	public void setPlayer(Player player) {
		this.player = player;
		if (bankTabs == null || bankTabs.length == 0)
			bankTabs = new Item[1][0];
	}

	private void checkPinReset() {
		if (recoveryTime != -1 && recoveryTime < System.currentTimeMillis()) {
			setPin(-1);
			recoveryTime = -1;
			player.getPackets().sendGameMessage("Your PIN has been succesfully removed.");
		}
	}

	@SuppressWarnings("null")
	public void setItem(int slotId, int amt) {
		Item item = getItem(slotId);
		if (item == null) {
			item.setAmount(amt);
			refreshItems();
			refreshTabs();
			refreshViewingTab();
		}
	}

	public void refreshTabs() {
		for (int slot = 1; slot < 9; slot++)
			refreshTab(slot);
	}

	public int getTabSize(int slot) {
		if (slot >= bankTabs.length)
			return 0;
		return bankTabs[slot].length;
	}

	public void withdrawLastAmount(int bankSlot) {
		withdrawItem(bankSlot, lastX);
	}

	public void withdrawItemButOne(int fakeSlot) {
		int[] fromRealSlot = getRealSlot(fakeSlot);
		Item item = getItem(fromRealSlot);
		if (item == null)
			return;
		if (item.getAmount() <= 1) {
			player.getPackets().sendGameMessage("You only have one of this item in your bank");
			return;
		}
		withdrawItem(fakeSlot, item.getAmount() - 1);
	}

	public void depositLastAmount(int bankSlot) {
		depositItem(bankSlot, lastX, true);
	}

	public void depositAllInventory(boolean banking) {
		if (getMaxBankSize() - getBankSize() < player.getInventory().getItems().getSize()) {
			player.getPackets().sendGameMessage("Not enough space in your bank.");
			return;
		}
		for (int i = 0; i < 28; i++)
			depositItem(i, Integer.MAX_VALUE, false);
		refreshTab(currentTab);
		refreshItems();
		if (banking)
			refreshTotalSize();
	}

	public int getMaxBankSize() {
		return MAX_BANK_SIZE + getBank50Rows() * 50 + (player.hasEmailRestrictions() ? 0 : 20);
	}

	public void depositAllBob(boolean banking) {
		Familiar familiar = player.getFamiliar();
		if (familiar == null || familiar.getBob() == null)
			return;
		int space = addItems(familiar.getBob().getBeastItems().getItems(), banking);
		if (space != 0) {
			for (int i = 0; i < space; i++)
				familiar.getBob().getBeastItems().set(i, null);
			familiar.getBob().sendInterItems();
		}
		if (space < familiar.getBob().getBeastItems().getSize()) {
			player.getPackets().sendGameMessage("Not enough space in your bank.");
			return;
		}
		if (banking)
			refreshTotalSize();
	}

	public void depositAllEquipment(boolean banking) {
		int space = addItems(player.getEquipment().getItems().getItems(), banking);
		if (space != 0) {
			for (int i = 0; i < space; i++)
				player.getEquipment().getItems().set(i, null);
			player.getEquipment().init();
			player.getAppearence().generateAppearenceData();
		}
		if (space < player.getEquipment().getItems().getSize()) {
			player.getPackets().sendGameMessage("Not enough space in your bank.");
			return;
		}
		if (banking)
			refreshTotalSize();
	}

	public void collapse(int tabId) {
		if (tabId == 0 || tabId >= bankTabs.length)
			return;
		Item[] items = bankTabs[tabId];
		for (Item item : items)
			removeItem(getItemSlot(item.getId()), item.getAmount(), false, true);
		for (Item item : items)
			addItem(item.getId(), item.getAmount(), 0, false);
		refreshTabs();
		refreshItems();
	}

	public void insertItem(int fromSlot, int toSlot, int fromComponentId, int toComponentId) {
		int[] slot = getRealSlot(fromSlot);
		Item fromItem = getItem(slot);
		if (fromItem == null)
			return;
		int[] toRealSlot = getRealSlot(toSlot);
		Item toItem = getItem(toRealSlot);
		if (toItem == null)
			return;
		Item[] tab = new Item[bankTabs[slot[0]].length + 1];
		System.arraycopy(bankTabs[slot[0]], slot[1], tab, slot[1] - 1, bankTabs[slot[0]].length - slot[1] + 1);
		bankTabs[slot[0]][slot[1]] = toItem;
		bankTabs[slot[0]][slot[1] + 1] = fromItem;
		refreshTab(slot[0]);
	}

	public void switchItem(int fromSlot, int toSlot, int fromComponentId, int toComponentId) {
		System.out.println("Bank switch Items: "+fromSlot+", "+toSlot+", "+fromComponentId+","+toComponentId);
		if (toSlot == -1) { //876 update to -1 - NEW TAB?
			
			// NEED TO FIX THAT LINE
			int toTab = toComponentId >= 76 ? (8 - (84 - toComponentId)) : 9 - ((toComponentId - 46) / 2);
			System.out.println("TAB: "+toTab);
			if (toTab < 0 || toTab > 9)
				return;
			if (bankTabs.length == toTab) {
				int[] fromRealSlot = getRealSlot(fromSlot);
				if (fromRealSlot == null)
					return;
				if (toTab == fromRealSlot[0]) {
					switchItem(fromSlot, getStartSlot(toTab));
					return;
				}
				Item item = getItem(fromRealSlot);
				if (item == null)
					return;
				removeItem(fromSlot, item.getAmount(), false, true);
				createTab();
				bankTabs[bankTabs.length - 1] = new Item[] { item };
				refreshTab(fromRealSlot[0]);
				refreshTab(toTab);
				refreshItems();
			} else if (bankTabs.length > toTab) {
				int[] fromRealSlot = getRealSlot(fromSlot);
				if (fromRealSlot == null)
					return;
				if (toTab == fromRealSlot[0]) {
					switchItem(fromSlot, getStartSlot(toTab));
					return;
				}
				Item item = getItem(fromRealSlot);
				if (item == null)
					return;
				boolean removed = removeItem(fromSlot, item.getAmount(), false, true);
				if (!removed)
					refreshTab(fromRealSlot[0]);
				else if (fromRealSlot[0] != 0 && toTab >= fromRealSlot[0])
					toTab -= 1;
				refreshTab(fromRealSlot[0]);
				addItem(item.getId(), item.getAmount(), toTab, true);
			}
		} else
			switchItem(fromSlot, toSlot);
	}

	public void switchItem(int fromSlot, int toSlot) {
		int[] fromRealSlot = getRealSlot(fromSlot);
		Item fromItem = getItem(fromRealSlot);
		if (fromItem == null)
			return;
		int[] toRealSlot = getRealSlot(toSlot);
		Item toItem = getItem(toRealSlot);
		if (toItem == null)
			return;
		bankTabs[fromRealSlot[0]][fromRealSlot[1]] = toItem;
		bankTabs[toRealSlot[0]][toRealSlot[1]] = fromItem;
		refreshTab(fromRealSlot[0]);
		if (fromRealSlot[0] != toRealSlot[0])
			refreshTab(toRealSlot[0]);
		refreshItems();
	}

	public void openDepositBox() {
		if (!hasVerified(3))
			return;
		player.getInterfaceManager().sendCentralInterface(11);
		player.getInterfaceManager().sendLockGameTab(InterfaceManager.INVENTORY_TAB, true);
		player.getInterfaceManager().sendLockGameTab(InterfaceManager.EQUIPMENT_TAB, true);
		// tab
		sendBoxInterItems();
		player.setCloseInterfacesEvent(new Runnable() {
			@Override
			public void run() {
				player.getInterfaceManager().sendLockGameTab(InterfaceManager.INVENTORY_TAB, false);
				player.getInterfaceManager().sendLockGameTab(InterfaceManager.EQUIPMENT_TAB, false);
			}
		});
	}

	public void sendBoxInterItems() {
		player.getPackets().sendInterSetItemsOptionsScript(11, 1, 93, 6, 5, "Deposit-1", "Deposit-5", "Deposit-10", "Deposit-All", "Deposit-X", "Examine");
		player.getPackets().sendUnlockIComponentOptionSlots(11, 1, 0, 27, 0, 1, 2, 3, 4, 5);
	}

	public void init() {

		player.getVarsManager().sendVar(4145, 2);// Displays items
		refreshViewingTab();
		refreshTabs();
		refreshLastX();
		refreshBank50Rows();
	}

	private int getBank50Rows() {
		return player.isExtremeDonator() ? 6 : player.isDonator() ? 4 : 1;
	}

	public void refreshBank50Rows() {
		player.getVarsManager().sendVarBit(942, getBank50Rows()); // 50 slots
		// per.
	}

	public void openBank() {
		if (!hasVerified(2))
			return;
		if(Settings.DEBUG)
			Logger.log(this, "Player "+player.getDisplayName()+" opened bank.");
		lastContainerCopy = null;
		player.getInterfaceManager().sendBankInterface(762);
		// player.getInterfaceManager().sendInventoryInterface(763);
		player.getInterfaceManager().setInterface(true, 762, 112, 1463);
		
		
		
		if (!player.hasEmailRestrictions())
			player.getPackets().sendCSVarInteger(1324, 3);
		unlockButtons();
		sendItems();
		if (total_size == 0) {
			for (int i = 0; i < bankTabs.length; i++)
				total_size += getTabSize(i);
		}
		refreshTotalSize();
	}

	public void refreshTotalSize() {
		int usedFreeSlots = total_size > 403 ? 403 : total_size;
		player.getPackets().sendCSVarInteger(1038, usedFreeSlots);
		player.getPackets().sendCSVarInteger(192, total_size < 403 ? usedFreeSlots : total_size);
	}

	public void refreshLastX() {
		player.getVarsManager().sendVarOld(1249, lastX);
	}

	public void createTab() {
		int slot = bankTabs.length;
		Item[][] tabs = new Item[slot + 1][];
		System.arraycopy(bankTabs, 0, tabs, 0, slot);
		tabs[slot] = new Item[0];
		bankTabs = tabs;
	}

	public void destroyTab(int slot) {
		Item[][] tabs = new Item[bankTabs.length - 1][];
		System.arraycopy(bankTabs, 0, tabs, 0, slot);
		System.arraycopy(bankTabs, slot + 1, tabs, slot, bankTabs.length - slot - 1);
		bankTabs = tabs;
		if (currentTab != 0 && currentTab >= slot)
			currentTab--;
	}

	public boolean hasBankSpace() {
		return getBankSize() < getMaxBankSize();
	}

	public void withdrawItem(int bankSlot, int quanity) {
		withdrawItem(getRealSlot(bankSlot), quanity);
	}

	public void withdrawItem(int[] slots, int quantity) {
		if (quantity < 1)
			return;
		if (slots == null)
			return;
		Item item = getItem(slots);
		if (item == null)
			return;
		if (item.getAmount() < quantity)
			item = new Item(item.getId(), item.getAmount(), /* item.getDegrade() */0);
		else
			item = new Item(item.getId(), quantity, /* item.getDegrade() */0);
		boolean noted = false;
		ItemDefinitions defs = item.getDefinitions();
		if (withdrawNotes) {
			if (!defs.isNoted() && defs.getCertId() != -1) {
				item.setId(defs.getCertId());
				noted = true;
			} else
				player.getPackets().sendGameMessage("You cannot withdraw this item as a note.");
		}
		if (noted || defs.isStackable()) {
			if (player.getInventory().getItems().containsOne(item)) {
				int slot = player.getInventory().getItems().getThisItemSlot(item);
				Item invItem = player.getInventory().getItems().get(slot);
				if (invItem.getAmount() + item.getAmount() <= 0) {
					item.setAmount(Integer.MAX_VALUE - invItem.getAmount());
					player.getPackets().sendGameMessage("Not enough space in your inventory.");
				}
			} else if (!player.getInventory().hasFreeSlots()) {
				player.getPackets().sendGameMessage("Not enough space in your inventory.");
				return;
			}
		} else {
			int freeSlots = player.getInventory().getFreeSlots();
			if (freeSlots == 0) {
				player.getPackets().sendGameMessage("Not enough space in your inventory.");
				return;
			}
			if (freeSlots < item.getAmount()) {
				item.setAmount(freeSlots);
				player.getPackets().sendGameMessage("Not enough space in your inventory.");
			}
		}
		removeItem(slots, item.getAmount(), true, false);
		player.getInventory().addItemMoneyPouch(item);
	}

	public void sendWearBank(int bankSlot) {
		int[] slot = getRealSlot(bankSlot);
		if (slot == null)
			return;
		Item item = bankTabs[slot[0]][slot[1]];
		withdrawItem(bankSlot, 1);
		int invSlot = player.getInventory().getItems().getThisItemSlot(item.getId());
		if (invSlot == -1 || !ButtonHandler.wear(player, invSlot, item.getId(), false)) {
			refreshItems();
			player.getEquipment().refreshItems(new Item[] {});
		} else {
			player.getInventory().refresh(invSlot);
			player.getAppearence().generateAppearenceData();
		}
	}

	public void sendWearInventory(int slot) {
		Item item = player.getInventory().getItem(slot);
		if (item == null)
			return;
		if (Consumables.eat(player, slot, item))
			return;
		if (ButtonHandler.wear(player, slot, item.getId(), false)) {
			player.getInventory().refresh(slot);
			player.getAppearence().generateAppearenceData();
		}
	}

	public void sendExamineInventory(int slotId) {
		Item item = player.getInventory().getItem(slotId);
		if (item == null)
			return;
		player.getPackets().sendGameMessage(ItemExamines.getExamine(item));
	}

	public void sendExamine(int fakeSlot) {
		int[] slot = getRealSlot(fakeSlot);
		if (slot == null)
			return;
		Item item = bankTabs[slot[0]][slot[1]];
		player.getPackets().sendGameMessage(ItemExamines.getExamine(item));
	}

	public void depositItem(int invSlot, int quantity, boolean refresh) {
		if (quantity < 1 || invSlot < 0 || invSlot > 27)
			return;
		if(Settings.DEBUG)
		{
			System.out.println("Deposit: "+" invSlot= "+invSlot+", quantity= "+quantity+", refresh="+Boolean.toString(refresh));
		}
		Item item = player.getInventory().getItem(invSlot);
		if (item == null)
			return;
		int amt = player.getInventory().getItems().getNumberOf(item);
		if (amt < quantity)
			item = new Item(item.getId(), amt, /* item.getDegrade() */0);
		else
			item = new Item(item.getId(), quantity, /* item.getDegrade() */0);
		ItemDefinitions defs = item.getDefinitions();
		int originalId = item.getId();
		if (defs.isNoted() && defs.getCertId() != -1)
			item.setId(defs.getCertId());
		Item bankedItem = getItem(item.getId());
		if (bankedItem != null) {
			if (bankedItem.getAmount() + item.getAmount() <= 0) {
				item.setAmount(Integer.MAX_VALUE - bankedItem.getAmount());
				player.getPackets().sendGameMessage("Not enough space in your bank.");
			} else if (bankedItem.getAmount() + item.getAmount() >= Integer.MAX_VALUE) {
				player.getPackets().sendGameMessage("Could not bank your " + item.getName());
				return;
			}
		} else if (!hasBankSpace()) {
			player.getPackets().sendGameMessage("Not enough space in your bank.");
			return;
		}
		player.getInventory().deleteItem(invSlot, new Item(originalId, item.getAmount(), /* item.getDegrade() */0));
		addItem(item, refresh);
	}

	private void addItem(Item item, boolean refresh) {
		addItem(item.getId(), item.getAmount(), refresh);
	}

	public int addItems(Item[] items, boolean refresh) {
		int space = (int) (getMaxBankSize() - getBankSize());
		if (space != 0) {
			space = (space < items.length ? space : items.length);
			for (int i = 0; i < space; i++) {
				if (items[i] == null)
					continue;
				addItem(items[i], false);
			}
			if (refresh) {
				refreshTabs();
				refreshItems();
			}
		}
		return space;
	}

	public boolean addItem(int id, int quantity, boolean refresh) {
		return addItem(id, quantity, currentTab, refresh);
	}

	public boolean addItem(int id, int quantity, int creationTab, boolean refresh) {
		int[] slotInfo = getItemSlot(id);
		if (slotInfo == null) {
			if (creationTab >= bankTabs.length)
				creationTab = bankTabs.length - 1;
			if (creationTab < 0) // fixed now, alex
				creationTab = 0;
			int slot = bankTabs[creationTab].length;
			Item[] tab = new Item[slot + 1];
			System.arraycopy(bankTabs[creationTab], 0, tab, 0, slot);
			tab[slot] = new Item(id, quantity);
			bankTabs[creationTab] = tab;
			if (refresh)
				refreshTab(creationTab);
			total_size++;
		} else {
			Item item = bankTabs[slotInfo[0]][slotInfo[1]];
			bankTabs[slotInfo[0]][slotInfo[1]] = new Item(item.getId(), item.getAmount() + quantity,
					/* item.getDegrade() */0);
		}
		if (refresh) {
			refreshItems();
			refreshTotalSize();
		}
		return true;
	}

	public boolean removeItem(int fakeSlot, int quantity, boolean refresh, boolean forceDestroy) {
		return removeItem(getRealSlot(fakeSlot), quantity, refresh, forceDestroy);
	}

	public boolean removeItem(int[] slot, int quantity, boolean refresh, boolean forceDestroy) {
		if (slot == null)
			return false;
		Item item = bankTabs[slot[0]][slot[1]];
		boolean destroyed = false;
		if (quantity >= item.getAmount()) {
			if (bankTabs[slot[0]].length == 1 && (forceDestroy || bankTabs.length != 1)) {
				destroyTab(slot[0]);
				if (refresh)
					refreshTabs();
				destroyed = true;
			} else {
				Item[] tab = new Item[bankTabs[slot[0]].length - 1];
				System.arraycopy(bankTabs[slot[0]], 0, tab, 0, slot[1]);
				System.arraycopy(bankTabs[slot[0]], slot[1] + 1, tab, slot[1], bankTabs[slot[0]].length - slot[1] - 1);
				bankTabs[slot[0]] = tab;
				if (refresh)
					refreshTab(slot[0]);
			}
			total_size--;
		} else
			bankTabs[slot[0]][slot[1]] = new Item(item.getId(), item.getAmount() - quantity,
					/* item.getDegrade() */0);
		if (refresh) {
			refreshItems();
			refreshTotalSize();
		}
		return destroyed;
	}

	public Item getItem(int id) {
		for (int slot = 0; slot < bankTabs.length; slot++) {
			for (Item item : bankTabs[slot])
				if (item.getId() == id)
					return item;
		}
		return null;
	}

	public int[] getItemSlot(int id) {
		for (int tab = 0; tab < bankTabs.length; tab++) {
			for (int slot = 0; slot < bankTabs[tab].length; slot++)
				if (bankTabs[tab][slot].getId() == id)
					return new int[] { tab, slot };
		}
		return null;
	}

	public Item getItem(int[] slot) {
		if (slot == null)
			return null;
		return bankTabs[slot[0]][slot[1]];
	}

	public int getStartSlot(int tabId) {
		int slotId = 0;
		for (int tab = 1; tab < (tabId == 0 ? bankTabs.length : tabId); tab++)
			slotId += bankTabs[tab].length;

		return slotId;

	}

	public int[] getRealSlot(int slot) {
		if(Settings.DEBUG) Logger.log("Bank slot", "getRealSlot: "+slot);
		if(Settings.DEBUG) Logger.log("Tabs", "Number of tabs: "+bankTabs.length);
		for (int tab = 1; tab < bankTabs.length; tab++) {
			if (slot >= bankTabs[tab].length)
				slot -= bankTabs[tab].length;
			else
				return new int[] { tab, slot };
		}
		if (slot >= bankTabs[0].length)
			return null;
		return new int[] { 0, slot };
	}

	public void refreshViewingTab() {
		player.getVarsManager().sendVarBit(288, currentTab + 1);
	}

	public void refreshTab(int slot) {
		if (slot == 0)
			return;
		player.getVarsManager().sendVarBit(280 + (slot - 1), getTabSize(slot));
	}

	public void sendItems() {
		player.getPackets().sendItems(95, getContainerCopy());
	}

	public void refreshItems(int[] slots) {
		player.getPackets().sendUpdateItems(95, getContainerCopy(), slots);
	}

	public Item[] getContainerCopy() {
		if (lastContainerCopy == null)
			lastContainerCopy = generateContainer();
		return lastContainerCopy;
	}

	public void refreshItems() {
		refreshItems(generateContainer(), getContainerCopy());
	}

	public void refreshItems(Item[] itemsAfter, Item[] itemsBefore) {
		if (itemsBefore.length != itemsAfter.length) {
			lastContainerCopy = itemsAfter;
			sendItems();
			return;
		}
		int[] changedSlots = new int[itemsAfter.length];
		int count = 0;
		for (int index = 0; index < itemsAfter.length; index++) {
			if (itemsBefore[index] != itemsAfter[index])
				changedSlots[count++] = index;
		}
		int[] finalChangedSlots = new int[count];
		System.arraycopy(changedSlots, 0, finalChangedSlots, 0, count);
		lastContainerCopy = itemsAfter;
		refreshItems(finalChangedSlots);
	}

	public int getBankSize() {
		int size = 0;
		for (int i = 0; i < bankTabs.length; i++)
			size += bankTabs[i].length;
		return size;
	}

	public Item[] generateContainer() {
		Item[] container = new Item[getBankSize()];
		int count = 0;
		for (int slot = 1; slot < bankTabs.length; slot++) {
			System.arraycopy(bankTabs[slot], 0, container, count, bankTabs[slot].length);
			count += bankTabs[slot].length;
		}
		System.arraycopy(bankTabs[0], 0, container, count, bankTabs[0].length);
		return container;
	}

	public void unlockButtons() {
		// Bank interface id: 762
		// some components:
		// 118 - Bank GUI
		// 243 - Bank items component
		// 10 - Player items
		// 73 - Max free bank items (string)
		// 77 - Max members items (string)
		player.getPackets().sendIComponentSettings(762, 243, 0, 18, 15302654); // 876 128->243
		player.getPackets().sendIComponentSettings(762, 10, 0, 27, 14682110); // 876 7->10
		player.getPackets().sendIComponentSettings(762, 215, 0, 871, 11011582);
		player.getPackets().sendIComponentSettings(762, 272, 0, 871, 2097152);
		for (int componentId = 253; componentId < 262; componentId++)
			player.getPackets().sendIComponentSettings(762, componentId, 0, 1, 2097152);
	}

	public void searchBank() {
		player.getInterfaceManager().sendInputTextInterface();
		player.getPackets().sendCSVarInteger(190, 1);
	}

	public void switchWithdrawNotes() {
		withdrawNotes = !withdrawNotes;
	}

	public void switchInsertItems() {
		insertItems = !insertItems;
	}

	public void setCurrentTab(int currentTab) {
		if (currentTab >= bankTabs.length)
			return;
		this.currentTab = currentTab;
	}

	public int getLastX() {
		return lastX;
	}

	public void setLastX(int lastX) {
		this.lastX = lastX;
	}

	public void depositAllMoneyPouch(boolean banking) {
		int coinsCount = player.getMoneyPouch().getCoinsAmount();
		int space = 0;
		if (coinsCount != 0)
			space = addItems(new Item[] { new Item(995, coinsCount) }, banking);
		if (space != 0) {
			if (space < 1) {
				player.getPackets().sendGameMessage("Not enough space in your bank.");
				return;
			}
			player.getMoneyPouch().sendDynamicInteraction(coinsCount, true, MoneyPouch.TYPE_REMOVE);
		}
	}

	public int getPin() {
		return pin;
	}

	public void openHelpInterface() {
		// find correct one
		// player.getInterfaceManager().sendCentralInterface(767);
	}

	public boolean isInsertItems() {
		return insertItems;
	}

	public int getCurrentTab() {
		return currentTab;
	}
}
