/* CVS: $Id: HumanSelection.java,v 1.16 2001/03/18 19:16:33 gvijf Exp $ */

package evolution;

import java.util.*;

import evolution.events.*;
import evolution.lands.SquareOfLand;

/**
 * A class to make human selections.
 */
public class HumanSelection implements evolution.events.Observer {

    /**
     * Create a new human selection.
     */
    public HumanSelection() {
        EventManager.getInst().subscribe(this, HumanDiedEvt.class);
    }

    /**
     *  Add/remove a human to the selection.
     *  If the human is already in the selection it is removed from
     *  the selection.
     *  @return true if the human was added, false if the human was removed
     */
    public boolean select(Human human){
        if(humans.contains(human)) {
            remove(human);
            return false;
        } else {
            add(human);
            return true;
        }
    }

    /**
     * Add the given human.
     */
    protected void add(Human human) {
        // we must take the squares first
        // due to the multi threading it could be the human dies in
        // the middle of doing this, and if that happens it square
        // connection will be reset
        SquareOfLand sq1 = null;
        SquareOfLand sq2 = human.getSquareOfLand();
        if(!humans.isEmpty()) sq1 = getLast().getSquareOfLand();
        humans.add(human);
        if(sq2 != null)
            EventManager.getInst().signalEvent(new SquareChangedEvt(sq2));
        if(sq1 != null)
            EventManager.getInst().signalEvent(new SquareChangedEvt(sq1));
    }

    /**
     * Remove the given human from the selection.
     */
    protected void remove(Human human) {
        // we must take the squares first
        // due to the multi threading it could be the human dies in
        // the middle of doing this, and if that happens it square
        // connection will be reset
        SquareOfLand sq1 = null;
        SquareOfLand sq2 = human.getSquareOfLand();
        humans.remove(human);
        if(sq2 != null)
            EventManager.getInst().signalEvent(new SquareChangedEvt(sq2));
        if(!humans.isEmpty()) sq1 = getLast().getSquareOfLand();
        if(sq1 != null)
            EventManager.getInst().signalEvent(new SquareChangedEvt(sq1));
    }

    /**
     * Check whether the human is selected or not.
     */
    public boolean isSelected(Human human) {
        return humans.contains(human);
    }

    /**
     * Check whether this human is the last selected human.
     */
    public boolean isActiveSelected(Human human) {
        if(humans.isEmpty()) return false;
        return human == getLast();
    }

    /**
     * Get the most recently added human.
     * precondition: there must be humans in the selection
     */
    protected Human getLast() {
        int last = humans.size() - 1;
        return (Human) humans.get(last);
    }

    /**
     * Triggered by the eventmanager when a human dies.
     */
    public void update(Event evt) {
        if(evt instanceof HumanDiedEvt) {
            Human h = ((HumanDiedEvt) evt).getHuman();
            if(humans.contains(h))
                remove(h);
        }
    }

    /**
     * The number of selected humans.
     */
    public int size() {
        return humans.size();
    }

    /**
     * Is this selection empty?
     */
    public boolean empty() {
        return humans.isEmpty();
    }

    /**
     * Make this selection empty.
     */
    public void clear() {
        try {
	        while(!empty())
		        pop();
        } catch(NoSuchElementException e) {
            // can't happen
        }
    }

    /**
     * Return the last human added.
     * @exception NoSuchElementException if the selection was empty.
     */
    public Human pop() throws NoSuchElementException {
        Human h = getLast();
        remove(h);
        return h;
    }

    /**
     * Prints the current selection to stdout (for debugging).
     */
    public void print() {
        System.out.println(humans);
    }

    /**
     * Return the list of humans in this selection.
     */
    public List list() {
        return humans;
    }

    /**
     * The list of humans in this selection.
     * @link aggregation
     * @supplierCardinality 1..*
     * @directed
     * @associates <{evolution.Human}>*/
    private List humans = new ArrayList();
}