package com.artemis.managers;

import java.util.HashMap;
import java.util.Map;

import com.artemis.Entity;
import com.artemis.Manager;
import com.artemis.utils.Bag;
import com.artemis.utils.ImmutableBag;

/**
 * If you need to group your entities together, e.g. tanks going into "units" group or explosions into "effects",
 * then use this manager. You must retrieve it using world instance.
 * 
 * A entity can be assigned to more than one group.
 * 
 * @author Arni Arent
 *
 */
public class GroupManager extends Manager {
	private Map<String, Bag<Entity>> entitiesByGroup;
	private Map<Entity, Bag<String>> groupsByEntity;

	public GroupManager() {
		entitiesByGroup = new HashMap<String, Bag<Entity>>();
		groupsByEntity = new HashMap<Entity, Bag<String>>();
	}
	

	@Override
	protected void initialize() {
	}
	
	
	/**
	 * Set the group of the entity.
	 * 
	 * @param group group to add the entity into.
	 * @param e entity to add into the group.
	 */
	public void add(Entity e, String group) {
		Bag<Entity> entities = entitiesByGroup.get(group);
		if(entities == null) {
			entities = new Bag<Entity>();
			entitiesByGroup.put(group, entities);
		}
		entities.add(e);
		
		Bag<String> groups = groupsByEntity.get(e);
		if(groups == null) {
			groups = new Bag<String>();
			groupsByEntity.put(e, groups);
		}
		groups.add(group);
	}
	
	/**
	 * Remove the entity from the specified group.
	 * @param e
	 * @param group
	 */
	public void remove(Entity e, String group) {
		Bag<Entity> entities = entitiesByGroup.get(group);
		if(entities != null) {
			entities.remove(e);
		}
		
		Bag<String> groups = groupsByEntity.get(e);
		if(groups != null) {
			groups.remove(group);
		}
	}
	
	public void removeFromAllGroups(Entity e) {
		Bag<String> groups = groupsByEntity.get(e);
		if(groups != null) {
			for(int i = 0, s = groups.size(); s > i; i++) {
				Bag<Entity> entities = entitiesByGroup.get(groups.get(i));
				if(entities != null) {
					entities.remove(e);
				}
			}
			groups.clear();
		}
	}
	
	/**
	 * Get all entities that belong to the provided group.
	 * @param group name of the group.
	 * @return read-only bag of entities belonging to the group.
	 */
	public ImmutableBag<Entity> getEntities(String group) {
		Bag<Entity> entities = entitiesByGroup.get(group);
		if(entities == null) {
			entities = new Bag<Entity>();
			entitiesByGroup.put(group, entities);
		}
		return entities;
	}
	
	/**
	 * @param e entity
	 * @return the groups the entity belongs to, null if none.
	 */
	public ImmutableBag<String> getGroups(Entity e) {
		return groupsByEntity.get(e);
	}
	
	/**
	 * Checks if the entity belongs to any group.
	 * @param e the entity to check.
	 * @return true if it is in any group, false if none.
	 */
	public boolean isInAnyGroup(Entity e) {
		return getGroups(e) != null;
	}
	
	/**
	 * Check if the entity is in the supplied group.
	 * @param group the group to check in.
	 * @param e the entity to check for.
	 * @return true if the entity is in the supplied group, false if not.
	 */
	public boolean isInGroup(Entity e, String group) {
		if(group != null) {
			Bag<String> bag = groupsByEntity.get(e);
			Object[] groups = bag.getData();
			for(int i = 0, s = bag.size(); s > i; i++) {
				String g = (String)groups[i];
				if(group.equals(g)) {
					return true;
				}
			}
		}
		return false;
	}

	@Override
	public void deleted(Entity e) {
		removeFromAllGroups(e);
	}
	
}

@@ -3253,16 +3253,40 @@
 et(e);%0D%0A
+%09%09%09if (bag != null) %7B%0D%0A%09
 %09%09%09Objec
@@ -3314,16 +3314,17 @@
 ata();%0D%0A
+%09
 %09%09%09for(i
@@ -3368,16 +3368,17 @@
  %7B%0D%0A%09%09%09%09
+%09
 String g
@@ -3400,16 +3400,17 @@
 ps%5Bi%5D;%0D%0A
+%09
 %09%09%09%09if(g
@@ -3433,16 +3433,17 @@
 %7B%0D%0A%09%09%09%09%09
+%09
 return t
@@ -3448,16 +3448,24 @@
  true;%0D%0A
+%09%09%09%09%09%7D%0D%0A
 %09%09%09%09%7D%0D%0A%09

check if entity is in any group before checking if it is in specific group (was NullPointerException)