package cz.cuni.amis.pogamut.ut2004.agent.module.sensor;

import cz.cuni.amis.pogamut.base.agent.worldview.IWorldView;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Item;

import java.util.logging.Logger;
import java.util.Collection;
import java.util.ArrayList;

/**
 * Module specialized on items on the map. This module extends the {@link Items}
 * module by adding filters for usability and/or takeability. These filters may
 * help the agent to decide, whether it is useful for him, to forage specific
 * items from the map.
 *
 * @author Juraj 'Loque' Simlovic
 */
public class AdvancedItems extends Items
{
	/**
	 * Retreives list of all items (both known and thrown).
	 *
	 * @param usefulOnly If true, the list will be filtered by usefullness.
	 * An item is considered useful, when it changes agent's status somehow.
	 * @return List of all items. Note: Spawned items are included only.
	 */
	public Collection<Item> getAllItems(boolean usefulOnly)
	{
		return filterUsefulItems (
			super.getAllItems().values(), usefulOnly
		);
	}

	/*========================================================================*/

	/**
	 * Retreives list of all visible items.
	 *
	 * @param usefulOnly If true, the list will be filtered by usefullness.
	 * An item is considered useful, when it changes agent's status somehow.
	 * @return List of all visible items. Note: Spawned items are included only.
	 */
	public Collection<Item> getVisibleItems(boolean usefulOnly)
	{
		return filterUsefulItems (
			super.getVisibleItems().values(), usefulOnly
		);
	}

	/*========================================================================*/

	/**
	 * Retreives list of all reachable items.
	 *
	 * @param usefulOnly If true, the list will be filtered by usefullness.
	 * An item is considered useful, when it changes agent's status somehow.
	 * @return List of all reachable items. Note: Spawned items are included only.
	 */
	public Collection<Item> getReachableItems(boolean usefulOnly)
	{
		return filterUsefulItems (
			super.getReachableItems().values(), usefulOnly
		);
	}

	/*========================================================================*/

	/**
	 * Retreives list of all item pickup points.
	 *
	 * @param usefulOnly If true, the list will be filtered by usefullness.
	 * An item is considered useful, when it changes agent's status somehow.
	 * @return List of all items. Note: Empty pickups are included as well.
	 *
	 * @see isPickupSpawned(Item)
	 */
	public Collection<Item> getKnownPickups(boolean usefulOnly)
	{
		return filterUsefulItems (
			super.getKnownPickups().values(), usefulOnly
		);
	}

	/*========================================================================*/

	/**
	 * Determines, whether an item can be useful for the agent.
	 *
	 * @param item Given item to be checked.
	 * @param usefulOnly If true, the method returns true, only if the item is
	 * useful (changes agent's status anyhow). Note: If an item is not takeable
	 * from the ground, it is never considered useful.
	 * @return True, if the item can be useful.
	 */
	public boolean isItemUseful(Item item, boolean usefulOnly)
	{
		// FIXME[js]: implement when available
		// FIXME[js]: Weapon, Ammo, Health, Armor, Special, Extra
		throw new UnsupportedOperationException("Not supported yet");
	}

	/**
	 * Determines, whether an item can be useful for the agent.
	 *
	 * @param items Items to be filtered on.
	 * @param usefulOnly Filters out non-useful items. An item is considered
	 * useful, when it changes agent's status somehow. Note: If an item is not
	 * takeable from the ground, it is never considered useful.
	 * @return True, if the item can be useful.
	 */
	public Collection<Item> filterUsefulItems(Collection<Item> items, boolean usefulOnly)
	{
		// new empty list
		ArrayList<Item> list = new ArrayList<Item> (items.size());

		// run through items and filter them out
		for (Item i: items)
			if (isItemUseful(i, usefulOnly))
				// add only useful to the results
				list.add(i);

		return list;
	}

	/*========================================================================*/

	/**
	 * Constructor. Setups the memory module based on given WorldView.
	 * @param worldView WorldView object to read the info from.
	 * @param agentInfo AgentInfo memory module. Note: If <i>null</i> is
	 * provided, this memory module creates its own AgentInfo memory module.
	 * Provide shared AgentInfo memory module to economize CPU time and other
	 * resources.
	 * @param log Logger to be used for logging runtime/debug info.
	 */
	public AdvancedItems(IWorldView worldView, AgentInfo agentInfo, Logger log)
	{
		super(worldView, agentInfo, log);
	}
}
