import java.util.Vector;

/**
 * The Rucksack class represents a rucksack that holds objects
 * of type PackingObject. Implement the predefined interface and
 * use it from RucksackProblem.java to solve a Rucksack problem
 * instance.
 */
public class Rucksack {

	/**
	 * Max capacity of the rucksack.
	 * 
	 * Is Initialized with 0
	 */
	private int m_capacity = 0;
	
	/**
	 * ObjectVector
	 * 
	 * Is initialized. (empty)
	 */
	private Vector<PackingObject> m_objects = new Vector<PackingObject>();  
	
	public Vector<PackingObject> getObjects() {
		return m_objects;
	}

	/**
	 * Initializes a new Rucksack object with a given capacity. 
	 * Sets up all required data structures.
	 * 
	 * @param capacity The capacity of the Rucksack.
	 */
	public Rucksack(int capacity) {
		if(capacity >= 0)
		{
			this.m_capacity = capacity;
		} else
		{
			throw new IllegalArgumentException();
		}
	}
	
	/**
	 * Inserts an object into the Rucksack.
	 * 
	 * @param o The object to be added. 
	 * @throws ObjectAlreadyPresentException if the object is already present.
	 * @throws CapacityExceededException if the capacity is exceeded by the 
	 *         new object.
	 */
	void putObject(PackingObject o) {
		if(this.getTotalCapacity() >= this.getTotalWeight() + o.getWeight())
		{
			if(!this.contains(o))
			{
				this.m_objects.add(o);
			} else
			{
				throw new ObjectAlreadyPresentException();
			}
		} else
		{
			throw new CapacityExceededException();
		}
	}
	
	/**
	 * Removes an object from the Rucksack.
	 * 
	 * @param o The object to be removed.
	 * @throws ObjectNotPresentException if the object is not in the rucksack.
	 */
	void removeObject(PackingObject o) {
		if(!this.m_objects.remove(o))
		{
			throw new ObjectNotPresentException();
		}
	}
	
	/**
	 * Checks whether an object is contained in the Rucksack
	 * 
	 * @param o The object to check for.
	 * @return True if the object is present, false otherwise.
	 */
	public boolean contains(PackingObject o) {
		return this.m_objects.contains(o);
	}

	/**
	 * Returns the total weight of all objects in the rucksack.
	 */
	public int getTotalWeight() {
		int result = 0;
		
		for(int i = 0; i < this.m_objects.size(); i++)
		{
			result +=this.m_objects.get(i).getWeight();
		}
		
		return result;
	}

	/**
	 * Returns the total value of all objects in the rucksack.
	 */
	public int getTotalValue() {

		int result = 0;
			
		for(int i = 0; i < this.m_objects.size(); i++)
		{
			result +=this.m_objects.get(i).getValue();
		}
		
		return result;
	}

	/**
	 * Returns the initial capacity of the rucksack.
	 */
	public int getTotalCapacity() {
		return this.m_capacity;
	}
	
	/**
	 * Returns the capacity of the Rucksack still available.
	 */
	public int getAvailableCapacity() {
		return this.getTotalCapacity() - this.getTotalWeight();
	}

	/**
	 * Copies the contents of another Rucksack to this Rucksack.
	 *  
	 * @param other The Rucksack to copy from.
	 */
	public void copyFrom(Rucksack other) {
		if(other != null)
		{
			Vector<PackingObject> temp = other.getObjects();
			
			for(int i = 0; i < temp.size(); i++)
			{
				try
				{ 
					this.putObject(temp.elementAt(i));
				} catch(ObjectAlreadyPresentException e1){}
				  catch(CapacityExceededException e2){}
			}
		}
	}

	/**
	 * Prints all objects in this Rucksack by iterating over a list of
	 * passed PackingObjects and checking for each object whether it
	 * is in the Rucksack using contains().
	 * 
	 * You can use this function for debugging purposes.
	 *  
	 * @param objects The complete list of objects that might be in the 
	 *                rucksack
	 * @return A string of the format [(value1,weight1), (value2,weight2), ...]
	 */
	public String toString(PackingObject[] objects) {
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		for (PackingObject object : objects) {
			if (contains(object))
				sb.append(object.toString()).append(", ");
		}
		if (sb.length() > 1)
			sb.delete(sb.length() - 2, sb.length());
		sb.append(']');
		return sb.toString();
	}
}