/* Copyright (C) 1999-2002 by Peter Eastman

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
   PARTICULAR PURPOSE.  See the GNU General Public License for more details. */


package artofillusion;

import artofillusion.animation.*;
import artofillusion.math.*;
import artofillusion.object.*;
import artofillusion.object.Mesh.*;
import artofillusion.object.TriangleMesh.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;


/** Similar to MeshSelectionHolder the class contains and manages information
  needed during editing of a skeleton (selectedJoint, detachSkeleton, 
  lockedJoints) in a mesh and sends events when data changes.
  The class allows to share the same edit settings among multiple views.

  @author Michael Butscher */

public class SkeletonControlHolder
{
  protected transient ModelEvent modelevent;
  protected ObjectInfo objinfo;  // TODO(MB) Needed ??
  
  protected int selectedJoint;
  //protected boolean detachSkeleton;
  protected Vector lockedJoints;
  
  public SkeletonControlHolder(ObjectInfo objinfo)
  {
    this.objinfo = objinfo;
    // Mesh mesh = (Mesh) (objinfo.object);
    selectedJoint = 0;
    //detachSkeleton = false;
    lockedJoints = new Vector();
  }
  
  public ModelEvent getModelEvent()
  {
    if (modelevent == null)
      modelevent = new ModelEvent();

    return modelevent;
  }
  
  /** Creates a ModelEvent which can be fired by the {@link #informChanged} method.
      The standard implementation returns a "selection changed" ModelEvent.

      @param cause      What the change caused (the caller) (may be null)
      @param during     it happened during which type of operation, see ModelEvent.CHANGEDUR_* constants
   */

  protected ModelEvent createChangedModelEvent(Object cause, String during)
  {
    return getModelEvent().createClone(this, cause).put("skeletoncontrol changed", null).put("happened during", during);
  }

  /** Called to inform the object about changes made on its own data.
      The method calls {@link #createChangedModelEvent} to get a ModelEvent and dispatches
      it to its  listeners.
      This method should not be overridden, override
        {@link #createChangedModelEvent} instead.

      @param cause      What the change caused (the caller) (may be null)
      @param during     it happened during which type of operation, see ModelEvent.CHANGEDUR_* constants
   */

  public void informChanged(Object cause, String during)
  {
    createChangedModelEvent(cause, during).processSend();
  }
  
  /** Get the ID of the selected joint. */
  public int getSelectedJoint()
  {
    return selectedJoint;
  }

  /** Set the selected joint and send appropriate <b>e</b>vents. Calling of
   {@link #informChanged} is not necessary.*/
  
  public void setSelectedJointE(int id)
  {
    modelevent.send(this, "joint deselected", new Integer(selectedJoint), null);
    selectedJoint = id;
    modelevent.send(this, "joint selected", new Integer(id), null);
  }

  /** Get an array of size [# joints in skeleton] specifying which joints are locked. */
  
  public boolean [] getLockedJoints(Skeleton s)  // TODO(MB) Parameter needed?
  {
    if (s == null)
      return new boolean [0];
    boolean b[] = new boolean [s.getNumJoints()];
    for (int i = 0; i < lockedJoints.size(); i++)
    {
      int index = s.findJointIndex(((Integer) lockedJoints.elementAt(i)).intValue());
      if (index > -1 && index < b.length)
        b[index] = true;
    }
    return b;
  }
  
  /** Determine whether a particular joint is locked. */
  
  public boolean isJointLocked(int id)
  {
    for (int i = 0; i < lockedJoints.size(); i++)
      if (((Integer) lockedJoints.elementAt(i)).intValue() == id)
        return true;
    return false;
  }

  /** Lock the joint with the specified ID. */
  
  public void lockJoint(int id)
  {
    Integer i = new Integer(id);
    if (lockedJoints.indexOf(i) == -1)
      lockedJoints.addElement(i);
  }
  
  /** Unlock the joint with the specified ID. */
  
  public void unlockJoint(int id)
  {
    lockedJoints.removeElement(new Integer(id));
  }
  
}

