// @topic S-0314-13-04-40 Java Iterator and Visitor patterns
// @brief class Floor implements IVisitable, IUpdatable

package week11;

import java.util.ArrayList;
import java.util.Iterator;

public class Floor implements IVisitable, IUpdatable {

    // collection of visitors currently visiting the floor:
    private ArrayList< Visitor > visitors = new ArrayList();

    // iterator helper object to allow visitor
    // removal from the collection of visitors
    // during the update loop:
    Iterator<Visitor> visitorIterator = null;

    // A visitor who is currently being updated
    // and may potentially want to remove itself
    // from the collection of visitors:
    Visitor removalCandidate = null;

    //------------------------------------------
    // operations
    //------------------------------------------
    
    // IVisitable implemention

    // A visitor wants to be accepted by the floor:
    @Override
    public boolean accept( Visitor visitor )
    {
        visitors.add( visitor );
        return true;
    }

    // A visitor wants to leave the floor:
    @Override
    public boolean forget( Visitor visitor )
    {
        if ( removalCandidate == visitor ) {
            // in the middle of an update loop
            // we can only remove the visitor
            // being currently updated:
            visitorIterator.remove();

        } else if ( visitorIterator == null ) {
            // outside of update loop it is
            // ok to remove any visitor:
            visitors.remove( visitor );

        } else {
            // sorry buddy, you cannot leave this floor
            // at this time for technical reasons,
            // "the system is too busy":
            return false;
        }
        return true;
    }

    // IUpdatable implemention

    // Scenario notifying the floor object
    // that a new visitor has arrived:
    @Override
    public void visitorArrived( Visitor visitor )
    {
        visitor.visitorArrived(this);
    }

    // A floor object notifying the visitor
    // that "you are here":
    @Override
    public void visitorArrived( Floor floor ) {/*ignore*/}
    
    // Generic update from the background thread:
    @Override
    public void update()
    {
        // Solution (1) -- not good:
        // if content of collection is modified
        // during the update,
        // java.util.ConcurrentModificationException
        // is very likely!!
        //for ( Visitor visitor : visitors ) {
        //    visitor.update();
        //}
        
        // Solution (2) -- same problem:
        //Iterator<Visitor> it = visitors.iterator();
        //while ( it.hasNext() ) {
        //    Visitor visitor = it.next();
        //    visitor.update();
        //}
        
        // Solution (3) -- keep iterator
        // as a member variable of this class:
        visitorIterator = visitors.iterator();
        while ( visitorIterator.hasNext() ) {
            removalCandidate = visitorIterator.next();
            removalCandidate.update();
        }

        // both references set to null to indicate
        // that generic update is over:
        visitorIterator = null;
        removalCandidate = null;
    }

    // Elevator notifying the floor and visitor objects
    // about the elevator arrival:
    @Override
    public void elevatorArrived( /*Elevator elevator*/ ) {/*TODO*/}

    // Special update to all objects,
    // possibly a random event generated
    // by the scenario or the user pressing
    // the "red button" during the simulation:
    @Override
    public void emergency() {}
}