/* 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.*;



/** The MeshSelectionHolder contains and manages a selection and selection type
  in a mesh. It's main purpose is to store a boolean array and send events
  when selection changes. The class allows to share the same selection
  among multiple views.
 
  @author Michael Butscher */

public class MeshSelectionHolder   //  TODO(MB) implements Copieable
{
  protected boolean selected[];
  /** Reference count for the number of objects which use this holder.
    Its initial value at object construction is 1.*/
  int refCount;
  
  protected transient ModelEvent modelevent;
  protected ObjectInfo objinfo;
  protected int selectMode;
  
  public MeshSelectionHolder(ObjectInfo objinfo)
  {
    this.objinfo = objinfo;
    Mesh mesh = (Mesh) (objinfo.object);
    selected = new boolean [mesh.getVertices().length];
    refCount = 1;
  }
  
  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("selection 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();
  }
  
  /** Increment viewer reference counter. */
  public void incRefCount()
  {
    refCount++;
  }
  
  /** Decrement viewer reference counter. Even if reference counter goes to 0,
    NO special cleanup actions are performed. If counter was already 0 it does
    not change. */
  public void decRefCount()
  {
    refCount--;
    if (refCount < 0)
      refCount = 0;
  }
  
  /** Get viewer reference counter. */
  public int getRefCount()
  {
    return refCount;
  }
    
  /** This methods only sets the selection mode. Do not mix up with e.g.
   {@link TriMeshViewer#setSelectionMode}.*/

  public void setSelectionMode(int mode)
  {
    selectMode = mode;
  }

  public int getSelectionMode()
  {
    return selectMode;
  }

  /** Get an array of flags telling which parts of the mesh are currently selected.  Depending
     on the current selection mode, these flags may correspond to vertices, edges, or faces. */
  public boolean[] getSelection()
  {
    return selected;
  }

  public void setSelection(boolean sel[])
  {
    selected = sel;
  }
  
  /** Returns an empty instance of the object where the refCount is set to 1. */
  protected MeshSelectionHolder createInstance()
  {
    return new MeshSelectionHolder(objinfo);
  }

  /** If refCount is 1, the method returns this, otherwise a deep copy
    is returned. If refCount is greater than 1 it is decremented by 1.
    The returned object always has a refCount value of 1.
   */
  public MeshSelectionHolder getUniqueInstance()
  {
    if (refCount == 1)
      return this;
    else
    {
      boolean[] newsel = new boolean[selected.length];
      System.arraycopy(selected, 0, newsel, 0, selected.length);
      MeshSelectionHolder result = createInstance();
      result.setSelection(newsel);
      result.setSelectionMode(getSelectionMode());
      
      decRefCount();
      return result;
    }
  }
  

}

