package com.rs.game.player;

import java.io.Serializable;

import com.rs.cache.loaders.BodyDefinitions;
import com.rs.cache.loaders.ItemDefinitions;
import com.rs.game.Animation;
import com.rs.game.EffectsManager.EffectType;
import com.rs.game.Entity;
import com.rs.game.TemporaryAtributtes.Key;
import com.rs.game.WorldTile;
import com.rs.game.item.Item;
import com.rs.game.item.ItemsContainer;
import com.rs.game.npc.NPC;
import com.rs.game.player.actions.Bonfire;
import com.rs.game.player.content.ItemConstants;
import com.rs.game.player.content.ItemTransportation;
import com.rs.game.player.content.Magic;
import com.rs.game.player.content.SkillCapeCustomizer;
import com.rs.game.player.content.grandExchange.GrandExchange;
import com.rs.game.player.controllers.SorceressGarden;
import com.rs.net.decoders.WorldPacketsDecoder;
import com.rs.net.decoders.handlers.ButtonHandler;
import com.rs.utils.ItemExamines;
import com.rs.utils.ItemWeights;
import com.rs.utils.Utils;

public final class Equipment implements Serializable {

	private static final long serialVersionUID = -4147163237095647617L;

	public static final byte SLOT_HAT = 0, SLOT_CAPE = 1, SLOT_AMULET = 2, SLOT_WEAPON = 3, SLOT_CHEST = 4, SLOT_SHIELD = 5, SLOT_LEGS = 7, SLOT_HANDS = 9, SLOT_FEET = 10, SLOT_RING = 12, SLOT_ARROWS = 13, SLOT_AURA = 14, SLOT_POCKET = 15, SLOT_WINGS = 17;

	private ItemsContainer<Item> items;
	private ItemsContainer<Item> cosmeticItems;

	private transient Player player;
	private transient int equipmentHpIncrease;
	private transient double equipmentWeight;
	private int costumeColor;

	public Equipment() {
		items = new ItemsContainer<Item>(BodyDefinitions.getEquipmentContainerSize(), false);
		cosmeticItems = new ItemsContainer<Item>(BodyDefinitions.getEquipmentContainerSize(), false);
	}

	public void setPlayer(Player player) {
		this.player = player;
	}

	public void init() {
		player.getPackets().sendItems(94, items);
		refresh(null);
	}

	public void checkItems() {
		int size = items.getSize();
		int newSize = BodyDefinitions.getEquipmentContainerSize();
		if (size != newSize) {
			Item[] copy = items.getItemsCopy();
			items = new ItemsContainer<Item>(newSize, false);
			cosmeticItems = new ItemsContainer<Item>(newSize, false);
			items.addAll(copy);
		} else if (cosmeticItems == null) // temporary
			cosmeticItems = new ItemsContainer<Item>(newSize, false);

		for (int i = 0; i < size; i++) {
			Item item = items.get(i);
			if (item == null)
				continue;
			if (!ItemConstants.canWear(item, player)) {
				items.set(i, null);
				player.getInventory().addItemDrop(item.getId(), item.getAmount());
			}
		}
	}

	public void refresh(int... slots) {
		if (slots != null)
			player.getPackets().sendUpdateItems(94, items, slots);
		player.getCombatDefinitions().refreshBonuses();
		refreshConfigs(slots == null);
	}

	public void reset() {
		items.reset();
		init();
	}

	public Item getItem(int slot) {
		return items.get(slot);
	}

	public void sendExamine(int slotId) {
		Item item = items.get(slotId);
		if (item == null)
			return;
		player.getPackets().sendInterfaceMessage(1464, 15, 0, slotId, ItemExamines.getExamine(item) + (ItemConstants.isTradeable(item) ? "<br>GE guide price: " + GrandExchange.getPrice(item.getId()) + " gp" : ""));
	}

	public void handleEquipment(int slotId, int itemId, int packetId) {
		Item item = getItem(slotId);
		if (item == null || item.getId() != itemId)
			return;
		if (packetId == WorldPacketsDecoder.ACTION_BUTTON1_PACKET || (slotId == Equipment.SLOT_AURA && packetId == WorldPacketsDecoder.ACTION_BUTTON4_PACKET))
			ButtonHandler.sendRemove(player, slotId, false);
		else if (packetId == WorldPacketsDecoder.ACTION_BUTTON8_PACKET)
			sendExamine(slotId);
		else {

			int option = packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET ? 0 : packetId == WorldPacketsDecoder.ACTION_BUTTON3_PACKET ? 1 : packetId == WorldPacketsDecoder.ACTION_BUTTON4_PACKET ? 2 : packetId == WorldPacketsDecoder.ACTION_BUTTON5_PACKET ? 3 : -1;

			if (item.getDefinitions().containsEquipmentOption(option, "Inspect") || item.getDefinitions().containsEquipmentOption(option, "Check") || item.getDefinitions().containsEquipmentOption(option, "Check state") || item.getDefinitions().containsEquipmentOption(option, "Check-charges") || item.getDefinitions().containsEquipmentOption(option, "Check charges")) {
				if (player.getCharges().checkCharges(item))
					return;
			}

			switch (slotId) {
			case Equipment.SLOT_HAT:
				if (packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET) {
					int hatId = player.getEquipment().getHatId();
					if (hatId == 24437 || hatId == 24439 || hatId == 24440 || hatId == 24441)
						player.getDialogueManager().startDialogue("FlamingSkull", player.getEquipment().getItem(Equipment.SLOT_HAT), -1);
				}
				break;
			case Equipment.SLOT_CAPE:
				if (packetId == WorldPacketsDecoder.ACTION_BUTTON9_PACKET) {
					int capeId = player.getEquipment().getCapeId();
					if (capeId == 20769 || capeId == 20771 || capeId == 32152 || capeId == 32153)
						SkillCapeCustomizer.startCustomizing(player, capeId);
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET) {
					int capeId = player.getEquipment().getCapeId();
					if (capeId == 20767 || capeId == 32151)
						SkillCapeCustomizer.startCustomizing(player, capeId);
					else if (capeId == 20763 || capeId == 24709)
						player.getEmotesManager().useBookEmote(39);
				}
				break;
			case Equipment.SLOT_AMULET:
				if (packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET) {
					if (item.getDefinitions().containsEquipmentOption(0, "Rub")) {
						ItemTransportation.transportationDialogue(player, item, true);
						return;
					}
					ItemTransportation.sendTeleport(player, item, 0, true);
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON3_PACKET) {
					ItemTransportation.sendTeleport(player, player.getEquipment().getItem(Equipment.SLOT_AMULET), 1, true);
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON4_PACKET) {
					ItemTransportation.sendTeleport(player, player.getEquipment().getItem(Equipment.SLOT_AMULET), 2, true);
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON5_PACKET) {
					ItemTransportation.sendTeleport(player, player.getEquipment().getItem(Equipment.SLOT_AMULET), 3, true);
				}
				break;
			case Equipment.SLOT_WEAPON:
				if (packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET) {
					int weaponId = player.getEquipment().getWeaponId();
					if (weaponId == 15484)
						player.getInterfaceManager().gazeOrbOfOculus();
					else if (weaponId == 14057) // broomstick
						player.setNextAnimation(new Animation(10532));
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON3_PACKET) {
					int weaponId = player.getEquipment().getWeaponId();
					if (weaponId == 14057) // broomstick
						SorceressGarden.teleportToSocreressGarden(player, true);
				}
				break;
			case Equipment.SLOT_SHIELD:
				if (packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET) {
					int shieldId = player.getEquipment().getShieldId();
					if (shieldId == 11283) {
						if (player.getDFSDelay() >= Utils.currentTimeMillis()) {
							player.getPackets().sendGameMessage("You must wait two minutes before performing this attack once more.");
							return;
						}
						player.getTemporaryAttributtes().put("dfs_shield_active", true);
					} else if (shieldId == 11284)
						player.getPackets().sendGameMessage("You don't have any charges in your shield.");
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON3_PACKET) {
					if (item.getDefinitions().containsEquipmentOption(1, "Provoke")) {
						Entity target = player.getCombatDefinitions().getCurrentTarget();
						if (target == null || !(target instanceof NPC)) {
							player.getPackets().sendGameMessage("You can't use provoke without a target.");
							return;
						}
						Long cd = (Long) player.getTemporaryAttributtes().get(Key.PROVOKE);
						if (cd != null && cd > Utils.currentWorldCycle()) {
							player.getPackets().sendGameMessage("You can't use provoke while it is on cooldown.");
							return;
						}
						player.getTemporaryAttributtes().put(Key.PROVOKE, Utils.currentWorldCycle() + 20);
						player.setNextAnimation(new Animation(18130));
						if (target instanceof NPC)
							((NPC) target).setTarget(player);
					}
				}
				break;
			case Equipment.SLOT_HANDS:
				if (packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET) {
					int glovesId = player.getEquipment().getGlovesId();
					if ((glovesId >= 24450 && glovesId <= 24454) || (glovesId >= 22358 && glovesId <= 22369))
						player.getCharges().checkPercentage("The gloves are " + ChargesManager.REPLACE + "% degraded.", glovesId, true);
				}
				break;
			case Equipment.SLOT_RING:
				if (packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET) {
					int ringId = player.getEquipment().getRingId();
					if (ringId == 15707) {
						player.getDungManager().openPartyInterface();
						return;
					}
					if (item.getDefinitions().containsEquipmentOption(0, "Rub")) {
						ItemTransportation.transportationDialogue(player, item, true);
						return;
					}
					ItemTransportation.sendTeleport(player, player.getEquipment().getItem(Equipment.SLOT_RING), 0, true);
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON3_PACKET) {
					int ringId = player.getEquipment().getRingId();
					if (ringId == 15707) {
						Magic.sendTeleportSpell(player, 13652, 13654, 2602, 2603, 1, 0, new WorldTile(3447, 3694, 0), 10, true, Magic.ITEM_TELEPORT);
						return;
					}
					ItemTransportation.sendTeleport(player, player.getEquipment().getItem(Equipment.SLOT_RING), 1, true);
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON4_PACKET) {
					ItemTransportation.sendTeleport(player, player.getEquipment().getItem(Equipment.SLOT_RING), 2, true);
				} else if (packetId == WorldPacketsDecoder.ACTION_BUTTON5_PACKET) {
					ItemTransportation.sendTeleport(player, player.getEquipment().getItem(Equipment.SLOT_RING), 3, true);
				}
				break;
			case Equipment.SLOT_AURA:
				if (packetId == WorldPacketsDecoder.ACTION_BUTTON2_PACKET)
					player.getAuraManager().activate();
				else if (packetId == WorldPacketsDecoder.ACTION_BUTTON3_PACKET)
					player.getAuraManager().sendAuraRemainingTime();
				break;
			}
		}
	}

	public void unlockEquipment(boolean menu) {
		player.getPackets().sendIComponentSettings(menu ? 1462 : 1464, menu ? 14 : 15, 0, 15, 15302654);
		player.getPackets().sendIComponentSettings(menu ? 1462 : 1464, menu ? 20 : 13, 2, 12, 2);
	}

	public void refreshConfigs(boolean init) {
		double hpIncrease = 0;
		if (player.getEffectsManager().hasActiveEffect(EffectType.BONFIRE)) {
			int maxhp = player.getSkills().getLevel(Skills.HITPOINTS) * 10;
			hpIncrease += (maxhp * Bonfire.getBonfireBoostMultiplier(player)) - maxhp;
		}
		if (player.getHpBoostMultiplier() != 0) {
			int maxhp = player.getSkills().getLevel(Skills.HITPOINTS) * 10;
			hpIncrease += maxhp * player.getHpBoostMultiplier();
		}

		// skip gear health as that doesnt appear as buff, its auto

		if (player.getVarsManager().sendVarBit(16463, (int) hpIncrease))
			player.updateBuffs();
		hpIncrease += player.getCombatDefinitions().getStats()[CombatDefinitions.HEALTH];

		if ((int) hpIncrease != equipmentHpIncrease) {
			equipmentHpIncrease = (int) hpIncrease;
			int maxHP = player.getMaxHitpoints();
			if (player.getHitpoints() > maxHP) {
				player.setHitpoints(maxHP);
				player.refreshHitPoints();
			}
		}
		double w = 0;
		for (Item item : items.getItems()) {
			if (item == null)
				continue;
			w += ItemWeights.getWeight(item, true);
		}
		equipmentWeight = w;
		player.getPackets().refreshWeight();
	}

	public boolean containsOneItem(int... itemIds) {
		for (int itemId : itemIds) {
			if (items.containsOne(new Item(itemId, 1)))
				return true;
		}
		return false;
	}

	public static boolean hideArms(Item item) {
		return item.getDefinitions().getEquipLookHideSlot() == 6;
	}

	public static boolean hideHair(Item item) {
		return item.getDefinitions().getEquipLookHideSlot() == 8;
	}

	public static boolean showBear(Item item) {
		String name = item.getName().toLowerCase();
		return !hideHair(item) || name.contains("horns") || name.contains("hat") || name.contains("afro") || name.contains("cowl") || name.contains("tattoo") || name.contains("headdress") || name.contains("hood") || (name.contains("mask") && !name.contains("h'ween"))
				|| (name.contains("helm")/* && !name.contains("full") */);
	}

	public static int getItemSlot(int itemId) {
		return ItemDefinitions.getItemDefinitions(itemId).getEquipSlot();
	}

	public static boolean isTwoHandedWeapon(Item item) {
		return item.getDefinitions().getEquipLookHideSlot() == 5;
	}

	public int getWeaponStance() {
		boolean combatStance = player.getCombatDefinitions().isCombatStance();
		boolean legacy = player.getCombatDefinitions().getCombatMode() == CombatDefinitions.LEGACY_COMBAT_MODE;
		Item weapon = items.get(3);
		if (weapon == null) {
			Item offhand = items.get(SLOT_SHIELD);
			if (offhand == null)
				return combatStance ? 2688 : 2699;
			int emote = offhand.getDefinitions().getCombatOpcode(
					combatStance ? (legacy ? 4384 : 2955) : (legacy ? 4383 : 2954)/* 4368 : 4367 */);
			return emote == 0 ? combatStance ? 2688 : 2699 : emote;
		}
		int emote = weapon.getDefinitions()
				.getCombatOpcode(combatStance ? (legacy ? 4384 : 2955) : (legacy ? 4383 : 2954)/* 4368 : 4367 */);
		return emote == 0 ? combatStance ? 2688 : 2699 : emote;

		// return weapon.getDefinitions().getRenderAnimId();
	}

	/*
	 * none for legacy
	 */
	public int getWeaponEndCombatEmote() {
		Item weapon = items.get(3);
		if (weapon == null) {
			Item offhand = items.get(SLOT_SHIELD);
			if (offhand == null)
				return -1;
			int emote = offhand.getDefinitions().getCombatOpcode(2918);
			return emote == 0 ? 18025 : emote;
		}
		int emote = weapon.getDefinitions().getCombatOpcode(2918);
		return emote == 0 ? 18025 : emote;
	}

	public boolean hasShield() {
		Item item = items.get(5);
		return items.get(5) != null && item.getDefinitions().isShield();
	}

	public boolean hasOffHand() {
		Item item = items.get(SLOT_SHIELD);
		return items.get(5) != null && item.getDefinitions().getCombatMap() != null;
	}

	public int getWeaponId() {
		Item item = items.get(SLOT_WEAPON);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getChestId() {
		Item item = items.get(SLOT_CHEST);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getId(int slot) {
		Item item = items.get(slot);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getHatId() {
		Item item = items.get(SLOT_HAT);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getShieldId() {
		Item item = items.get(SLOT_SHIELD);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getLegsId() {
		Item item = items.get(SLOT_LEGS);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getPocketId() {
		Item item = items.get(SLOT_POCKET);
		if (item == null)
			return -1;
		return item.getId();
	}

	public void removeAmmo(int ammoId, int amount) {
		if (amount == -1) {
			items.remove(SLOT_WEAPON, new Item(ammoId, 1));
			refresh(SLOT_WEAPON);
			if (items.get(SLOT_WEAPON) == null)
				player.getAppearence().generateAppearenceData();
		} else if (amount == -2) {
			items.remove(SLOT_SHIELD, new Item(ammoId, 1));
			refresh(SLOT_SHIELD);
			if (items.get(SLOT_SHIELD) == null)
				player.getAppearence().generateAppearenceData();
		} else {
			items.remove(SLOT_ARROWS, new Item(ammoId, amount));
			refresh(SLOT_ARROWS);
		}
	}

	public int getAuraId() {
		Item item = items.get(SLOT_AURA);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getCapeId() {
		Item item = items.get(SLOT_CAPE);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getRingId() {
		Item item = items.get(SLOT_RING);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getAmmoId() {
		Item item = items.get(SLOT_ARROWS);
		if (item == null)
			return -1;
		return item.getId();
	}

	public void deleteItem(int itemId, int amount) {
		Item[] itemsBefore = items.getItemsCopy();
		items.remove(new Item(itemId, amount));
		refreshItems(itemsBefore);
	}

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

	public int getBootsId() {
		Item item = items.get(SLOT_FEET);
		if (item == null)
			return -1;
		return item.getId();
	}

	public int getGlovesId() {
		Item item = items.get(SLOT_HANDS);
		if (item == null)
			return -1;
		return item.getId();
	}

	public ItemsContainer<Item> getItems() {
		return items;
	}

	public int getEquipmentHpIncrease() {
		return equipmentHpIncrease;
	}

	public void setEquipmentHpIncrease(int hp) {
		this.equipmentHpIncrease = hp;
	}

	public boolean wearingArmour() {
		return getItem(SLOT_HAT) != null || getItem(SLOT_CAPE) != null || getItem(SLOT_AMULET) != null || getItem(SLOT_WEAPON) != null || getItem(SLOT_CHEST) != null || getItem(SLOT_SHIELD) != null || getItem(SLOT_LEGS) != null || getItem(SLOT_HANDS) != null || getItem(SLOT_FEET) != null || getItem(SLOT_AURA) != null;
	}

	public int getAmuletId() {
		Item item = items.get(SLOT_AMULET);
		if (item == null)
			return -1;
		return item.getId();
	}

	public boolean hasTwoHandedWeapon() {
		Item weapon = items.get(SLOT_WEAPON);
		return weapon != null && isTwoHandedWeapon(weapon);
	}

	// player.isCanPvp() || costume == null || (costume.getType() != 0 &&
	// (player.getAppearence().isMale() ? 1 : 2) != costume.getType())
	public ItemsContainer<Item> getCosmeticItems() {
		return cosmeticItems;
	}

	public boolean isCanDisplayCosmetic() {
		return !player.isCanPvp();
	}

	public int getCostumeColor() {
		return costumeColor;
	}

	public void setCostumeColor(int costumeColor) {
		this.costumeColor = costumeColor;
		player.getAppearence().generateAppearenceData();
	}

	public double getEquipmentWeight() {
		return equipmentWeight;
	}

	public void refreshEquipmentInterfaceBonuses() {
		player.getVarsManager().sendVar(1037, player.getCombatDefinitions().getStats()[CombatDefinitions.MELEE_ACCURACY_PENALTY] / 10);
		player.getVarsManager().sendVar(1038, player.getCombatDefinitions().getStats()[CombatDefinitions.RANGE_ACCURACY_PENALTY] / 10);
		player.getVarsManager().sendVar(1039, player.getCombatDefinitions().getStats()[CombatDefinitions.MAGE_ACCURACY_PENALTY] / 10);
		// main hand
		player.getVarsManager().sendVar(715, player.getCombatDefinitions().getHandDamage(false) / 10);
		player.getVarsManager().sendVar(3531, player.getCombatDefinitions().getAbilitiesDamage() / 10);
		player.getVarsManager().sendVar(3561, player.getCombatDefinitions().getSkillAccuracy(false) / 10);
		player.getVarsManager().sendVar(717, player.getCombatDefinitions().getStyle(false));
		// offhand
		player.getVarsManager().sendVar(716, player.getCombatDefinitions().getHandDamage(true) / 10);
		player.getVarsManager().sendVar(3562, player.getCombatDefinitions().getSkillAccuracy(true) / 10);
		player.getVarsManager().sendVar(718, player.getCombatDefinitions().getStyle(true));

		// armor
		player.getVarsManager().sendVar(711, player.getCombatDefinitions().getStats()[CombatDefinitions.ARMOR] / 10);
		player.getVarsManager().sendVar(3563, player.getCombatDefinitions().getDefenceArmor() / 10);
		player.getVarsManager().sendVar(712, player.getCombatDefinitions().getStats()[CombatDefinitions.ARMOR_MELEE_WEAKNESS]);
		player.getVarsManager().sendVar(713, player.getCombatDefinitions().getStats()[CombatDefinitions.ARMOR_RANGE_WEAKNESS]);
		player.getVarsManager().sendVar(714, player.getCombatDefinitions().getStats()[CombatDefinitions.ARMOR_MAGIC_WEAKNESS]);

		player.getVarsManager().sendVarBit(21707, 0); // armor pve def
		player.getVarsManager().sendVar(4379, 0); // armor pvp def

		player.getPackets().sendCSVarInteger(779, 2702); // sets equip inter
		// render anim
		player.getPackets().sendExecuteScript(6992);
	}
}
