package com.artemis;

import java.util.BitSet;

/**
 * An Aspects is used by systems as a matcher against entities, to check if a system is
 * interested in an entity. Aspects define what sort of component types an entity must
 * possess, or not possess.
 * 
 * This creates an aspect where an entity must possess A and B and C:
 * Aspect.getAspectForAll(A.class, B.class, C.class)
 * 
 * This creates an aspect where an entity must possess A and B and C, but must not possess U or V.
 * Aspect.getAspectForAll(A.class, B.class, C.class).exclude(U.class, V.class)
 * 
 * This creates an aspect where an entity must possess A and B and C, but must not possess U or V, but must possess one of X or Y or Z.
 * Aspect.getAspectForAll(A.class, B.class, C.class).exclude(U.class, V.class).one(X.class, Y.class, Z.class)
 *
 * You can create and compose aspects in many ways:
 * Aspect.getEmpty().one(X.class, Y.class, Z.class).all(A.class, B.class, C.class).exclude(U.class, V.class)
 * is the same as:
 * Aspect.getAspectForAll(A.class, B.class, C.class).exclude(U.class, V.class).one(X.class, Y.class, Z.class)
 *
 * @author Arni Arent
 *
 */
public class Aspect {
	
	private BitSet allSet;
	private BitSet exclusionSet;
	private BitSet oneSet;
	
	private Aspect() {
		this.allSet = new BitSet();
		this.exclusionSet = new BitSet();
		this.oneSet = new BitSet();
	}
	
	protected BitSet getAllSet() {
		return allSet;
	}
	
	protected BitSet getExclusionSet() {
		return exclusionSet;
	}
	
	protected BitSet getOneSet() {
		return oneSet;
	}
	
	/**
	 * Returns an aspect where an entity must possess all of the specified component types.
	 * @param type a required component type
	 * @param types a required component type
	 * @return an aspect that can be matched against entities
	 */
	public Aspect all(Class<? extends Component> type, Class<? extends Component>... types) {
		allSet.set(ComponentType.getIndexFor(type));
		
		for (Class<? extends Component> t : types) {
			allSet.set(ComponentType.getIndexFor(t));
		}

		return this;
	}
	
	/**
	 * Excludes all of the specified component types from the aspect. A system will not be
	 * interested in an entity that possesses one of the specified exclusion component types.
	 * 
	 * @param type component type to exclude
	 * @param types component type to exclude
	 * @return an aspect that can be matched against entities
	 */
	public Aspect exclude(Class<? extends Component> type, Class<? extends Component>... types) {
		exclusionSet.set(ComponentType.getIndexFor(type));
		
		for (Class<? extends Component> t : types) {
			exclusionSet.set(ComponentType.getIndexFor(t));
		}
		return this;
	}
	
	/**
	 * Returns an aspect where an entity must possess one of the specified component types.
	 * @param type one of the types the entity must possess
	 * @param types one of the types the entity must possess
	 * @return an aspect that can be matched against entities
	 */
	public Aspect one(Class<? extends Component> type, Class<? extends Component>... types) {
		oneSet.set(ComponentType.getIndexFor(type));
		
		for (Class<? extends Component> t : types) {
			oneSet.set(ComponentType.getIndexFor(t));
		}
		return this;
	}
	
	/**
	 * Creates an aspect where an entity must possess all of the specified component types.
	 * 
	 * @param type the type the entity must possess
	 * @param types the type the entity must possess
	 * @return an aspect that can be matched against entities
	 * 
	 * @deprecated
	 * @see getAspectForAll
	 */
	public static Aspect getAspectFor(Class<? extends Component> type, Class<? extends Component>... types) {
		return getAspectForAll(type, types);
	}
	
	/**
	 * Creates an aspect where an entity must possess all of the specified component types.
	 * 
	 * @param type a required component type
	 * @param types a required component type
	 * @return an aspect that can be matched against entities
	 */
	public static Aspect getAspectForAll(Class<? extends Component> type, Class<? extends Component>... types) {
		Aspect aspect = new Aspect();
		aspect.all(type, types);
		return aspect;
	}
	
	/**
	 * Creates an aspect where an entity must possess one of the specified component types.
	 * 
	 * @param type one of the types the entity must possess
	 * @param types one of the types the entity must possess
	 * @return an aspect that can be matched against entities
	 */
	public static Aspect getAspectForOne(Class<? extends Component> type, Class<? extends Component>... types) {
		Aspect aspect = new Aspect();
		aspect.one(type, types);
		return aspect;
	}
	
	/**
	 * Creates and returns an empty aspect. This can be used if you want a system that processes no entities, but
	 * still gets invoked. Typical usages is when you need to create special purpose systems for debug rendering,
	 * like rendering FPS, how many entities are active in the world, etc.
	 * 
	 * You can also use the all, one and exclude methods on this aspect, so if you wanted to create a system that
	 * processes only entities possessing just one of the components A or B or C, then you can do:
	 * Aspect.getEmpty().one(A,B,C);
	 * 
	 * @return an empty Aspect that will reject all entities.
	 */
	public static Aspect getEmpty() {
		return new Aspect();
	}

}

@@ -3276,467 +3276,8 @@
  * %0A
-%09 * @param type the type the entity must possess%0A%09 * @param types the type the entity must possess%0A%09 * @return an aspect that can be matched against entities%0A%09 * %0A%09 * @deprecated%0A%09 * @see getAspectForAll%0A%09 */%0A%09public static Aspect getAspectFor(Class%3C? extends Component%3E type, Class%3C? extends Component%3E... types) %7B%0A%09%09return getAspectForAll(type, types);%0A%09%7D%0A%09%0A%09/**%0A%09 * Creates an aspect where an entity must possess all of the specified component types.%0A%09 * %0A
 %09 * 

Remove deprecated method