// <pre>
package actor;

import java.util.Iterator;

/**
 * @author Robbins
 */
public class ActorArbitrator
  implements BehaviorArbitrator, BehaviorListListener
{
  private AnimationManager animationManager;

  public ActorArbitrator(Actor actor)
  {
    animationManager = new AnimationManager();
    actor.getBehaviors().addListener(this);
  }
  
  /**
   * Run simplest form of abitration in which we loop through all behaviors
   * in the actor's behavior list to find the one with the highest priority.
   * If multiple behaviors have the same priority, this arbitrator will
   * select the last one on the actors behavior list with the assumption that
   * it was the last one added.
   * 
   * We then run the selected behavior to obtain a MotionChange object
   * (assume the change is fine), then use it to update the actor.
   * 
   * More sophisticated arbitrators may run multiple behaviors from the
   * actors behavior list and somehow blend the resulting MotionChange
   * requests.
   */
  public MotionChange arbitrate(WorldState world, Actor actor)
  {
    MotionChange arbitratedMotionChange = null;
    Point3D[] animationPts = null;
    
    if (!actor.getBehaviors().isEmpty())
    {
      int highestPriority = 0;
      Behavior arbitratedBehavior = null;
      Iterator behaviorIterator = actor.getBehaviors().iterator();
      AbstractBehavior nextBehavior = null;

      while (behaviorIterator.hasNext())
      {
        nextBehavior = (AbstractBehavior)behaviorIterator.next();
        if (nextBehavior.getPriority() >= highestPriority)
        {
          arbitratedBehavior = nextBehavior;
          highestPriority = nextBehavior.getPriority();
        }
      }

      if (arbitratedBehavior != null)
      {
        arbitratedMotionChange =
          arbitratedBehavior.doBehavior(world, new InvariantActor(actor));

        if (arbitratedMotionChange != null)
        {
          actor.updateMotion(arbitratedMotionChange);
        }
      }
    }

    /*
		 * Get new animated vertices from the AnimationManager, then use them to
		 * update the actor's vertices.
		 */
    animationPts = animationManager.getAnimatedVertices(world, actor);
    actor.getModel().updateVertices(animationPts);

    /*
		 * Return the arbitrated MotionChange object in case a parent arbitrator is
		 * above this one.
		 */
    return arbitratedMotionChange;

  }

  public void onBehaviorListChange(BehaviorListChangedEvent bce)
  {
    /*
		 * Uncomment and complete the code below if you want to change something in
		 * or about the arbitrator whenever a behavior is added, changed, or
		 * removed
		 */

    //    if (bce.getType() == BehaviorListChangedEvent.ADDED)
    //    {
    //      Behavior addedBehavior = bce.getBehavior();
    //      /* Do something with addedBehavior */
    //    }
    //    else if (bce.getType() == BehaviorListChangedEvent.CHANGED)
    //    {
    //      Behavior changedBehavior = bce.getBehavior();
    //      /* Do something with changedBehavior */
    //    }
    //    else if (bce.getType() == BehaviorListChangedEvent.REMOVED)
    //    {
    //      Behavior removedBehavior = bce.getBehavior();
    //      /* Do something with removedBehavior */
    //    }

  }

  public AnimationManager getAnimationManager()
  {
    return animationManager;
  }

  public void setAnimationManager(AnimationManager keyFrameArbitrator)
  {
    this.animationManager = keyFrameArbitrator;
  }

}