/**
 * Given the equipped items, calculate the hero's stats
 */
void MenuInventory::applyEquipment(ItemStack *equipped) {

	const std::vector<Item> &pc_items = items->items;
	int item_id;

	// calculate bonuses to basic stats, added by items
	bool checkRequired = true;
	while(checkRequired) {
		checkRequired = false;
		stats->offense_additional = stats->defense_additional = stats->physical_additional = stats->mental_additional = 0;
		for (int i = 0; i < MAX_EQUIPPED; i++) {
			item_id = equipped[i].item;
			const Item &item = pc_items[item_id];
			unsigned bonus_counter = 0;
			while (bonus_counter < item.bonus_stat.size() && item.bonus_stat[bonus_counter] != "") {
				if (item.bonus_stat[bonus_counter] == "offense")
					stats->offense_additional += item.bonus_val[bonus_counter];
				else if (item.bonus_stat[bonus_counter] == "defense")
					stats->defense_additional += item.bonus_val[bonus_counter];
				else if (item.bonus_stat[bonus_counter] == "physical")
					stats->physical_additional += item.bonus_val[bonus_counter];
				else if (item.bonus_stat[bonus_counter] == "mental")
					stats->mental_additional += item.bonus_val[bonus_counter];
				else if (item.bonus_stat[bonus_counter] == "all basic stats") {
					stats->offense_additional += item.bonus_val[bonus_counter];
					stats->defense_additional += item.bonus_val[bonus_counter];
					stats->physical_additional += item.bonus_val[bonus_counter];
					stats->mental_additional += item.bonus_val[bonus_counter];
				}
				bonus_counter++;
			}
		}

		// calculate bonuses. added by item sets
		std::vector<int> set;
		std::vector<int> quantity;
		std::vector<int>::iterator it;

		for (int i=0; i<MAX_EQUIPPED; i++) {
			item_id = equipped[i].item;
			it = std::find(set.begin(), set.end(), items->items[item_id].set);
			if (items->items[item_id].set > 0 && it != set.end()) {
				quantity[std::distance(set.begin(), it)] += 1;
			}
			else if (items->items[item_id].set > 0) {
				set.push_back(items->items[item_id].set);
				quantity.push_back(1);
			}
		}
		// calculate bonuses to basic stats, added by item sets
		ItemSet temp_set;
		for (unsigned k=0; k<set.size(); k++) {
			temp_set = items->item_sets[set[k]];
			for (unsigned bonus_counter=0; bonus_counter<temp_set.bonus.size(); bonus_counter++) {
				if (temp_set.bonus[bonus_counter].requirement != quantity[k]) continue;

				if (temp_set.bonus[bonus_counter].bonus_stat == "offense")
					stats->offense_additional += temp_set.bonus[bonus_counter].bonus_val;
				else if (temp_set.bonus[bonus_counter].bonus_stat == "defense")
					stats->defense_additional += temp_set.bonus[bonus_counter].bonus_val;
				else if (temp_set.bonus[bonus_counter].bonus_stat == "physical")
					stats->physical_additional += temp_set.bonus[bonus_counter].bonus_val;
				else if (temp_set.bonus[bonus_counter].bonus_stat == "mental")
					stats->mental_additional += temp_set.bonus[bonus_counter].bonus_val;
				else if (temp_set.bonus[bonus_counter].bonus_stat == "all basic stats") {
					stats->offense_additional += temp_set.bonus[bonus_counter].bonus_val;
					stats->defense_additional += temp_set.bonus[bonus_counter].bonus_val;
					stats->physical_additional += temp_set.bonus[bonus_counter].bonus_val;
					stats->mental_additional += temp_set.bonus[bonus_counter].bonus_val;
				}
			}
		}
		// check that each equipped item fit requirements
		for (int i = 0; i < MAX_EQUIPPED; i++) {
			if (!items->requirementsMet(stats, equipped[i].item)) {
				add(equipped[i]);
				equipped[i].clear();
				checkRequired = true;
			}
		}
	}

	// defaults
	for (unsigned i=0; i<stats->powers_list_items.size(); ++i) {
		int id = stats->powers_list_items[i];
		// stats->hp > 0 is hack to keep on_death revive passives working
		if (powers->powers[id].passive && stats->hp > 0)
			stats->effects.removeEffectPassive(id);
	}
	stats->powers_list_items.clear();

	// reset wielding vars
	stats->equip_flags.clear();

	// remove all effects and bonuses added by items
	stats->effects.clearItemEffects();

	applyItemStats(equipped);
	applyItemSetBonuses(equipped);


	// disable any incompatible slots, unequipping items if neccessary
	for (int i=0; i<MAX_EQUIPPED; ++i) {
		inventory[EQUIPMENT].slots[i]->enabled = true;

		int id = inventory[EQUIPMENT][i].item;
		for (unsigned j=0; j<items->items[id].disable_slots.size(); ++j) {
			for (int k=0; k<MAX_EQUIPPED; ++k) {
				if (slot_type[k] == items->items[id].disable_slots[j]) {
					add(inventory[EQUIPMENT].storage[k]);
					inventory[EQUIPMENT].storage[k].clear();
					inventory[EQUIPMENT].slots[k]->enabled = false;
				}
			}
		}
	}
	// update stat display
	stats->refresh_stats = true;
}
/**
 * Given the equipped items, calculate the hero's stats
 */
void MenuInventory::applyEquipment() {
	if (items->items.empty())
		return;

	int item_id;

	// calculate bonuses to basic stats, added by items
	bool checkRequired = true;
	while(checkRequired) {
		checkRequired = false;

		for (size_t j = 0; j < PRIMARY_STATS.size(); ++j) {
			stats->primary_additional[j] = 0;
		}

		for (int i = 0; i < MAX_EQUIPPED; i++) {
			item_id = inventory[EQUIPMENT].storage[i].item;
			const Item &item = items->items[item_id];
			unsigned bonus_counter = 0;
			while (bonus_counter < item.bonus.size()) {
				for (size_t j = 0; j < PRIMARY_STATS.size(); ++j) {
					if (item.bonus[bonus_counter].base_index == static_cast<int>(j))
						stats->primary_additional[j] += item.bonus[bonus_counter].value;
				}

				bonus_counter++;
			}
		}

		// calculate bonuses. added by item sets
		std::vector<int> set;
		std::vector<int> quantity;
		std::vector<int>::iterator it;

		for (int i=0; i<MAX_EQUIPPED; i++) {
			item_id = inventory[EQUIPMENT].storage[i].item;
			it = std::find(set.begin(), set.end(), items->items[item_id].set);
			if (items->items[item_id].set > 0 && it != set.end()) {
				quantity[std::distance(set.begin(), it)] += 1;
			}
			else if (items->items[item_id].set > 0) {
				set.push_back(items->items[item_id].set);
				quantity.push_back(1);
			}
		}
		// calculate bonuses to basic stats, added by item sets
		ItemSet temp_set;
		for (unsigned k=0; k<set.size(); k++) {
			temp_set = items->item_sets[set[k]];
			for (unsigned bonus_counter=0; bonus_counter<temp_set.bonus.size(); bonus_counter++) {
				if (temp_set.bonus[bonus_counter].requirement != quantity[k]) continue;

				for (size_t j = 0; j < PRIMARY_STATS.size(); ++j) {
					if (temp_set.bonus[bonus_counter].base_index == static_cast<int>(j))
						stats->primary_additional[j] += temp_set.bonus[bonus_counter].value;
				}
			}
		}
		// check that each equipped item fit requirements
		for (int i = 0; i < MAX_EQUIPPED; i++) {
			if (!items->requirementsMet(stats, inventory[EQUIPMENT].storage[i].item)) {
				add(inventory[EQUIPMENT].storage[i], CARRIED, -1, true, false);
				inventory[EQUIPMENT].storage[i].clear();
				checkRequired = true;
			}
		}
	}

	// defaults
	for (unsigned i=0; i<stats->powers_list_items.size(); ++i) {
		int id = stats->powers_list_items[i];
		// stats->hp > 0 is hack to keep on_death revive passives working
		if (powers->powers[id].passive && stats->hp > 0)
			stats->effects.removeEffectPassive(id);
	}
	stats->powers_list_items.clear();

	// reset wielding vars
	stats->equip_flags.clear();

	// remove all effects and bonuses added by items
	stats->effects.clearItemEffects();

	applyItemStats();
	applyItemSetBonuses();


	// enable all slots by default
	for (int i=0; i<MAX_EQUIPPED; ++i) {
		inventory[EQUIPMENT].slots[i]->enabled = true;
	}
	// disable any incompatible slots, unequipping items if neccessary
	for (int i=0; i<MAX_EQUIPPED; ++i) {
		int id = inventory[EQUIPMENT][i].item;
		for (unsigned j=0; j<items->items[id].disable_slots.size(); ++j) {
			for (int k=0; k<MAX_EQUIPPED; ++k) {
				if (slot_type[k] == items->items[id].disable_slots[j]) {
					add(inventory[EQUIPMENT].storage[k], CARRIED, -1, true, false);
					inventory[EQUIPMENT].storage[k].clear();
					inventory[EQUIPMENT].slots[k]->enabled = false;
				}
			}
		}
	}
	// update stat display
	stats->refresh_stats = true;
}